Pre Merge pull request !796 from DanielTsui/master-pictureWordCaptcha
commit
ae86b06cf8
|
|
@ -36,14 +36,15 @@
|
||||||
* Verify 验证码组件
|
* Verify 验证码组件
|
||||||
* @description 分发验证码使用
|
* @description 分发验证码使用
|
||||||
* */
|
* */
|
||||||
import { VerifyPoints, VerifySlide } from './Verify'
|
import {VerifyPictureWord, VerifyPoints, VerifySlide} from './Verify'
|
||||||
import { computed, ref, toRefs, watchEffect } from 'vue'
|
import { computed, ref, toRefs, watchEffect } from 'vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Vue3Verify',
|
name: 'Vue3Verify',
|
||||||
components: {
|
components: {
|
||||||
VerifySlide,
|
VerifySlide,
|
||||||
VerifyPoints
|
VerifyPoints,
|
||||||
|
VerifyPictureWord
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
captchaType: {
|
captchaType: {
|
||||||
|
|
@ -118,6 +119,10 @@ export default {
|
||||||
}
|
}
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
switch (captchaType.value) {
|
switch (captchaType.value) {
|
||||||
|
case 'pictureWord':
|
||||||
|
verifyType.value = '3'
|
||||||
|
componentType.value = 'VerifyPictureWord'
|
||||||
|
break
|
||||||
case 'blockPuzzle':
|
case 'blockPuzzle':
|
||||||
verifyType.value = '2'
|
verifyType.value = '2'
|
||||||
componentType.value = 'VerifySlide'
|
componentType.value = 'VerifySlide'
|
||||||
|
|
@ -438,4 +443,4 @@ export default {
|
||||||
content: ' ';
|
content: ' ';
|
||||||
inset: 0;
|
inset: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -0,0 +1,194 @@
|
||||||
|
<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
|
||||||
|
@click="refresh"
|
||||||
|
ref="canvas"
|
||||||
|
:src="'data:image/png;base64,' + verificationCodeImg"
|
||||||
|
alt=""
|
||||||
|
style="display: block; width: 100%; height: 100%"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
width: setSize.imgWidth,
|
||||||
|
color: barAreaColor,
|
||||||
|
'border-color': barAreaBorderColor,
|
||||||
|
// 'line-height': barSize.height
|
||||||
|
}"
|
||||||
|
class="verify-bar-area"
|
||||||
|
>
|
||||||
|
<div class="verify-msg">{{ text }}</div>
|
||||||
|
<div :style="{
|
||||||
|
'line-height': barSize.height
|
||||||
|
}">
|
||||||
|
<input class="verify-input" type="text" v-model="userCode" />
|
||||||
|
</div>
|
||||||
|
<button type="button" class="verify-btn" @click="submit" :disabled="checking">{{ t('captcha.verify') }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup type="text/babel">
|
||||||
|
/**
|
||||||
|
* VerifyPictureWord
|
||||||
|
* @description 输入文字
|
||||||
|
* */
|
||||||
|
import { resetSize } from '../utils/util';
|
||||||
|
import { aesEncrypt } from '../utils/ase';
|
||||||
|
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
|
||||||
|
},
|
||||||
|
//间隔
|
||||||
|
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 secretKey = ref(''), //后端返回的ase加密秘钥
|
||||||
|
|
||||||
|
userCode = ref(''), // 用户输入的验证码 暂存至pointJson,无需加密
|
||||||
|
|
||||||
|
verificationCodeImg = ref(''), //后端获取到的背景图片
|
||||||
|
backToken = ref(''), //后端返回的token值
|
||||||
|
setSize = reactive({
|
||||||
|
imgHeight: 0,
|
||||||
|
imgWidth: 0,
|
||||||
|
barHeight: 0,
|
||||||
|
barWidth: 0
|
||||||
|
}),
|
||||||
|
text = ref(''),
|
||||||
|
barAreaColor = ref('#000'),
|
||||||
|
barAreaBorderColor = ref('#ddd'),
|
||||||
|
showRefresh = ref(true),
|
||||||
|
// bindingClick = ref(true)
|
||||||
|
checking = ref(false);
|
||||||
|
|
||||||
|
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 canvas = ref(null);
|
||||||
|
|
||||||
|
const submit = () => {
|
||||||
|
checking.value = true;
|
||||||
|
//发送后端请求
|
||||||
|
var captchaVerification = secretKey.value
|
||||||
|
? aesEncrypt(backToken.value + '---' + userCode.value, secretKey.value)
|
||||||
|
: backToken.value + '---' + userCode.value;
|
||||||
|
let data = {
|
||||||
|
captchaType: captchaType.value,
|
||||||
|
pointJson: userCode.value,
|
||||||
|
token: backToken.value
|
||||||
|
};
|
||||||
|
reqCheck(data).then((res) => {
|
||||||
|
if (res.repCode == '0000') {
|
||||||
|
barAreaColor.value = '#4cae4c';
|
||||||
|
barAreaBorderColor.value = '#5cb85c';
|
||||||
|
text.value = t('captcha.success');
|
||||||
|
// bindingClick.value = false
|
||||||
|
if (mode.value == 'pop') {
|
||||||
|
setTimeout(() => {
|
||||||
|
proxy.$parent.clickShow = false;
|
||||||
|
refresh();
|
||||||
|
}, 1500);
|
||||||
|
}
|
||||||
|
proxy.$parent.$emit('success', { captchaVerification });
|
||||||
|
} else {
|
||||||
|
proxy.$parent.$emit('error', proxy);
|
||||||
|
barAreaColor.value = '#d9534f';
|
||||||
|
barAreaBorderColor.value = '#d9534f';
|
||||||
|
text.value = t('captcha.fail');
|
||||||
|
setTimeout(() => {
|
||||||
|
refresh();
|
||||||
|
}, 700);
|
||||||
|
}
|
||||||
|
checking.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const refresh = async function() {
|
||||||
|
barAreaColor.value = '#000';
|
||||||
|
barAreaBorderColor.value = '#ddd';
|
||||||
|
checking.value = false;
|
||||||
|
|
||||||
|
userCode.value = '';
|
||||||
|
|
||||||
|
await getPicture();
|
||||||
|
showRefresh.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 请求背景图片和验证图片
|
||||||
|
const getPicture = async () => {
|
||||||
|
let data = {
|
||||||
|
captchaType: captchaType.value
|
||||||
|
};
|
||||||
|
const res = await getCode(data);
|
||||||
|
if (res.repCode == '0000') {
|
||||||
|
verificationCodeImg.value = res.repData.originalImageBase64;
|
||||||
|
backToken.value = res.repData.token;
|
||||||
|
secretKey.value = res.repData.secretKey;
|
||||||
|
text.value = t('captcha.code');
|
||||||
|
} else {
|
||||||
|
text.value = res.repMsg;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import VerifySlide from './VerifySlide.vue'
|
import VerifySlide from './VerifySlide.vue'
|
||||||
import VerifyPoints from './VerifyPoints.vue'
|
import VerifyPoints from './VerifyPoints.vue'
|
||||||
|
import VerifyPictureWord from './VerifyPictureWord.vue'
|
||||||
|
|
||||||
export { VerifySlide, VerifyPoints }
|
export { VerifySlide, VerifyPoints, VerifyPictureWord }
|
||||||
|
|
@ -146,9 +146,11 @@ export default {
|
||||||
invalidTenantName:"Invalid Tenant Name"
|
invalidTenantName:"Invalid Tenant Name"
|
||||||
},
|
},
|
||||||
captcha: {
|
captcha: {
|
||||||
|
verify: 'Verify',
|
||||||
verification: 'Please complete security verification',
|
verification: 'Please complete security verification',
|
||||||
slide: 'Swipe right to complete verification',
|
slide: 'Swipe right to complete verification',
|
||||||
point: 'Please click',
|
point: 'Please click',
|
||||||
|
code: 'Please enter the verification code',
|
||||||
success: 'Verification succeeded',
|
success: 'Verification succeeded',
|
||||||
fail: 'verification failed'
|
fail: 'verification failed'
|
||||||
},
|
},
|
||||||
|
|
@ -457,4 +459,4 @@ export default {
|
||||||
btn_zoom_out: 'Zoom out',
|
btn_zoom_out: 'Zoom out',
|
||||||
preview: 'Preivew'
|
preview: 'Preivew'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -147,9 +147,11 @@ export default {
|
||||||
invalidTenantName: '无效的租户名称'
|
invalidTenantName: '无效的租户名称'
|
||||||
},
|
},
|
||||||
captcha: {
|
captcha: {
|
||||||
|
verify: '验证',
|
||||||
verification: '请完成安全验证',
|
verification: '请完成安全验证',
|
||||||
slide: '向右滑动完成验证',
|
slide: '向右滑动完成验证',
|
||||||
point: '请依次点击',
|
point: '请依次点击',
|
||||||
|
code: '请输入验证码',
|
||||||
success: '验证成功',
|
success: '验证成功',
|
||||||
fail: '验证失败'
|
fail: '验证失败'
|
||||||
},
|
},
|
||||||
|
|
@ -453,4 +455,4 @@ export default {
|
||||||
preview: '预览'
|
preview: '预览'
|
||||||
},
|
},
|
||||||
'OAuth 2.0': 'OAuth 2.0' // 避免菜单名是 OAuth 2.0 时,一直 warn 报错
|
'OAuth 2.0': 'OAuth 2.0' // 避免菜单名是 OAuth 2.0 时,一直 warn 报错
|
||||||
}
|
}
|
||||||
|
|
@ -177,7 +177,8 @@ const permissionStore = usePermissionStore()
|
||||||
const redirect = ref<string>('')
|
const redirect = ref<string>('')
|
||||||
const loginLoading = ref(false)
|
const loginLoading = ref(false)
|
||||||
const verify = ref()
|
const verify = ref()
|
||||||
const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字
|
const captchaType = ref('pictureWord') // blockPuzzle 滑块 clickWord 点击文字 pictureWord 文字验证码
|
||||||
|
// const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字 pictureWord 文字验证码
|
||||||
|
|
||||||
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN)
|
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN)
|
||||||
|
|
||||||
|
|
@ -360,4 +361,4 @@ onMounted(() => {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
Loading…
Reference in New Issue