123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- <template>
- <div class="w100">
- <el-input text maxlength="4" placeholder="请输入验证码" autocomplete="off" v-bind="$attrs">
- <template #prefix>
- <el-icon class="el-input__icon"><ele-Message /></el-icon>
- </template>
- <template #suffix>
- <el-link type="primary" :underline="false" v-show="state.status !== 'countdown'" :disabled="state.status === 'countdown'" @click="onClick">{{
- state.status === 'ready' ? state.startText : state.endText
- }}</el-link>
- <el-countdown
- v-show="state.status === 'countdown'"
- :format="state.changeText"
- :value="state.countdown"
- value-style="font-size:var(--el-font-size-base);color:var(--el-color-primary)"
- @change="onChange"
- />
- </template>
- </el-input>
- <el-dialog ref="dialogRef" v-model="state.showDialog" class="my-captcha" title="请完成安全验证" draggable append-to-body width="380px">
- <MySlideCaptcha
- ref="slideCaptchaRef"
- :fail-tip="state.failTip"
- :success-tip="state.successTip"
- width="100%"
- height="auto"
- @refresh="onRefresh"
- @finish="onFinish"
- />
- </el-dialog>
- </div>
- </template>
- <script lang="ts" setup name="my-input-code">
- import { ref, reactive, defineAsyncComponent } from 'vue'
- import { CaptchaApi } from '/@/api/admin/Captcha'
- import { isMobile } from '/@/utils/test'
- import { ElMessage } from 'element-plus'
- const MySlideCaptcha = defineAsyncComponent(() => import('/@/components/my-slide-captcha/index.vue'))
- const props = defineProps({
- seconds: {
- type: Number,
- default: 60,
- },
- startText: {
- type: String,
- default: '获取验证码',
- },
- changeText: {
- type: String,
- default: 's秒重新获取',
- },
- endText: {
- type: String,
- default: '重新获取',
- },
- mobile: {
- type: String,
- default: '',
- },
- validate: {
- type: Function,
- default: null,
- },
- })
- const slideCaptchaRef = ref()
- const dialogRef = ref()
- const state = reactive({
- status: 'ready',
- startText: props.startText,
- changeText: props.changeText,
- endText: props.endText,
- countdown: Date.now(),
- showDialog: false,
- requestId: '',
- failTip: '',
- successTip: '',
- })
- const startCountdown = () => {
- state.status = 'countdown'
- state.countdown = Date.now() + (props.seconds + 1) * 1000
- }
- const onClick = () => {
- if (state.status !== 'countdown') {
- if (props.validate) {
- props.validate(onGetCode)
- } else {
- onGetCode()
- }
- }
- }
- const onChange = (value: number) => {
- if (value < 1000) state.status = 'finish'
- }
- //刷新滑块验证码
- const onRefresh = async () => {
- slideCaptchaRef.value.startRequestGenerate()
- const res = await new CaptchaApi().generate().catch(() => {
- slideCaptchaRef.value.endRequestGenerate(null, null)
- })
- if (res?.success && res.data) {
- state.requestId = res.data.id || ''
- slideCaptchaRef.value.endRequestGenerate(res.data.backgroundImage, res.data.sliderImage)
- }
- }
- //验证滑块验证码
- const onFinish = async (data: any) => {
- slideCaptchaRef.value.startRequestVerify()
- const res = await new CaptchaApi().check(data, { id: state.requestId }).catch(() => {
- state.failTip = '服务异常,请稍后重试'
- slideCaptchaRef.value.endRequestVerify(false)
- })
- if (res?.success && res.data) {
- let success = res.data.result === 0
- state.failTip = res.data.result == 1 ? '验证未通过,拖动滑块将悬浮图像正确合并' : '验证超时, 请重新操作'
- state.successTip = '验证通过'
- slideCaptchaRef.value.endRequestVerify(success)
- if (success) {
- state.showDialog = false
- startCountdown()
- //发送短信验证码
- } else {
- setTimeout(() => {
- onRefresh()
- }, 1000)
- }
- }
- }
- //获得验证码
- const onGetCode = () => {
- //验证手机号
- if (!isMobile(props.mobile)) {
- ElMessage.warning({ message: '请输入正确的手机号码', grouping: true })
- return
- }
- state.showDialog = true
- //刷新验证码
- slideCaptchaRef.value?.handleRefresh()
- }
- </script>
- <style scoped lang="scss">
- :deep(.el-statistic__content) {
- font-size: var(--el-font-size-base);
- }
- </style>
- <style lang="scss">
- .my-captcha .el-dialog__body {
- padding-top: 10px;
- }
- .my-captcha .captcha__bar {
- border-color: var(--el-border-color) !important;
- }
- </style>
|