2025-04-09 14:59:26 +08:00

388 lines
12 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div style="position: relative;">
<div v-if="type === '2'" class="verify-img-out" :style="{ height: parseInt(setSize.imgHeight) + vSpace + 'px' }">
<div v-loading="loading" class="verify-img-panel" :style="{ width: setSize.imgWidth, height: setSize.imgHeight }">
<img
:src="backImgBase ? 'data:image/png;base64,' + backImgBase : defaultImg"
alt=""
style="width: 100%; height: 100%; display: block;"
/>
<div v-show="showRefresh" class="verify-refresh" @click="refresh"><i class="iconfont icon-refresh" /></div>
<transition name="tips">
<span v-if="tipWords" class="verify-tips" :class="passFlag ? 'suc-bg' : 'err-bg'">{{ tipWords }}</span>
</transition>
</div>
</div>
<!-- 公共部分 -->
<div
class="verify-bar-area"
:style="{ width: setSize.imgWidth, height: barSize.height, 'line-height': barSize.height }"
>
<span class="verify-msg" v-text="text" />
<div
class="verify-left-bar"
:style="{
width: leftBarWidth !== undefined ? leftBarWidth : barSize.height,
height: barSize.height,
'border-color': leftBarBorderColor,
transaction: transitionWidth,
}"
>
<span class="verify-msg" v-text="finishText" />
<div
class="verify-move-block"
:style="{
width: barSize.height,
height: barSize.height,
'background-color': moveBlockBackgroundColor,
left: moveBlockLeft,
transition: transitionLeft,
}"
@touchstart="start"
@mousedown="start"
>
<i :class="['verify-icon iconfont', iconClass]" :style="{ color: iconColor }" />
<div
v-if="type === '2'"
class="verify-sub-block"
:style="{
width: Math.floor((parseInt(setSize.imgWidth) * 47) / 310) + 'px',
height: setSize.imgHeight,
top: '-' + (parseInt(setSize.imgHeight) + vSpace) + 'px',
'background-size': setSize.imgWidth + ' ' + setSize.imgHeight,
}"
>
<img
:src="'data:image/png;base64,' + blockBackImgBase"
alt=""
style="width: 100%; height: 100%; display: block;"
/>
</div>
</div>
</div>
</div>
</div>
</template>
<script type="text/babel">
/**
* VerifySlide
* @description 滑块
* */
import { aesEncrypt } from './../utils/ase'
import { resetSize } from './../utils/util'
import { knowUserCaptchaApi, knowUserSmsCaptchaApi } from '~/server/userApi'
// "captchaType":"blockPuzzle",
export default {
name: 'VerifySlide',
props: {
captchaType: {
type: String,
},
type: {
type: String,
default: '1',
},
phone: {
type: String,
default: '',
},
// 弹出式pop固定fixed
mode: {
type: String,
default: 'fixed',
},
vSpace: {
type: Number,
default: 5,
},
explain: {
type: String,
default: '向右滑动完成验证',
},
imgSize: {
type: Object,
default() {
return {
width: '310px',
height: '155px',
}
},
},
blockSize: {
type: Object,
default() {
return {
width: '50px',
height: '50px',
}
},
},
barSize: {
type: Object,
default() {
return {
width: '310px',
height: '40px',
}
},
},
defaultImg: {
type: String,
default: '',
},
},
data() {
return {
secretKey: '', // 后端返回的加密秘钥 字段
passFlag: '', // 是否通过的标识
backImgBase: '', // 验证码背景图片
blockBackImgBase: '', // 验证滑块的背景图片
backToken: '', // 后端返回的唯一token值
startMoveTime: '', // 移动开始的时间
endMovetime: '', // 移动结束的时间
tipsBackColor: '', // 提示词的背景颜色
tipWords: '',
text: '',
finishText: '',
setSize: {
imgHeight: 0,
imgWidth: 0,
barHeight: 0,
barWidth: 0,
},
top: 0,
left: 0,
moveBlockLeft: undefined,
leftBarWidth: undefined,
// 移动中样式
moveBlockBackgroundColor: undefined,
leftBarBorderColor: '#ddd',
iconColor: undefined,
iconClass: 'icon-right',
status: false, // 鼠标状态
isEnd: false, // 是够验证完成
showRefresh: true,
transitionLeft: '',
transitionWidth: '',
loading: false //加载效果
}
},
computed: {
barArea() {
return this.$el.querySelector('.verify-bar-area')
},
resetSize() {
return resetSize
},
},
watch: {
// type变化则全面刷新
type: {
immediate: true,
handler() {
this.init()
},
},
},
mounted() {
// 禁止拖拽
this.$el.onselectstart = function () {
return false
}
},
methods: {
init() {
this.text = this.explain
this.getPictrue()
this.$nextTick(() => {
const setSize = this.resetSize(this) // 重新设置宽度高度
this.setSize.imgWidth = setSize.imgWidth
this.setSize.imgHeight = setSize.imgHeight
this.setSize.barHeight = setSize.barHeight
this.setSize.barWidth = setSize.barWidth
this.$parent.$emit('ready', this)
})
var _this = this
window.removeEventListener('touchmove', function (e) {
_this.move(e)
})
window.removeEventListener('mousemove', function (e) {
_this.move(e)
})
// 鼠标松开
window.removeEventListener('touchend', function () {
_this.end()
})
window.removeEventListener('mouseup', function () {
_this.end()
})
window.addEventListener('touchmove', function (e) {
_this.move(e)
})
window.addEventListener('mousemove', function (e) {
_this.move(e)
})
// 鼠标松开
window.addEventListener('touchend', function () {
_this.end()
})
window.addEventListener('mouseup', function () {
_this.end()
})
},
// 鼠标按下
start: function (e) {
e = e || window.event
if (!e.touches) {
// 兼容PC端
var x = e.clientX
} else {
// 兼容移动端
var x = e.touches[0].pageX
}
this.startLeft = Math.floor(x - this.barArea.getBoundingClientRect().left)
this.startMoveTime = +new Date() // 开始滑动的时间
if (this.isEnd == false) {
this.text = ''
this.moveBlockBackgroundColor = '#337ab7'
this.leftBarBorderColor = '#337AB7'
this.iconColor = '#fff'
e.stopPropagation()
this.status = true
}
},
// 鼠标移动
move: function (e) {
e = e || window.event
if (this.status && this.isEnd == false) {
if (!e.touches) {
// 兼容PC端
var x = e.clientX
} else {
// 兼容移动端
var x = e.touches[0].pageX
}
var bar_area_left = this.barArea.getBoundingClientRect().left
var move_block_left = x - bar_area_left // 小方块相对于父元素的left值
if (move_block_left >= this.barArea.offsetWidth - parseInt(parseInt(this.blockSize.width) / 2) - 2) {
move_block_left = this.barArea.offsetWidth - parseInt(parseInt(this.blockSize.width) / 2) - 2
}
if (move_block_left <= 0) {
move_block_left = parseInt(parseInt(this.blockSize.width) / 2)
}
// 拖动后小方块的left值
this.moveBlockLeft = move_block_left - this.startLeft + 'px'
this.leftBarWidth = move_block_left - this.startLeft + 'px'
}
},
// 鼠标松开
end() {
this.endMovetime = +new Date()
var _this = this
// 判断是否重合
if (this.status && this.isEnd == false) {
var moveLeftDistance = parseInt((this.moveBlockLeft || '').replace('px', ''))
moveLeftDistance = (moveLeftDistance * 310) / parseInt(this.setSize.imgWidth)
const params = {
captchaType: this.captchaType,
pointJson: this.secretKey
? aesEncrypt(JSON.stringify({ x: moveLeftDistance, y: 5.0 }), this.secretKey)
: JSON.stringify({ x: moveLeftDistance, y: 5.0 }),
token: this.backToken,
}
knowUserSmsCaptchaApi(params).then((res) => {
if (res.repCode == '0000') {
this.moveBlockBackgroundColor = '#5cb85c';
this.leftBarBorderColor = '#5cb85c';
this.iconColor = '#fff';
this.iconClass = 'icon-check';
this.showRefresh = false;
this.isEnd = true;
if (this.mode == 'pop') {
setTimeout(() => {
this.$parent.clickShow = false;
this.refresh();
}, 1500);
}
this.passFlag = true;
this.tipWords = `${((this.endMovetime - this.startMoveTime) / 1000).toFixed(2)}s验证成功`;
var captchaVerification = this.secretKey
? aesEncrypt(this.backToken + '---' + JSON.stringify({ x: moveLeftDistance, y: 5.0 }), this.secretKey)
: this.backToken + '---' + JSON.stringify({ x: moveLeftDistance, y: 5.0 });
setTimeout(() => {
this.tipWords = '';
this.$emit('success', { captchaVerification });
}, 1000);
} else {
this.moveBlockBackgroundColor = '#d9534f';
this.leftBarBorderColor = '#d9534f';
this.iconColor = '#fff';
this.iconClass = 'icon-close';
this.passFlag = false;
setTimeout(function () {
_this.refresh();
}, 1000);
this.$emit('error', this);
this.tipWords = '验证失败';
setTimeout(() => {
this.tipWords = '';
}, 1000);
}
})
}
},
refresh: function () {
this.showRefresh = true
this.finishText = ''
this.transitionLeft = 'left .3s'
this.moveBlockLeft = undefined
this.leftBarWidth = undefined
this.transitionWidth = 'width .3s'
this.leftBarBorderColor = '#ddd'
this.moveBlockBackgroundColor = '#fff'
this.iconColor = '#000'
this.iconClass = 'icon-right'
this.isEnd = false
this.getPictrue()
setTimeout(() => {
this.status = false
this.transitionWidth = ''
this.transitionLeft = ''
this.text = this.explain
}, 300)
},
// 请求背景图片和验证图片
async getPictrue() {
let params = {}
if(process.client){
params = {
captchaType: this.captchaType,
clientUid: localStorage.getItem('slider'),
ts: Date.now(), // 现在的时间戳
}
}
this.loading = true
const res = await knowUserCaptchaApi(params)
if (res.repCode == '0000') {
this.backImgBase = res.repData.originalImageBase64;
this.blockBackImgBase = res.repData.jigsawImageBase64
this.backToken = res.repData.token;
this.secretKey = res.repData.secretKey;
} else {
this.text = res.repMsg;
}
this.loading = false
},
},
}
</script>