Pre Merge pull request !809 from 山野羡民/feat-captcha

pull/809/MERGE
山野羡民 2025-08-07 21:19:08 +00:00 committed by Gitee
commit f1a096eec1
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
7 changed files with 183 additions and 11 deletions

View File

@ -36,14 +36,15 @@
* Verify 验证码组件
* @description 分发验证码使用
* */
import { VerifyPoints, VerifySlide } from './Verify'
import { VerifyPoints, VerifySlide, VerifyInput } from './Verify'
import { computed, ref, toRefs, watchEffect } from 'vue'
export default {
name: 'Vue3Verify',
components: {
VerifySlide,
VerifyPoints
VerifyPoints,
VerifyInput
},
props: {
captchaType: {
@ -118,14 +119,21 @@ export default {
}
watchEffect(() => {
switch (captchaType.value) {
case 'blockPuzzle':
case 'blockPuzzle': //
verifyType.value = '2'
componentType.value = 'VerifySlide'
break
case 'clickWord':
case 'clickWord': //
verifyType.value = ''
componentType.value = 'VerifyPoints'
break
case 'pictureWord': //
verifyType.value = ''
componentType.value = 'VerifyInput'
break
default:
// TODO rotatePuzzle
break
}
})

View File

@ -0,0 +1,162 @@
<template>
<div style="position: relative">
<div class="verify-img-out">
<div
:style="{
width: setSize.imgWidth,
height: setSize.imgHeight,
'background-size': setSize.imgWidth + ' ' + setSize.imgHeight,
'margin-bottom': vSpace + 'px'
}"
class="verify-img-panel"
>
<div v-show="showRefresh" class="verify-refresh" style="z-index: 3" @click="refresh">
<i class="iconfont icon-refresh"></i>
</div>
<img
ref="canvas"
:src="'data:image/png;base64,' + inputBackImgBase"
alt=""
style="display: block; width: 100%; height: 100%"
/>
</div>
</div>
<div
:style="{
width: setSize.imgWidth,
border: 'none',
'line-height': barSize.height
}"
class="verify-bar-area flex"
>
<el-text>{{ t('login.code') }}</el-text>
<el-input v-model="userCode" :placeholder="t('login.codePlaceholder')" class="flex-1 ml-10px"/>
<el-button type="primary" @click="doCheck" class="ml-10px">确定</el-button>
</div>
</div>
</template>
<script setup lang="ts">
/**
* VerifyInput
* @description 输入
* */
import {resetSize} from '../utils/util'
import {getCode, reqCheck} from '@/api/login'
import {getCurrentInstance, nextTick, onMounted, reactive, ref, toRefs} from 'vue'
const props = defineProps({
//-pop-fixed
mode: {
type: String,
default: 'fixed'
},
captchaType: {
type: String
},
//px
vSpace: {
type: Number,
default: 5
},
imgSize: {
type: Object,
default() {
return {
width: '310px',
height: '155px'
}
}
},
barSize: {
type: Object,
default() {
return {
width: '310px',
height: '40px'
}
}
}
})
const { t } = useI18n()
const {mode, captchaType} = toRefs(props)
const {proxy} = getCurrentInstance()
let inputBackImgBase = ref('') //
let backToken = ref('') //token
let setSize = reactive({
imgHeight: 0,
imgWidth: 0,
barHeight: 0,
barWidth: 0
})
let userCode = ref('')
let showRefresh = ref(true)
const init = () => {
//
getPicture()
nextTick(() => {
let {imgHeight, imgWidth, barHeight, barWidth} = resetSize(proxy)
setSize.imgHeight = imgHeight
setSize.imgWidth = imgWidth
setSize.barHeight = barHeight
setSize.barWidth = barWidth
proxy.$parent.$emit('ready', proxy)
})
}
onMounted(() => {
//
init()
proxy.$el.onselectstart = function () {
return false
}
})
const doCheck = () => {
if (!userCode.value) {
ElMessage.error(t('login.codePlaceholder'))
return
}
//
const captchaVerification = backToken.value + '---' + userCode.value
let data = {
captchaType: captchaType.value,
pointJson: userCode.value,
token: backToken.value
}
reqCheck(data).then((res) => {
if (res.repCode === '0000') {
ElMessage.success(t('captcha.success'))
if (mode.value === 'pop') {
setTimeout(() => {
proxy.$parent.clickShow = false
refresh()
}, 1500)
}
proxy.$parent.$emit('success', {captchaVerification})
} else {
ElMessage.warning(res.repMsg)
proxy.$parent.$emit('error', proxy)
setTimeout(() => {
refresh()
}, 700)
}
})
}
const refresh = async function () {
await getPicture()
showRefresh.value = true
}
//
const getPicture = async () => {
let data = {
captchaType: captchaType.value
}
const res = await getCode(data)
if (res.repCode === '0000') {
inputBackImgBase.value = res.repData.originalImageBase64
backToken.value = res.repData.token
secretKey.value = res.repData.secretKey
}
}
</script>

View File

@ -1,4 +1,5 @@
import VerifySlide from './VerifySlide.vue'
import VerifyPoints from './VerifyPoints.vue'
import VerifyInput from './VerifyInput.vue'
export { VerifySlide, VerifyPoints }
export {VerifySlide, VerifyPoints, VerifyInput}

View File

@ -185,7 +185,7 @@ const { push } = useRouter()
const permissionStore = usePermissionStore()
const loginLoading = ref(false)
const verify = ref()
const captchaType = ref('blockPuzzle') // blockPuzzle clickWord
const captchaType = ref('blockPuzzle') // blockPuzzle clickWord pictureWord
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN)

