add Captcha components

This commit is contained in:
RockYang 2024-08-13 10:01:07 +08:00
parent c4a68076d6
commit 7fe50788a5
3 changed files with 158 additions and 126 deletions

View File

@ -0,0 +1,2 @@
ALTER TABLE `chatgpt_users` ADD `mobile` CHAR(11) NULL COMMENT '手机号' AFTER `username`;
ALTER TABLE `chatgpt_users` ADD `email` VARCHAR(50) NULL COMMENT '邮箱地址' AFTER `mobile`;

View File

@ -0,0 +1,144 @@
<template>
<el-container class="captcha-box">
<el-dialog
v-model="show"
:close-on-click-modal="true"
:show-close="false"
style="width: 360px;"
>
<slide-captcha
v-if="isMobile()"
:bg-img="bgImg"
:bk-img="bkImg"
:result="result"
@refresh="getSlideCaptcha"
@confirm="handleSlideConfirm"
@hide="show = false"/>
<captcha-plus
v-else
:max-dot="maxDot"
:image-base64="imageBase64"
:thumb-base64="thumbBase64"
width="300"
@close="show = false"
@refresh="handleRequestCaptCode"
@confirm="handleConfirm"
/>
</el-dialog>
</el-container>
</template>
<script setup>
import {ref} from "vue";
import lodash from 'lodash'
import {validateEmail, validateMobile} from "@/utils/validate";
import {httpGet, httpPost} from "@/utils/http";
import CaptchaPlus from "@/components/CaptchaPlus.vue";
import SlideCaptcha from "@/components/SlideCaptcha.vue";
import {isMobile} from "@/utils/libs";
import {showMessageError, showMessageOK} from "@/utils/dialog";
const show = ref(false)
const maxDot = ref(5)
const imageBase64 = ref('')
const thumbBase64 = ref('')
const captKey = ref('')
const dots = ref(null)
const emits = defineEmits(['success']);
const handleRequestCaptCode = () => {
httpGet('/api/captcha/get').then(res => {
const data = res.data
imageBase64.value = data.image
thumbBase64.value = data.thumb
captKey.value = data.key
}).catch(e => {
showMessageError('获取人机验证数据失败:' + e.message)
})
}
const handleConfirm = (dts) => {
if (lodash.size(dts) <= 0) {
return showMessageError('请进行人机验证再操作')
}
let dotArr = []
lodash.forEach(dts, (dot) => {
dotArr.push(dot.x, dot.y)
})
dots.value = dotArr.join(',')
httpPost('/api/captcha/check', {
dots: dots.value,
key: captKey.value
}).then(() => {
// ElMessage.success('')
show.value = false
emits('success', {key:captKey.value, dots:dots.value})
}).catch(() => {
showMessageError('人机验证失败')
handleRequestCaptCode()
})
}
const loadCaptcha = () => {
show.value = true
//
if (isMobile()) {
getSlideCaptcha()
} else {
handleRequestCaptCode()
}
}
//
const bgImg = ref('')
const bkImg = ref('')
const result = ref(0)
const getSlideCaptcha = () => {
result.value = 0
httpGet("/api/captcha/slide/get").then(res => {
bkImg.value = res.data.bkImg
bgImg.value = res.data.bgImg
captKey.value = res.data.key
}).catch(e => {
showMessageError('获取人机验证数据失败:' + e.message)
})
}
const handleSlideConfirm = (x) => {
httpPost("/api/captcha/slide/check", {
key: captKey.value,
x: x
}).then(() => {
result.value = 1
show.value = false
emits('success',{key:captKey.value, x:x})
}).catch(() => {
result.value = 2
})
}
// 便
defineExpose({
loadCaptcha
});
</script>
<style lang="stylus">
.captcha-box {
.el-dialog {
.el-dialog__header {
padding: 0;
}
.el-dialog__body {
padding 0
}
}
}
</style>

View File

