Files
yunzerwebsiteallinone/uniapp/utils/geetest.js
T

139 lines
3.3 KiB
JavaScript

/**
* 极验 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
}