View File

@ -38,6 +38,7 @@
</el-form-item>
</el-col>
<Verify
v-if="getShow && resetPasswordData.captchaEnable === 'true'"
ref="verify"
:captchaType="captchaType"
:imgSize="{ width: '400px', height: '200px' }"
@ -143,7 +144,7 @@ const iconCircleCheck = useIcon({ icon: 'ep:circle-check' })
const { validForm } = useFormValid(formSmsResetPassword)
const { handleBackLogin, getLoginState, setLoginState } = useLoginState()
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.RESET_PASSWORD)
const captchaType = ref('blockPuzzle') // blockPuzzle clickWord
const captchaType = ref('blockPuzzle') // blockPuzzle clickWord pictureWord
const validatePass2 = (_rule, value, callback) => {
if (value === '') {

View File

@ -82,7 +82,7 @@
</el-form-item>
</el-col>
<Verify
v-if="loginData.captchaEnable === 'true'"
v-if="getShow && loginData.captchaEnable === 'true'"
ref="verify"
:captchaType="captchaType"
:imgSize="{ width: '400px', height: '200px' }"
@ -177,7 +177,7 @@ const permissionStore = usePermissionStore()
const redirect = ref<string>('')
const loginLoading = ref(false)
const verify = ref()
const captchaType = ref('blockPuzzle') // blockPuzzle clickWord
const captchaType = ref('blockPuzzle') // blockPuzzle clickWord pictureWord
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN)

View File

@ -85,7 +85,7 @@
</el-form-item>
</el-col>
<Verify
v-if="registerData.captchaEnable === 'true'"
v-if="getShow && registerData.captchaEnable === 'true'"
ref="verify"
:captchaType="captchaType"
:imgSize="{ width: '400px', height: '200px' }"
@ -119,7 +119,7 @@ const permissionStore = usePermissionStore()
const redirect = ref<string>('')
const loginLoading = ref(false)
const verify = ref()
const captchaType = ref('blockPuzzle') // blockPuzzle clickWord
const captchaType = ref('blockPuzzle') // blockPuzzle clickWord pictureWord
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.REGISTER)