mirror of https://github.com/certd/certd
perf: 登录失败时清除验证码状态
parent
2c1600ddfb
commit
1c15beadc7
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<component :is="captchaComponent" v-if="settingStore.inited" ref="captchaRef" class="captcha_input" :captcha-get="getCaptcha" @change="onChange" />
|
<component :is="captchaComponent" v-if="settingStore.inited" ref="captchaRef" :model-value="modelValue" class="captcha_input" :captcha-get="getCaptcha" @change="onChange" />
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, defineAsyncComponent } from "vue";
|
import { ref, computed, defineAsyncComponent } from "vue";
|
||||||
|
@ -7,6 +7,12 @@ import { useSettingStore } from "/@/store/settings";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import { request } from "/@/api/service";
|
import { request } from "/@/api/service";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
});
|
||||||
const captchaRef = ref(null);
|
const captchaRef = ref(null);
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
|
|
||||||
|
@ -17,7 +23,7 @@ const captchaAddonId = computed(() => {
|
||||||
return settingStore.sysPublic.captchaAddonId ?? 0;
|
return settingStore.sysPublic.captchaAddonId ?? 0;
|
||||||
});
|
});
|
||||||
const captchaComponent = computed(() => {
|
const captchaComponent = computed(() => {
|
||||||
let type = "image";
|
let type: any = "image";
|
||||||
if (settingStore.sysPublic.captchaAddonId && settingStore.sysPublic.captchaType) {
|
if (settingStore.sysPublic.captchaAddonId && settingStore.sysPublic.captchaType) {
|
||||||
type = settingStore.sysPublic.captchaType;
|
type = settingStore.sysPublic.captchaType;
|
||||||
}
|
}
|
||||||
|
@ -36,7 +42,7 @@ async function getCaptcha(): Promise<any> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function onChange(data) {
|
function onChange(data: any) {
|
||||||
emits("update:modelValue", data);
|
emits("update:modelValue", data);
|
||||||
emits("change", data);
|
emits("change", data);
|
||||||
}
|
}
|
||||||
|
@ -44,7 +50,11 @@ function onChange(data) {
|
||||||
async function getCaptchaForm() {
|
async function getCaptchaForm() {
|
||||||
return await captchaRef.value.getCaptchaForm();
|
return await captchaRef.value.getCaptchaForm();
|
||||||
}
|
}
|
||||||
|
async function reset() {
|
||||||
|
await captchaRef.value.reset();
|
||||||
|
}
|
||||||
defineExpose({
|
defineExpose({
|
||||||
getCaptchaForm,
|
getCaptchaForm,
|
||||||
|
reset,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<div ref="captchaRef" class="geetest_captcha_wrapper"></div>
|
<div ref="captchaRef" class="geetest_captcha_wrapper"></div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, defineProps, defineEmits, ref, onUnmounted } from "vue";
|
import { onMounted, defineProps, defineEmits, ref, onUnmounted, Ref, watch } from "vue";
|
||||||
import { useSettingStore } from "/@/store/settings";
|
import { useSettingStore } from "/@/store/settings";
|
||||||
import { request } from "/src/api/service";
|
import { request } from "/src/api/service";
|
||||||
import { notification } from "ant-design-vue";
|
import { notification } from "ant-design-vue";
|
||||||
|
@ -12,13 +12,14 @@ defineOptions({
|
||||||
});
|
});
|
||||||
const emit = defineEmits(["update:modelValue", "change"]);
|
const emit = defineEmits(["update:modelValue", "change"]);
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
modelValue: any;
|
||||||
captchaGet: () => Promise<any>;
|
captchaGet: () => Promise<any>;
|
||||||
}>();
|
}>();
|
||||||
const captchaRef = ref(null);
|
const captchaRef = ref(null);
|
||||||
// const addonApi = createAddonApi();
|
// const addonApi = createAddonApi();
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
|
|
||||||
const captchaInstanceRef = ref({});
|
const captchaInstanceRef: Ref = ref({});
|
||||||
async function init() {
|
async function init() {
|
||||||
// if (!initGeetest4) {
|
// if (!initGeetest4) {
|
||||||
// await import("https://static.geetest.com/v4/gt4.js");
|
// await import("https://static.geetest.com/v4/gt4.js");
|
||||||
|
@ -35,6 +36,13 @@ async function init() {
|
||||||
captcha.appendTo(captchaRef.value); // 调用appendTo将验证码插入到页的某一个元素中,这个元素用户可以自定义
|
captcha.appendTo(captchaRef.value); // 调用appendTo将验证码插入到页的某一个元素中,这个元素用户可以自定义
|
||||||
captchaInstanceRef.value.instance = captcha;
|
captchaInstanceRef.value.instance = captcha;
|
||||||
captchaInstanceRef.value.captchaId = captchaId;
|
captchaInstanceRef.value.captchaId = captchaId;
|
||||||
|
|
||||||
|
captcha.onSuccess(function () {
|
||||||
|
const form = getCaptchaForm();
|
||||||
|
if (form) {
|
||||||
|
emitChange(form);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -58,29 +66,51 @@ function getCaptchaForm() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const valueRef = ref(null);
|
// const valueRef = ref(null);
|
||||||
const timeoutId = setInterval(() => {
|
// const timeoutId = setInterval(() => {
|
||||||
const form = getCaptchaForm();
|
// const form = getCaptchaForm();
|
||||||
if (form && valueRef.value != form) {
|
// if (form && valueRef.value != form) {
|
||||||
console.log("form", form);
|
// console.log("form", form);
|
||||||
valueRef.value = form;
|
// valueRef.value = form;
|
||||||
emitChange(form);
|
// emitChange(form);
|
||||||
}
|
// }
|
||||||
}, 1000);
|
// }, 1000);
|
||||||
|
|
||||||
onUnmounted(() => {
|
// onUnmounted(() => {
|
||||||
clearTimeout(timeoutId);
|
// clearTimeout(timeoutId);
|
||||||
});
|
// });
|
||||||
|
|
||||||
function emitChange(value: string) {
|
function emitChange(value: string) {
|
||||||
emit("update:modelValue", value);
|
emit("update:modelValue", value);
|
||||||
emit("change", value);
|
emit("change", value);
|
||||||
}
|
}
|
||||||
|
function reset() {
|
||||||
|
captchaInstanceRef.value.instance.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => {
|
||||||
|
return props.modelValue;
|
||||||
|
},
|
||||||
|
value => {
|
||||||
|
if (value == null) {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
getCaptchaForm,
|
getCaptchaForm,
|
||||||
|
reset,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => [props.captchaGet],
|
||||||
|
async () => {
|
||||||
|
await init();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await init();
|
await init();
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,10 +11,11 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineEmits, defineExpose, defineProps, ref } from "vue";
|
import { defineEmits, defineExpose, defineProps, ref, watch } from "vue";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
modelValue: any;
|
||||||
captchaGet?: () => Promise<any>;
|
captchaGet?: () => Promise<any>;
|
||||||
}>();
|
}>();
|
||||||
defineOptions({
|
defineOptions({
|
||||||
|
@ -42,6 +43,7 @@ function getCaptchaForm() {
|
||||||
defineExpose({
|
defineExpose({
|
||||||
resetImageCode,
|
resetImageCode,
|
||||||
getCaptchaForm,
|
getCaptchaForm,
|
||||||
|
reset: resetImageCode,
|
||||||
});
|
});
|
||||||
|
|
||||||
resetImageCode();
|
resetImageCode();
|
||||||
|
@ -52,7 +54,18 @@ function onChange(value: string) {
|
||||||
emitChange(form);
|
emitChange(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitChange(value) {
|
watch(
|
||||||
|
() => {
|
||||||
|
return props.modelValue;
|
||||||
|
},
|
||||||
|
value => {
|
||||||
|
if (value == null) {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
function emitChange(value: any) {
|
||||||
emit("update:modelValue", value);
|
emit("update:modelValue", value);
|
||||||
emit("change", value);
|
emit("change", value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,10 +21,17 @@
|
||||||
</a-input>
|
</a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item has-feedback name="captchaForEmail" label="验证码">
|
<a-form-item has-feedback name="captchaForEmail" label="验证码">
|
||||||
<CaptchaInput v-model:model-value="formState.captchaForEmail"></CaptchaInput>
|
<CaptchaInput ref="captchaForEmailRef" v-model:model-value="formState.captchaForEmail"></CaptchaInput>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item has-feedback name="validateCode" label="邮件验证码">
|
<a-form-item has-feedback name="validateCode" label="邮件验证码">
|
||||||
<email-code v-model:value="formState.validateCode" :captcha="formState.captchaForEmail" :email="formState.input" :random-str="formState.randomStr" verification-type="forgotPassword" />
|
<email-code
|
||||||
|
v-model:value="formState.validateCode"
|
||||||
|
:captcha="formState.captchaForEmail"
|
||||||
|
:email="formState.input"
|
||||||
|
:random-str="formState.randomStr"
|
||||||
|
verification-type="forgotPassword"
|
||||||
|
@error="formState.captchaForEmail = null"
|
||||||
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane key="mobile" tab="手机号找回">
|
<a-tab-pane key="mobile" tab="手机号找回">
|
||||||
|
@ -36,10 +43,17 @@
|
||||||
</a-input>
|
</a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item has-feedback name="captchaForSms" label="验证码">
|
<a-form-item has-feedback name="captchaForSms" label="验证码">
|
||||||
<CaptchaInput v-model:model-value="formState.captchaForSms"></CaptchaInput>
|
<CaptchaInput ref="captchaForSmsRef" v-model:model-value="formState.captchaForSms"></CaptchaInput>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item name="validateCode" label="手机验证码">
|
<a-form-item name="validateCode" label="手机验证码">
|
||||||
<sms-code v-model:value="formState.validateCode" :captcha="formState.captchaForSms" :mobile="formState.input" :phone-code="formState.phoneCode" verification-type="forgotPassword" />
|
<sms-code
|
||||||
|
v-model:value="formState.validateCode"
|
||||||
|
:captcha="formState.captchaForSms"
|
||||||
|
:mobile="formState.input"
|
||||||
|
:phone-code="formState.phoneCode"
|
||||||
|
verification-type="forgotPassword"
|
||||||
|
@error="formState.captchaForSms = null"
|
||||||
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
|
@ -141,15 +155,20 @@ watch(forgotPasswordType, () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleFinish = async (values: any) => {
|
const handleFinish = async (values: any) => {
|
||||||
await userStore.forgotPassword(
|
try {
|
||||||
toRaw({
|
await userStore.forgotPassword(
|
||||||
type: forgotPasswordType.value,
|
toRaw({
|
||||||
input: formState.input,
|
type: forgotPasswordType.value,
|
||||||
validateCode: formState.validateCode,
|
input: formState.input,
|
||||||
password: formState.password,
|
validateCode: formState.validateCode,
|
||||||
confirmPassword: formState.confirmPassword,
|
password: formState.password,
|
||||||
}) as any
|
confirmPassword: formState.confirmPassword,
|
||||||
);
|
}) as any
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
formState.captchaForSms = null;
|
||||||
|
formState.captchaForEmail = null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFinishFailed = (errors: any) => {
|
const handleFinishFailed = (errors: any) => {
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-form-item name="smsCode" :rules="rules.smsCode">
|
<a-form-item name="smsCode" :rules="rules.smsCode">
|
||||||
<sms-code v-model:value="formState.smsCode" :captcha="formState.smsCaptcha" :mobile="formState.mobile" :phone-code="formState.phoneCode" />
|
<sms-code v-model:value="formState.smsCode" :captcha="formState.smsCaptcha" :mobile="formState.mobile" :phone-code="formState.phoneCode" @error="formState.smsCaptcha = null" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</template>
|
</template>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
|
@ -188,6 +188,8 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
formState.captcha = null;
|
||||||
|
formState.smsCaptcha = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -209,18 +211,6 @@ export default defineComponent({
|
||||||
|
|
||||||
const captchaInputRef = ref();
|
const captchaInputRef = ref();
|
||||||
const captchaInputForSmsCode = ref();
|
const captchaInputForSmsCode = ref();
|
||||||
async function doCaptchaValidate() {
|
|
||||||
if (!sysPublicSettings.captchaEnabled) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
const res = await captchaInputRef.value.getValidatedForm();
|
|
||||||
if (!res) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...res,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
t,
|
t,
|
||||||
|
|
|
@ -24,7 +24,7 @@ const props = defineProps<{
|
||||||
captcha?: any;
|
captcha?: any;
|
||||||
verificationType?: string;
|
verificationType?: string;
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits(["update:value", "change"]);
|
const emit = defineEmits(["update:value", "change", "error"]);
|
||||||
|
|
||||||
function onChange(value: string) {
|
function onChange(value: string) {
|
||||||
emit("update:value", value);
|
emit("update:value", value);
|
||||||
|
@ -59,6 +59,9 @@ async function sendSmsCode() {
|
||||||
captcha: props.captcha,
|
captcha: props.captcha,
|
||||||
verificationType: props.verificationType,
|
verificationType: props.verificationType,
|
||||||
});
|
});
|
||||||
|
} catch (e) {
|
||||||
|
emit("error", e);
|
||||||
|
throw e;
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ const props = defineProps<{
|
||||||
captcha?: any;
|
captcha?: any;
|
||||||
verificationType?: string;
|
verificationType?: string;
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits(["update:value", "change"]);
|
const emit = defineEmits(["update:value", "change", "error"]);
|
||||||
|
|
||||||
function onChange(value: string) {
|
function onChange(value: string) {
|
||||||
emit("update:value", value);
|
emit("update:value", value);
|
||||||
|
@ -54,6 +54,9 @@ async function sendSmsCode() {
|
||||||
captcha: props.captcha,
|
captcha: props.captcha,
|
||||||
verificationType: props.verificationType,
|
verificationType: props.verificationType,
|
||||||
});
|
});
|
||||||
|
} catch (e) {
|
||||||
|
emit("error", e);
|
||||||
|
throw e;
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-form-item has-feedback name="validateCode" :rules="rules.validateCode" label="邮件验证码">
|
<a-form-item has-feedback name="validateCode" :rules="rules.validateCode" label="邮件验证码">
|
||||||
<email-code v-model:value="formState.validateCode" :captcha="formState.captchaForEmail" :email="formState.email" />
|
<email-code v-model:value="formState.validateCode" :captcha="formState.captchaForEmail" :email="formState.email" @error="formState.captchaForEmail = null" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</template>
|
</template>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
|
@ -182,16 +182,20 @@ export default defineComponent({
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFinish = async (values: any) => {
|
const handleFinish = async (values: any) => {
|
||||||
await userStore.register(
|
try {
|
||||||
toRaw({
|
await userStore.register(
|
||||||
type: registerType.value,
|
toRaw({
|
||||||
password: formState.password,
|
type: registerType.value,
|
||||||
username: formState.username,
|
password: formState.password,
|
||||||
email: formState.email,
|
username: formState.username,
|
||||||
captcha: formState.captcha,
|
email: formState.email,
|
||||||
validateCode: formState.validateCode,
|
captcha: formState.captcha,
|
||||||
}) as any
|
validateCode: formState.validateCode,
|
||||||
);
|
}) as any
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
formState.captcha = null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFinishFailed = (errors: any) => {
|
const handleFinishFailed = (errors: any) => {
|
||||||
|
|
Loading…
Reference in New Issue