From c982ecee68d72bea341b27a582f9f84cd08ce36a Mon Sep 17 00:00:00 2001 From: xiaozhi <1822691309@qq.com> Date: Thu, 10 Sep 2026 20:31:00 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=A1=8C=E4=B8=BA=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 3 + src/components/Captcha/index.vue | 11 ---- src/utils/captcha.ts | 94 ++++++++++++++++++++++++++++++++ src/views/index.vue | 47 ++++++---------- src/views/login.vue | 22 ++++++++ vite.config.ts | 4 +- 6 files changed, 137 insertions(+), 44 deletions(-) delete mode 100644 src/components/Captcha/index.vue create mode 100644 src/utils/captcha.ts diff --git a/.env.development b/.env.development index 5bfb9da..bb23c99 100644 --- a/.env.development +++ b/.env.development @@ -2,6 +2,9 @@ VITE_APP_TITLE = RuoYi-Vue-Plus后台管理系统 VITE_APP_LOGO_TITLE = RuoYi-Vue-Plus +# 后台请求地址 +VITE_API_TARGET=http://localhost:8080 + # 开发环境配置 VITE_APP_ENV = 'development' diff --git a/src/components/Captcha/index.vue b/src/components/Captcha/index.vue deleted file mode 100644 index 63cf316..0000000 --- a/src/components/Captcha/index.vue +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/src/utils/captcha.ts b/src/utils/captcha.ts new file mode 100644 index 0000000..80f9beb --- /dev/null +++ b/src/utils/captcha.ts @@ -0,0 +1,94 @@ +// 返回状态定义 +export type CaptchaResult = -1 | 0 | 1 +type CaptchaStatusCallback = (status: CaptchaResult) => void + +/** + * 唤起 tianai TAC行为验证码 + * ✅ 动态创建全局遮罩容器,无需模板写div + * ✅ 弹窗视口永久居中,全局最高层级 + * ✅ 完全对齐官方loadTAC配置参数 + * @param onStatusChange 状态回调,0=未完成 + * @returns Promise 1成功,-1失败/关闭/加载异常 + */ +export async function showTACCaptcha(onStatusChange?: CaptchaStatusCallback): Promise { + await nextTick() + return new Promise((resolve) => { + // ========= 动态创建全局全屏遮罩容器 ========= + const maskWrap = document.createElement('div') + const tempId = 'tac-captcha-temp-' + Date.now() + maskWrap.id = tempId + + // 全局顶层全屏遮罩 + flex居中 + maskWrap.style.position = 'fixed' + maskWrap.style.top = '0' + maskWrap.style.left = '0' + maskWrap.style.width = '100vw' + maskWrap.style.height = '100vh' + maskWrap.style.zIndex = '99999' + maskWrap.style.backgroundColor = 'rgba(0,0,0,0.5)' + maskWrap.style.display = 'flex' + maskWrap.style.alignItems = 'center' + maskWrap.style.justifyContent = 'center' + maskWrap.style.margin = '0' + maskWrap.style.padding = '0' + maskWrap.style.overflow = 'hidden' + document.body.appendChild(maskWrap) + + const bindSelector = `#${tempId}` + // 打开弹窗,状态=未完成 + onStatusChange?.(0) + + const captchaConfig = { + // 请求验证码接口 + requestCaptchaDataUrl: "http://localhost:8080/resource/captcha/behavior/generate", + // 验证验证码接口 + validCaptchaUrl: "http://localhost:8080/resource/captcha/behavior/verify", + // 绑定的div + bindEl: bindSelector, + // 验证成功回调函数 + validSuccess: (res, c, t) => { + console.log("验证码验证成功回调...") + // 销毁验证码 + t.destroyWindow(); + document.body.removeChild(maskWrap) + console.log(res) + onStatusChange?.(1) + resolve(1) // ✅ 成功,返回1,await解除阻塞 + }, + // 验证失败的回调函数(可忽略,如果不自定义 validFail 方法时,会使用默认的) + validFail: (res, c, t) => { + console.log("验证码验证失败回调..."); + // 验证失败后重新拉取验证码 + t.reloadCaptcha(); + }, + // 刷新按钮回调事件 + btnRefreshFun: (el, tac) => { + console.log("刷新按钮触发事件..."); + tac.reloadCaptcha(); + }, + // 关闭按钮回调事件 + btnCloseFun: (el, tac) => { + console.log("关闭按钮触发事件..."); + tac.destroyWindow(); + document.body.removeChild(maskWrap) + onStatusChange?.(-1) + resolve(-1) // ✅ 用户关闭弹窗,返回 -1 + } + } + // 一些样式配置, 可不传 + let style = { + logoUrl: null// 去除logo + } + // 参数1 为 tac文件是目录地址, 目录里包含 tac的js和css等文件 + // 参数2 为 tac验证码相关配置 + // 参数3 为 tac窗口一些样式配置 + window.initTAC("./tac", captchaConfig, style).then(tac => { + tac.init(); // 调用init则显示验证码 + }).catch(e => { + console.log("初始化tac失败", e); + document.body.removeChild(maskWrap) + onStatusChange?.(-1) + resolve(-1) // ✅ 初始化异常,返回 -1 + }) + }) +} diff --git a/src/views/index.vue b/src/views/index.vue index a8c1e39..6ed16a7 100644 --- a/src/views/index.vue +++ b/src/views/index.vue @@ -5,39 +5,24 @@ - diff --git a/src/views/login.vue b/src/views/login.vue index e360dcf..bfb11c9 100644 --- a/src/views/login.vue +++ b/src/views/login.vue @@ -121,6 +121,7 @@ import { authRouterUrl } from '@/api/system/social/auth'; import { LoginData } from '@/api/types'; import { HttpStatus } from '@/enums/RespEnum'; import { useUserStore } from '@/store/modules/user'; +import {CaptchaResult, showTACCaptcha} from "@/utils/captcha"; const title = import.meta.env.VITE_APP_TITLE; const currentYear = new Date().getFullYear(); @@ -185,6 +186,26 @@ const handleLogin = () => { loginRef.value?.validate(async (valid: boolean, fields: any) => { if (valid) { loading.value = true; + const captchaRes: CaptchaResult = await showTACCaptcha((status) => { + console.log('验证码实时状态:', status) + }) + console.log("captchaRes结果:", captchaRes) // 打印看实际返回值!重点调试 + + switch (captchaRes) { + case 1: + console.log("✅验证码校验成功,拿token调用登录接口") + break // 跳出switch,继续往下执行登录 + case -1: + console.log("❌ 关闭弹窗 / 加载失败") + loading.value = false; + return; // 退出当前async回调,不再执行后面登录代码 + default: + console.log("⚠️ 验证码其他状态", captchaRes) + loading.value = false; + return; + } + + // ========== 验证码成功才会执行到这里 ========== if (loginForm.value.rememberMe) { localStorage.setItem('username', String(loginForm.value.username)); localStorage.setItem('rememberMe', String(loginForm.value.rememberMe)); @@ -210,6 +231,7 @@ const handleLogin = () => { }); }; + const getCode = async () => { const res = await getCodeImg(); const { data } = res; diff --git a/vite.config.ts b/vite.config.ts index fe142c7..a896a6c 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,5 +1,5 @@ import { defineConfig, loadEnv } from 'vite'; -import createPlugins from './vite/plugins'; +import createPlugins from './vite/plugins/index'; import autoprefixer from 'autoprefixer'; // css自动添加兼容性前缀 export default defineConfig(({ mode, command }) => { @@ -30,7 +30,7 @@ export default defineConfig(({ mode, command }) => { open: true, proxy: { [env.VITE_APP_BASE_API]: { - target: 'http://localhost:8080', + target: env.VITE_API_TARGET, changeOrigin: true, ws: true, rewrite: path => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')