/** * 极验 4.0 — 点击登录后弹出 bind 模式验证码,成功后返回校验参数供登录接口使用。 */ import { getGeetest4Infos } from '@/api/auth.js' import { GEETEST4_CAPTCHA_ID } from '@/api/config.js' // #ifdef H5 import '@/static/js/gt4.js' // #endif function normalizeValidate(result, fallbackCaptchaId) { return { captcha_id: result?.captcha_id || fallbackCaptchaId, lot_number: result?.lot_number || '', pass_token: result?.pass_token || '', gen_time: result?.gen_time || '', captcha_output: result?.captcha_output || '' } } /** 优先读后端配置,失败时使用本地 captcha_id */ export async function fetchGeetest4CaptchaId() { try { const data = await getGeetest4Infos() if (data?.captcha_id) return data.captcha_id } catch { // 后端未配置或未开启时走本地兜底 } return GEETEST4_CAPTCHA_ID } // #ifdef H5 function showGeetest4H5(captchaId) { return new Promise((resolve, reject) => { if (typeof window === 'undefined' || !window.initGeetest4) { reject(new Error('极验 SDK 未加载')) return } let settled = false const settle = (fn) => { if (settled) return settled = true fn() } window.initGeetest4( { captchaId, product: 'bind', language: 'zh-CN', https: true }, (instance) => { const teardown = () => { try { if (typeof instance.hideCaptcha === 'function') instance.hideCaptcha() if (typeof instance.destroy === 'function') instance.destroy() } catch { // ignore } } instance.onSuccess(() => { const result = normalizeValidate(instance.getValidate(), captchaId) teardown() settle(() => resolve(result)) }) instance.onFail(() => { teardown() settle(() => reject(new Error('人机验证未通过'))) }) instance.onError(() => { teardown() settle(() => reject(new Error('人机验证加载失败'))) }) instance.onClose?.(() => { setTimeout(() => { if (settled) return teardown() settle(() => reject(new Error('已取消人机验证'))) }, 400) }) instance.showCaptcha() } ) }) } // #endif // #ifdef APP-PLUS function showGeetest4App(captchaId) { // 清理可能残留的原生 Webview if (typeof plus !== 'undefined' && plus.webview) { try { const old = plus.webview.getWebviewById('geetest-captcha-overlay') if (old) old.close('none') } catch (e) {} } return new Promise((resolve, reject) => { uni.navigateTo({ url: `/pages/login/geetest-webview?captchaId=${encodeURIComponent(captchaId)}`, events: { geetestSuccess(data) { resolve(normalizeValidate(data, captchaId)) }, geetestFail(msg) { reject(new Error(msg || '人机验证未通过')) } }, fail(err) { reject(new Error(err?.errMsg || '无法打开验证页面')) } }) }) } // #endif /** * 弹出极验 4.0 验证 * @returns {Promise<{ captcha_id, lot_number, pass_token, gen_time, captcha_output }>} */ export async function showGeetest4() { const captchaId = await fetchGeetest4CaptchaId() if (!captchaId) { throw new Error('未配置极验 captcha_id') } // #ifdef H5 return showGeetest4H5(captchaId) // #endif // #ifdef APP-PLUS return showGeetest4App(captchaId) // #endif // #ifndef H5 || APP-PLUS throw new Error('当前平台暂不支持极验验证,请使用 H5 或 App') // #endif }