1
This commit is contained in:
2
src/auto-imports.d.ts
vendored
2
src/auto-imports.d.ts
vendored
@@ -119,7 +119,7 @@ declare global {
|
||||
const useActiveElement: typeof import('@vueuse/core')['useActiveElement']
|
||||
const useAgent: typeof import('./composables/useAgent.js')['useAgent']
|
||||
const useAgentStore: typeof import('./stores/agentStore.js')['useAgentStore']
|
||||
const useAliyunCaptcha: typeof import('./composables/useAliyunCaptcha.js')['useAliyunCaptcha']
|
||||
const useAliyunCaptcha: typeof import('./composables/useAliyunCaptcha.js')['default']
|
||||
const useAnimate: typeof import('@vueuse/core')['useAnimate']
|
||||
const useApiFetch: typeof import('./composables/useApiFetch.js')['default']
|
||||
const useAppStore: typeof import('./stores/appStore.js')['useAppStore']
|
||||
|
||||
@@ -448,8 +448,8 @@ async function sendVerificationCode() {
|
||||
.post({ mobile: formData.mobile, actionType: "query", captchaVerifyParam })
|
||||
.json(),
|
||||
(result) => {
|
||||
const { data, error } = result
|
||||
if (!error.value && data.value?.code === 200) {
|
||||
// result 已经是解包后的响应数据(data.value)
|
||||
if (result && result.code === 200) {
|
||||
showToast({ message: "验证码发送成功", type: "success" });
|
||||
startCountdown();
|
||||
nextTick(() => {
|
||||
@@ -458,8 +458,8 @@ async function sendVerificationCode() {
|
||||
verificationCodeInput.focus();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
showToast({ message: data.value?.msg || "验证码发送失败,请重试" });
|
||||
} else if (result) {
|
||||
showToast({ message: result.msg || "验证码发送失败,请重试" });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,154 +1,103 @@
|
||||
import { showToast, showLoadingToast, closeToast } from 'vant'
|
||||
import useApiFetch from '@/composables/useApiFetch'
|
||||
|
||||
// 阿里云验证码场景ID(从环境变量读取)
|
||||
const ALIYUN_CAPTCHA_SCENE_ID = import.meta.env.VITE_ALIYUN_CAPTCHA_SCENE_ID || 'wynt39to'
|
||||
import { showToast, showLoadingToast, closeToast } from "vant";
|
||||
import useApiFetch from "@/composables/useApiFetch";
|
||||
|
||||
// 阿里云验证码场景 ID
|
||||
const ALIYUN_CAPTCHA_SCENE_ID = "wynt39to";
|
||||
// 是否启用加密模式(通过环境变量控制,非加密模式时前端不调用后端获取 EncryptedSceneId)
|
||||
const ENABLE_ENCRYPTED = import.meta.env.VITE_ALIYUN_CAPTCHA_ENCRYPTED === 'false'
|
||||
const ENABLE_ENCRYPTED =
|
||||
import.meta.env.VITE_ALIYUN_CAPTCHA_ENCRYPTED === "false";
|
||||
|
||||
let captchaInitialized = false
|
||||
let captchaInitialised = false;
|
||||
/** 首次初始化后,SDK 会异步调用 getInstance,用此 Promise 在实例就绪后再 show */
|
||||
let captchaReadyPromise = null
|
||||
let captchaReadyResolve = null
|
||||
let captchaReadyPromise = null;
|
||||
let captchaReadyResolve = null;
|
||||
|
||||
async function ensureCaptchaInit() {
|
||||
console.log('[AliyunCaptcha] ====== ensureCaptchaInit 开始执行 ======');
|
||||
|
||||
// 1. 检查是否已经初始化或非浏览器环境
|
||||
if (captchaInitialized) {
|
||||
console.log('[AliyunCaptcha] 已初始化,直接返回');
|
||||
return;
|
||||
}
|
||||
if (typeof window === 'undefined') {
|
||||
console.log('[AliyunCaptcha] 非浏览器环境,直接返回');
|
||||
return;
|
||||
}
|
||||
if (captchaInitialised || typeof window === "undefined") return;
|
||||
if (typeof window.initAliyunCaptcha !== "function") return;
|
||||
|
||||
// 2. 检查 SDK 是否存在
|
||||
if (typeof window.initAliyunCaptcha !== 'function') {
|
||||
console.error('[AliyunCaptcha] ❌ initAliyunCaptcha 不存在,SDK 可能未加载!请检查是否引入 captcha.js');
|
||||
return;
|
||||
}
|
||||
console.log('[AliyunCaptcha] ✅ initAliyunCaptcha 函数存在,SDK 已加载');
|
||||
|
||||
// 3. 设置初始化状态
|
||||
captchaInitialized = true;
|
||||
captchaInitialised = true;
|
||||
window.captcha = null;
|
||||
window.__lastBizResponse = null;
|
||||
window.__onCaptchaBizSuccess = null;
|
||||
captchaReadyPromise = new Promise((resolve) => {
|
||||
captchaReadyResolve = resolve;
|
||||
});
|
||||
console.log('[AliyunCaptcha] 初始化状态已设置,创建 captchaReadyPromise');
|
||||
|
||||
// 4. 构建配置对象
|
||||
const initConfig = {
|
||||
// 非加密模式:仅传 SceneId,不调用后端接口
|
||||
if (!ENABLE_ENCRYPTED) {
|
||||
window.initAliyunCaptcha({
|
||||
SceneId: ALIYUN_CAPTCHA_SCENE_ID,
|
||||
mode: "popup",
|
||||
element: "#captcha-element",
|
||||
getInstance(instance) {
|
||||
window.captcha = instance;
|
||||
if (typeof captchaReadyResolve === "function") {
|
||||
captchaReadyResolve();
|
||||
captchaReadyResolve = null;
|
||||
}
|
||||
},
|
||||
captchaVerifyCallback(param) {
|
||||
return typeof window.__captchaVerifyCallback === "function"
|
||||
? window.__captchaVerifyCallback(param)
|
||||
: Promise.resolve({
|
||||
captchaResult: false,
|
||||
bizResult: false,
|
||||
});
|
||||
},
|
||||
onBizResultCallback(bizResult) {
|
||||
if (typeof window.__onBizResultCallback === "function") {
|
||||
window.__onBizResultCallback(bizResult);
|
||||
}
|
||||
window.__lastBizResponse = null;
|
||||
window.__onCaptchaBizSuccess = null;
|
||||
},
|
||||
slideStyle: { width: 360, height: 40 },
|
||||
language: "cn",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 加密模式:先从后端获取 EncryptedSceneId,再初始化
|
||||
const { data, error } = await useApiFetch("/captcha/encryptedSceneId")
|
||||
.post()
|
||||
.json();
|
||||
const resp = data?.value;
|
||||
const encryptedSceneId = resp?.data?.encryptedSceneId;
|
||||
if (error?.value || !encryptedSceneId) {
|
||||
showToast({ message: "获取验证码参数失败,请稍后重试" });
|
||||
captchaInitialised = false;
|
||||
captchaReadyPromise = null;
|
||||
captchaReadyResolve = null;
|
||||
return;
|
||||
}
|
||||
window.initAliyunCaptcha({
|
||||
SceneId: ALIYUN_CAPTCHA_SCENE_ID,
|
||||
mode: 'popup',
|
||||
element: '#captcha-element',
|
||||
|
||||
EncryptedSceneId: encryptedSceneId,
|
||||
mode: "popup",
|
||||
element: "#captcha-element",
|
||||
getInstance(instance) {
|
||||
console.log('[AliyunCaptcha] 🎯 getInstance 被调用,实例已创建:', instance);
|
||||
window.captcha = instance;
|
||||
if (typeof captchaReadyResolve === 'function') {
|
||||
console.log('[AliyunCaptcha] ✅ 调用 captchaReadyResolve(),通知实例就绪');
|
||||
if (typeof captchaReadyResolve === "function") {
|
||||
captchaReadyResolve();
|
||||
captchaReadyResolve = null;
|
||||
} else {
|
||||
console.warn('[AliyunCaptcha] ⚠️ captchaReadyResolve 不是函数,可能已被调用');
|
||||
}
|
||||
},
|
||||
|
||||
captchaVerifyCallback(param) {
|
||||
console.log('[AliyunCaptcha] 📞 captchaVerifyCallback 被调用,参数:', JSON.stringify(param, null, 2));
|
||||
const result = typeof window.__captchaVerifyCallback === 'function'
|
||||
return typeof window.__captchaVerifyCallback === "function"
|
||||
? window.__captchaVerifyCallback(param)
|
||||
: Promise.resolve({ captchaResult: false, bizResult: false });
|
||||
|
||||
console.log('[AliyunCaptcha] 📤 captchaVerifyCallback 返回值:', result);
|
||||
return result;
|
||||
},
|
||||
|
||||
onBizResultCallback(bizResult) {
|
||||
console.log('[AliyunCaptcha] 📬 onBizResultCallback 被调用,bizResult:', bizResult);
|
||||
if (typeof window.__onBizResultCallback === 'function') {
|
||||
if (typeof window.__onBizResultCallback === "function") {
|
||||
window.__onBizResultCallback(bizResult);
|
||||
} else {
|
||||
console.warn('[AliyunCaptcha] ⚠️ __onBizResultCallback 不是函数');
|
||||
}
|
||||
window.__lastBizResponse = null;
|
||||
window.__onCaptchaBizSuccess = null;
|
||||
},
|
||||
|
||||
slideStyle: { width: 360, height: 40 },
|
||||
language: 'cn',
|
||||
};
|
||||
|
||||
console.log('[AliyunCaptcha] 📋 构建的 initConfig:', JSON.stringify(initConfig, null, 2));
|
||||
|
||||
// 5. 判断加密模式
|
||||
if (!ENABLE_ENCRYPTED) {
|
||||
console.log('[AliyunCaptcha] 🔓 使用非加密模式(ENABLE_ENCRYPTED = false)');
|
||||
console.log('[AliyunCaptcha] 📤 调用 window.initAliyunCaptcha(initConfig)');
|
||||
try {
|
||||
window.initAliyunCaptcha(initConfig);
|
||||
console.log('[AliyunCaptcha] ✅ initAliyunCaptcha 调用完成(非加密模式)');
|
||||
} catch (err) {
|
||||
console.error('[AliyunCaptcha] ❌ initAliyunCaptcha 调用失败(非加密模式):', err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 6. 加密模式:获取 encryptedSceneId
|
||||
console.log('[AliyunCaptcha] 🔐 使用加密模式(ENABLE_ENCRYPTED = true)');
|
||||
console.log('[AliyunCaptcha] 📡 请求后端接口获取 encryptedSceneId: /captcha/encryptedSceneId');
|
||||
|
||||
let resp, encryptedSceneId;
|
||||
try {
|
||||
const { data, error } = await useApiFetch('/captcha/encryptedSceneId')
|
||||
.post()
|
||||
.json();
|
||||
|
||||
console.log('[AliyunCaptcha] 📥 后端接口响应:', { data: data?.value, error: error?.value });
|
||||
|
||||
resp = data?.value;
|
||||
encryptedSceneId = resp?.data?.encryptedSceneId;
|
||||
|
||||
if (error?.value) {
|
||||
console.error('[AliyunCaptcha] ❌ 后端接口请求失败:', error.value);
|
||||
}
|
||||
if (!encryptedSceneId) {
|
||||
console.error('[AliyunCaptcha] ❌ encryptedSceneId 为空,响应数据:', resp);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[AliyunCaptcha] ❌ 请求 encryptedSceneId 时发生异常:', err);
|
||||
resp = null;
|
||||
encryptedSceneId = null;
|
||||
}
|
||||
|
||||
if (error?.value || !encryptedSceneId) {
|
||||
console.error('[AliyunCaptcha] ❌ 获取 encryptedSceneId 失败,error:', error?.value, 'encryptedSceneId:', encryptedSceneId);
|
||||
showToast({ message: '获取验证码参数失败,请稍后重试' });
|
||||
captchaInitialized = false;
|
||||
captchaReadyPromise = null;
|
||||
captchaReadyResolve = null;
|
||||
console.log('[AliyunCaptcha] 🔄 重置初始化状态,等待下次重试');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[AliyunCaptcha] ✅ 成功获取 encryptedSceneId:', encryptedSceneId);
|
||||
initConfig.EncryptedSceneId = encryptedSceneId;
|
||||
console.log('[AliyunCaptcha] 📤 调用 window.initAliyunCaptcha(initConfig)(加密模式)');
|
||||
|
||||
try {
|
||||
console.log('[AliyunCaptcha] 开始调用 window.initAliyunCaptcha(initConfig)(加密模式)')
|
||||
window.initAliyunCaptcha(initConfig)
|
||||
console.log('[AliyunCaptcha] ✅ window.initAliyunCaptcha 调用完成(加密模式)')
|
||||
} catch (err) {
|
||||
console.error('[AliyunCaptcha] ❌ window.initAliyunCaptcha 调用失败(加密模式):', err)
|
||||
}
|
||||
|
||||
language: "cn",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,59 +112,61 @@ export function useAliyunCaptcha() {
|
||||
* 先弹出滑块,通过后执行 bizVerify(captchaVerifyParam),再根据结果调用 onSuccess。
|
||||
*/
|
||||
async function runWithCaptcha(bizVerify, onSuccess) {
|
||||
if (typeof window === 'undefined') {
|
||||
showToast({ message: '验证码仅支持浏览器环境' })
|
||||
return
|
||||
if (typeof window === "undefined") {
|
||||
showToast({ message: "验证码仅支持浏览器环境" });
|
||||
return;
|
||||
}
|
||||
|
||||
showLoadingToast({
|
||||
message: '安全验证加载中...',
|
||||
const loading = showLoadingToast({
|
||||
message: "安全验证加载中...",
|
||||
forbidClick: true,
|
||||
duration: 0,
|
||||
loadingType: 'spinner',
|
||||
})
|
||||
loadingType: "spinner",
|
||||
});
|
||||
|
||||
try {
|
||||
window.__captchaVerifyCallback = async (captchaVerifyParam) => {
|
||||
window.__lastBizResponse = null
|
||||
const { data, error } = await bizVerify(captchaVerifyParam)
|
||||
const result = data?.value ?? data
|
||||
window.__lastBizResponse = null;
|
||||
const { data, error } = await bizVerify(captchaVerifyParam);
|
||||
const result = data?.value ?? data;
|
||||
if (error?.value || !result) {
|
||||
return { captchaResult: false, bizResult: false }
|
||||
return { captchaResult: false, bizResult: false };
|
||||
}
|
||||
window.__lastBizResponse = result
|
||||
const captchaOk = result.captchaVerifyResult !== false
|
||||
const bizOk = result.code === 200
|
||||
return { captchaResult: captchaOk, bizResult: bizOk }
|
||||
}
|
||||
window.__lastBizResponse = result;
|
||||
const captchaOk = result.captchaVerifyResult !== false;
|
||||
const bizOk = result.code === 200;
|
||||
return { captchaResult: captchaOk, bizResult: bizOk };
|
||||
};
|
||||
|
||||
window.__onBizResultCallback = (bizResult) => {
|
||||
if (
|
||||
bizResult === true &&
|
||||
window.__lastBizResponse &&
|
||||
typeof window.__onCaptchaBizSuccess === 'function'
|
||||
typeof window.__onCaptchaBizSuccess === "function"
|
||||
) {
|
||||
window.__onCaptchaBizSuccess(window.__lastBizResponse)
|
||||
window.__onCaptchaBizSuccess(window.__lastBizResponse);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
await ensureCaptchaInit()
|
||||
await ensureCaptchaInit();
|
||||
|
||||
// 首次初始化时 SDK 会异步调用 getInstance,需等待实例就绪后再 show
|
||||
if (captchaReadyPromise) {
|
||||
await captchaReadyPromise
|
||||
captchaReadyPromise = null
|
||||
await captchaReadyPromise;
|
||||
captchaReadyPromise = null;
|
||||
}
|
||||
if (!window.captcha) {
|
||||
showToast({ message: '验证码未加载,请刷新页面重试' })
|
||||
return
|
||||
showToast({ message: "验证码未加载,请刷新页面重试" });
|
||||
return;
|
||||
}
|
||||
window.__onCaptchaBizSuccess = onSuccess
|
||||
window.captcha.show()
|
||||
window.__onCaptchaBizSuccess = onSuccess;
|
||||
window.captcha.show();
|
||||
} finally {
|
||||
closeToast()
|
||||
closeToast();
|
||||
}
|
||||
}
|
||||
|
||||
return { runWithCaptcha }
|
||||
return { runWithCaptcha };
|
||||
}
|
||||
|
||||
export default useAliyunCaptcha;
|
||||
|
||||
Reference in New Issue
Block a user