@ -1,48 +1,20 @@
<template>
<el-container class="captcha-box">
<el-button type="primary" class="send-btn" :size="props.size" :disabled="!canSend" @click="loadCaptcha" plain>
<el-container class="send-verify-code">
<el-button type="primary" class="send-btn" :size="props.size" :disabled="!canSend" @click="showCaptcha" plain>
{{ btnText }}
</el-button>
<el-dialog
v-model="showCaptcha"
:close-on-click-modal="true"
:show-close="false"
style="width: 360px;"
>
<slide-captcha
v-if="isMobile()"
:bg-img="bgImg"
:bk-img="bkImg"
:result="result"
@refresh="getSlideCaptcha"
@confirm="handleSlideConfirm"
@hide="showCaptcha = false"/>
<captcha-plus
v-else
:max-dot="maxDot"
:image-base64="imageBase64"
:thumb-base64="thumbBase64"
width="300"
@close="showCaptcha = false"
@refresh="handleRequestCaptCode"
@confirm="handleConfirm"
/>
</el-dialog>
<captcha @success="sendMsg" ref="captchaRef"/>
</el-container>
</template>
<script setup>
//
import {ref} from "vue";
import lodash from 'lodash'
import {validateEmail, validateMobile} from "@/utils/validate";
import {httpGet, httpPost} from "@/utils/http";
import CaptchaPlus from "@/components/CaptchaPlus.vue";
import SlideCaptcha from "@/components/SlideCaptcha.vue";
import {isMobile} from "@/utils/libs";
import {httpPost} from "@/utils/http";
import {showMessageError, showMessageOK} from "@/utils/dialog";
import Captcha from "@/components/Captcha.vue";
// eslint-disable-next-line no-undef
const props = defineProps({
@ -51,69 +23,22 @@ const props = defineProps({
});
const btnText = ref('发送验证码')
const canSend = ref(true)
const showCaptcha = ref(false)
const maxDot = ref(5)
const imageBase64 = ref('')
const thumbBase64 = ref('')
const captKey = ref('')
const dots = ref(null)
const captchaRef = ref(null)
const handleRequestCaptCode = () => {
httpGet('/api/captcha/get').then(res => {
const data = res.data
imageBase64.value = data.image
thumbBase64.value = data.thumb
captKey.value = data.key
}).catch(e => {
showMessageError('获取人机验证数据失败:' + e.message)
})
}
const handleConfirm = (dots) => {
if (lodash.size(dots) <= 0) {
return showMessageError('请进行人机验证再操作')
}
let dotArr = []
lodash.forEach(dots, (dot) => {
dotArr.push(dot.x, dot.y)
})
dots.value = dotArr.join(',')
httpPost('/api/captcha/check', {
dots: dots.value,
key: captKey.value
}).then(() => {
// ElMessage.success('')
showCaptcha.value = false
sendMsg()
}).catch(() => {
showMessageError('人机验证失败')
handleRequestCaptCode()
})
}
const loadCaptcha = () => {
const showCaptcha = () => {
if (!validateMobile(props.receiver) && !validateEmail(props.receiver)) {
return showMessageError("请输入合法的手机号/邮箱地址")
}
showCaptcha.value = true
//
if (isMobile()) {
getSlideCaptcha()
} else {
handleRequestCaptCode()
}
captchaRef.value.loadCaptcha()
}
const sendMsg = () => {
const sendMsg = (data) => {
if (!canSend.value) {
return
}
canSend.value = false
httpPost('/api/sms/code', {receiver: props.receiver, key: captKey.value, dots: dots.value}).then(() => {
httpPost('/api/sms/code', {receiver: props.receiver, key: data.key, dots: data.dots, x:data.x}).then(() => {
showMessageOK('验证码发送成功')
let time = 120
btnText.value = time
@ -132,52 +57,13 @@ const sendMsg = () => {
showMessageError('验证码发送失败:' + e.message)
})
}
//
const bgImg = ref('')
const bkImg = ref('')
const result = ref(0)
const getSlideCaptcha = () => {
result.value = 0
httpGet("/api/captcha/slide/get").then(res => {
bkImg.value = res.data.bkImg
bgImg.value = res.data.bgImg
captKey.value = res.data.key
}).catch(e => {
showMessageError('获取人机验证数据失败:' + e.message)
})
}
const handleSlideConfirm = (x) => {
httpPost("/api/captcha/slide/check", {
key: captKey.value,
x: x
}).then(() => {
result.value = 1
showCaptcha.value = false
sendMsg()
}).catch(() => {
result.value = 2
})
}
</script>
<style lang="stylus">
<style lang="stylus" scoped>
.captcha-box {
.send-verify-code {
.send-btn {
width: 100%;
}
.el-dialog {
.el-dialog__header {
padding: 0;
}
.el-dialog__body {
padding 0
}
}
}
</style>