perf: 登录支持极验验证码

This commit is contained in:
xiaojunnuo
2025-09-11 23:47:05 +08:00
parent 65f34f1d31
commit 370db62bf0
22 changed files with 552 additions and 129 deletions
@@ -0,0 +1,90 @@
<template>
<div ref="captchaRef" class="captcha_input"></div>
</template>
<script setup lang="ts">
import { onMounted, defineProps, defineEmits, ref } from "vue";
import { useSettingStore } from "/@/store/settings";
import { request } from "/src/api/service";
import { notification } from "ant-design-vue";
const props = defineProps<{
modelValue?: any;
}>();
const emit = defineEmits(["update:modelValue", "change"]);
const captchaRef = ref(null);
// const addonApi = createAddonApi();
const settingStore = useSettingStore();
const api = {
async getClientParams(): Promise<any> {
const res = await request({
url: "/captcha/getParams",
method: "post",
});
return res;
},
};
// async function getCaptchaAddonDefine() {
// const type = settingStore.public.captchaType;
// const define = addonApi.getDefineByType("captcha", type);
// }
const captchaInstanceRef = ref({});
async function init() {
const params = await api.getClientParams();
// @ts-ignore
initGeetest4(
{
captchaId: params.captchaId,
},
(captcha: any) => {
// captcha为验证码实例
captcha.appendTo(captchaRef.value); // 调用appendTo将验证码插入到页的某一个元素中,这个元素用户可以自定义
captchaInstanceRef.value.instance = captcha;
captchaInstanceRef.value.captchaId = params.captchaId;
}
);
}
async function getValidatedForm() {
if (!captchaInstanceRef.value?.instance) {
notification.error({
message: "验证码还未初始化",
});
return false;
}
const result = await captchaInstanceRef.value.instance.getValidate();
if (!result) {
notification.error({
message: "请先完成验证码验证",
});
return false;
}
result.captcha_id = captchaInstanceRef.value.captchaId;
return result;
}
function onChange(value: string) {
emit("update:modelValue", value);
emit("change", value);
}
defineExpose({
getValidatedForm,
});
onMounted(async () => {
await init();
});
</script>
<style lang="less">
.captcha_input {
.geetest_captcha {
.geetest_holder {
width: 100%;
}
}
}
</style>
@@ -1,46 +0,0 @@
<template>
<div class="captcha"></div>
</template>
<script setup lang="ts">
import { doRequest } from "/@/components/plugins/lib";
import { createAddonApi } from "/src/api/modules/addon";
import { useSettingStore } from "/@/store/settings";
const props = defineProps<{
modelValue?: any;
}>();
const emit = defineEmits(["update:modelValue", "change"]);
const addonApi = createAddonApi();
const settingStore = useSettingStore();
async function getCaptchaAddonDefine() {
const type = settingStore.public.captchaType;
const define = addonApi.getDefineByType("captcha", type);
const res = await doRequest(
{
addonId: settingStore.public.captchaAddonId
type: "captcha",
typeName: type,
action: "onGetParams",
},
);
}
function init() {
// @ts-ignore
initGeetest4(
{
captchaId: "您的captchaId",
},
(captcha: any) => {
// captcha为验证码实例
captcha.appendTo(".captcha"); // 调用appendTo将验证码插入到页的某一个元素中,这个元素用户可以自定义
}
);
}
function onChange(value: string) {
emit("update:modelValue", value);
emit("change", value);
}
</script>
@@ -21,8 +21,8 @@
</a-input-password>
</a-form-item>
<a-form-item required name="captcha">
<captcha v-model:model-value="formState.captcha"></captcha>
<a-form-item v-if="settingStore.sysPublic.captchaEnabled" required name="captcha">
<CaptchaInput ref="captchaInputRef" v-model:model-value="formState.captcha"></CaptchaInput>
</a-form-item>
</template>
</a-tab-pane>
@@ -95,10 +95,10 @@ import ImageCode from "/@/views/framework/login/image-code.vue";
import SmsCode from "/@/views/framework/login/sms-code.vue";
import { useI18n } from "/@/locales";
import { LanguageToggle } from "/@/vben/layouts";
import CaptchaInput from "./captcha-input.vue";
export default defineComponent({
name: "LoginPage",
components: { LanguageToggle, SmsCode, ImageCode },
components: { LanguageToggle, SmsCode, ImageCode, CaptchaInput },
setup() {
const { t } = useI18n();
const verifyCodeInputRef = ref();
@@ -165,6 +165,10 @@ export default defineComponent({
const handleFinish = async (values: any) => {
loading.value = true;
try {
formState.captcha = await doCaptchaValidate();
if (!formState.captcha) {
return;
}
const loginType = formState.loginType;
await userStore.login(loginType, toRaw(formState));
} catch (e: any) {
@@ -199,6 +203,20 @@ export default defineComponent({
return sysPublicSettings.registerEnabled && (sysPublicSettings.usernameRegisterEnabled || sysPublicSettings.emailRegisterEnabled);
}
const captchaInputRef = ref();
async function doCaptchaValidate() {
if (!sysPublicSettings.captchaEnabled) {
return {};
}
const res = await captchaInputRef.value.getValidatedForm();
if (!res) {
return false;
}
return {
...res,
};
}
return {
t,
loading,
@@ -216,6 +234,7 @@ export default defineComponent({
handleTwoFactorSubmit,
verifyCodeInputRef,
settingStore,
captchaInputRef,
};
},
});