From 1652ee1e55a344c6064b9501d75f4dd343b22cea Mon Sep 17 00:00:00 2001 From: Mrx <18278715334@163.com> Date: Thu, 5 Mar 2026 16:54:19 +0800 Subject: [PATCH] 1 --- src/auto-imports.d.ts | 2 +- src/components/InquireForm.vue | 8 +- src/composables/useAliyunCaptcha.js | 245 +++++++++++----------------- 3 files changed, 103 insertions(+), 152 deletions(-) diff --git a/src/auto-imports.d.ts b/src/auto-imports.d.ts index 38b094f..f0f911a 100644 --- a/src/auto-imports.d.ts +++ b/src/auto-imports.d.ts @@ -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'] diff --git a/src/components/InquireForm.vue b/src/components/InquireForm.vue index aab855d..570c081 100644 --- a/src/components/InquireForm.vue +++ b/src/components/InquireForm.vue @@ -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 || "验证码发送失败,请重试" }); } } ); diff --git a/src/composables/useAliyunCaptcha.js b/src/composables/useAliyunCaptcha.js index 74a4035..56a88ec 100644 --- a/src/composables/useAliyunCaptcha.js +++ b/src/composables/useAliyunCaptcha.js @@ -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;