添加行为验证码
This commit is contained in:
@@ -2,6 +2,9 @@
|
|||||||
VITE_APP_TITLE = RuoYi-Vue-Plus后台管理系统
|
VITE_APP_TITLE = RuoYi-Vue-Plus后台管理系统
|
||||||
VITE_APP_LOGO_TITLE = RuoYi-Vue-Plus
|
VITE_APP_LOGO_TITLE = RuoYi-Vue-Plus
|
||||||
|
|
||||||
|
# 后台请求地址
|
||||||
|
VITE_API_TARGET=http://localhost:8080
|
||||||
|
|
||||||
# 开发环境配置
|
# 开发环境配置
|
||||||
VITE_APP_ENV = 'development'
|
VITE_APP_ENV = 'development'
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
|
|
||||||
</style>
|
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
// 返回状态定义
|
||||||
|
export type CaptchaResult = -1 | 0 | 1
|
||||||
|
type CaptchaStatusCallback = (status: CaptchaResult) => void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 唤起 tianai TAC行为验证码
|
||||||
|
* ✅ 动态创建全局遮罩容器,无需模板写div
|
||||||
|
* ✅ 弹窗视口永久居中,全局最高层级
|
||||||
|
* ✅ 完全对齐官方loadTAC配置参数
|
||||||
|
* @param onStatusChange 状态回调,0=未完成
|
||||||
|
* @returns Promise<CaptchaResult> 1成功,-1失败/关闭/加载异常
|
||||||
|
*/
|
||||||
|
export async function showTACCaptcha(onStatusChange?: CaptchaStatusCallback): Promise<CaptchaResult> {
|
||||||
|
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
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
+16
-31
@@ -5,39 +5,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="Index" lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
|
||||||
|
import {CaptchaResult,showTACCaptcha} from "@/utils/captcha";
|
||||||
|
|
||||||
async function login() {
|
async function login() {
|
||||||
await nextTick()
|
const captchaRes: CaptchaResult = await showTACCaptcha((status) => {
|
||||||
const captchaConfig = {
|
console.log('验证码实时状态:', status)
|
||||||
// 请求验证码接口
|
|
||||||
requestCaptchaDataUrl: "http://localhost:8080/resource/captcha/behavior/generate",
|
|
||||||
// 验证验证码接口
|
|
||||||
validCaptchaUrl: "http://localhost:8080/resource/captcha/behavior/verify",
|
|
||||||
// 绑定的div
|
|
||||||
bindEl: "#captcha-box",
|
|
||||||
// 验证成功回调函数
|
|
||||||
validSuccess: (res, c, t) => {
|
|
||||||
console.log("验证码验证成功回调...")
|
|
||||||
// 销毁验证码
|
|
||||||
t.destroyWindow();
|
|
||||||
alert("验证成功: token:" + res.data.token)
|
|
||||||
console.log(res)
|
|
||||||
// todo 携带token调用登录接口
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 一些样式配置, 可不传
|
|
||||||
let style = {
|
|
||||||
logoUrl: null// 去除logo
|
|
||||||
// logoUrl: "/xx/xx/xxx.png" // 替换成自定义的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);
|
|
||||||
})
|
})
|
||||||
|
switch (captchaRes) {
|
||||||
|
case 1:
|
||||||
|
console.log("✅验证码校验成功,拿token调用登录接口")
|
||||||
|
// todo: 在这里调用登录,带上后端返回的token
|
||||||
|
break
|
||||||
|
case -1:
|
||||||
|
console.log("❌ 关闭弹窗 / 加载失败")
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ import { authRouterUrl } from '@/api/system/social/auth';
|
|||||||
import { LoginData } from '@/api/types';
|
import { LoginData } from '@/api/types';
|
||||||
import { HttpStatus } from '@/enums/RespEnum';
|
import { HttpStatus } from '@/enums/RespEnum';
|
||||||
import { useUserStore } from '@/store/modules/user';
|
import { useUserStore } from '@/store/modules/user';
|
||||||
|
import {CaptchaResult, showTACCaptcha} from "@/utils/captcha";
|
||||||
|
|
||||||
const title = import.meta.env.VITE_APP_TITLE;
|
const title = import.meta.env.VITE_APP_TITLE;
|
||||||
const currentYear = new Date().getFullYear();
|
const currentYear = new Date().getFullYear();
|
||||||
@@ -185,6 +186,26 @@ const handleLogin = () => {
|
|||||||
loginRef.value?.validate(async (valid: boolean, fields: any) => {
|
loginRef.value?.validate(async (valid: boolean, fields: any) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
loading.value = true;
|
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) {
|
if (loginForm.value.rememberMe) {
|
||||||
localStorage.setItem('username', String(loginForm.value.username));
|
localStorage.setItem('username', String(loginForm.value.username));
|
||||||
localStorage.setItem('rememberMe', String(loginForm.value.rememberMe));
|
localStorage.setItem('rememberMe', String(loginForm.value.rememberMe));
|
||||||
@@ -210,6 +231,7 @@ const handleLogin = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const getCode = async () => {
|
const getCode = async () => {
|
||||||
const res = await getCodeImg();
|
const res = await getCodeImg();
|
||||||
const { data } = res;
|
const { data } = res;
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
import { defineConfig, loadEnv } from 'vite';
|
import { defineConfig, loadEnv } from 'vite';
|
||||||
import createPlugins from './vite/plugins';
|
import createPlugins from './vite/plugins/index';
|
||||||
import autoprefixer from 'autoprefixer'; // css自动添加兼容性前缀
|
import autoprefixer from 'autoprefixer'; // css自动添加兼容性前缀
|
||||||
|
|
||||||
export default defineConfig(({ mode, command }) => {
|
export default defineConfig(({ mode, command }) => {
|
||||||
@@ -30,7 +30,7 @@ export default defineConfig(({ mode, command }) => {
|
|||||||
open: true,
|
open: true,
|
||||||
proxy: {
|
proxy: {
|
||||||
[env.VITE_APP_BASE_API]: {
|
[env.VITE_APP_BASE_API]: {
|
||||||
target: 'http://localhost:8080',
|
target: env.VITE_API_TARGET,
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
ws: true,
|
ws: true,
|
||||||
rewrite: path => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
|
rewrite: path => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
|
||||||
|
|||||||
Reference in New Issue
Block a user