foreign-admin-ui/src/views/user/components/Captcha.vue

117 lines
2.4 KiB
Vue

<template>
<el-form-item class="captcha-container" label="请输入验证码" label-position="top" :prop="prop">
<el-input-otp v-model="captchaValue" :length="length" integer @change="handleChange" @finish="handleFinish" size="large" />
<el-button type="primary" class="form-btn" v-if="showSendButton" @click="sendCode" :disabled="isCounting">{{
isCounting ? `${countdown}s后重新获取` : '发送验证码' }}</el-button>
</el-form-item>
</template>
<script setup lang="ts">
import { ref, watch, toRefs } from 'vue'
defineOptions({
name: 'Captcha'
})
const props = defineProps({
modelValue: {
type: String,
default: ''
},
length: {
type: Number,
default: 6
},
showSendButton: {
type: Boolean,
default: false
},
sendState: {
type: Object,
default: () => ({
isCounting: false,
countdown: 0,
})
},
prop: {
type: String,
default: 'code' // 和父组件rules中的key一致
},
})
// 本地倒计时状态
const isCounting = ref(false)
const countdown = ref(0)
// 监听外部 sendState 变化
watch(
() => props.sendState,
(newVal) => {
console.log('监听 倒数 变化');
isCounting.value = newVal.isCounting
countdown.value = newVal.countdown
},
{ deep: true, immediate: true }
)
const { showSendButton } = toRefs(props)
const emit = defineEmits(['update:modelValue', 'change', 'finish', 'sendCode'])
// 使用 el-input-otp 的值(字符串形式)
const captchaValue = ref('')
// 监听外部 modelValue 变化
watch(
() => props.modelValue,
(newVal) => {
if (newVal !== captchaValue.value) {
captchaValue.value = newVal || '';
}
},
{ immediate: true }
)
// 值变化时同步到父组件
const handleChange = (val: string) => {
emit('update:modelValue', val);
emit('change', val);
}
// 输入完成时触发
const handleFinish = (val: string) => {
emit('update:modelValue', val);
emit('finish', val);
}
const clear = () => {
captchaValue.value = '';
emit('update:modelValue', '');
}
defineExpose({ clear })
// 发送验证码
const sendCode = () => {
emit('sendCode');
}
</script>
<style lang="scss" scoped>
.captcha-container {
:deep(.el-form-item__content) {
flex-wrap: nowrap;
gap: 8px;
}
:deep(.el-input-otp) {
--el-input-otp-font-size: 18px;
--el-input-otp-width: 40px;
--el-input-otp-height: 40px;
}
}
.form-btn {
height: 40px;
}
</style>