123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376 |
- <template>
- <div style="position: relative">
- <div
- v-if="type === '2'"
- class="verify-img-out"
- :style="{ height: parseInt(setSize.imgHeight) + vSpace + 'px' }"
- >
- <div class="verify-img-panel" :style="{ width: setSize.imgWidth, height: setSize.imgHeight }">
- <img
- :src="'data:image/png;base64,' + backImgBase"
- alt=""
- style="width: 100%; height: 100%; display: block"
- />
- <div class="verify-refresh" @click="refresh" v-show="showRefresh">
- <i class="iconfont icon-refresh"></i>
- </div>
- <transition name="tips">
- <span class="verify-tips" v-if="tipWords" :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"></span>
- <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"></span>
- <div
- class="verify-move-block"
- @touchstart="start"
- @mousedown="start"
- :style="{
- width: barSize.height,
- height: barSize.height,
- 'background-color': moveBlockBackgroundColor,
- left: moveBlockLeft,
- transition: transitionLeft
- }"
- >
- <i :class="['verify-icon iconfont', iconClass]" :style="{ color: iconColor }"></i>
- <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; -webkit-user-drag: none"
- />
- </div>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script type="text/babel" setup>
- /**
- * VerifySlide
- * @description 滑块
- * */
- import { aesEncrypt } from './../utils/ase'
- import { resetSize } from './../utils/util'
- import { getCode, reqCheck } from '@/api/login'
- const props = defineProps({
- captchaType: {
- type: String
- },
- type: {
- type: String,
- default: '1'
- },
- //弹出式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: '30px'
- }
- }
- }
- })
- const { t } = useI18n()
- const { mode, captchaType, type, blockSize, explain } = toRefs(props)
- const { proxy } = getCurrentInstance()
- let secretKey = ref(''), //后端返回的ase加密秘钥
- passFlag = ref(''), //是否通过的标识
- backImgBase = ref(''), //验证码背景图片
- blockBackImgBase = ref(''), //验证滑块的背景图片
- backToken = ref(''), //后端返回的唯一token值
- startMoveTime = ref(''), //移动开始的时间
- endMovetime = ref(''), //移动结束的时间
- tipWords = ref(''),
- text = ref(''),
- finishText = ref(''),
- setSize = reactive({
- imgHeight: 0,
- imgWidth: 0,
- barHeight: 0,
- barWidth: 0
- }),
- moveBlockLeft = ref(undefined),
- leftBarWidth = ref(undefined),
- // 移动中样式
- moveBlockBackgroundColor = ref(undefined),
- leftBarBorderColor = ref('#ddd'),
- iconColor = ref(undefined),
- iconClass = ref('icon-right'),
- status = ref(false), //鼠标状态
- isEnd = ref(false), //是够验证完成
- showRefresh = ref(true),
- transitionLeft = ref(''),
- transitionWidth = ref(''),
- startLeft = ref(0)
- const barArea = computed(() => {
- return proxy.$el.querySelector('.verify-bar-area')
- })
- const init = () => {
- if (explain.value === '') {
- text.value = t('captcha.slide')
- } else {
- text.value = explain.value
- }
- getPictrue()
- 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)
- })
- window.removeEventListener('touchmove', function (e) {
- move(e)
- })
- window.removeEventListener('mousemove', function (e) {
- move(e)
- })
- //鼠标松开
- window.removeEventListener('touchend', function () {
- end()
- })
- window.removeEventListener('mouseup', function () {
- end()
- })
- window.addEventListener('touchmove', function (e) {
- move(e)
- })
- window.addEventListener('mousemove', function (e) {
- move(e)
- })
- //鼠标松开
- window.addEventListener('touchend', function () {
- end()
- })
- window.addEventListener('mouseup', function () {
- end()
- })
- }
- watch(type, () => {
- init()
- })
- onMounted(() => {
- // 禁止拖拽
- init()
- proxy.$el.onselectstart = function () {
- return false
- }
- })
- //鼠标按下
- const start = (e) => {
- e = e || window.event
- if (!e.touches) {
- //兼容PC端
- var x = e.clientX
- } else {
- //兼容移动端
- var x = e.touches[0].pageX
- }
- startLeft.value = Math.floor(x - barArea.value.getBoundingClientRect().left)
- startMoveTime.value = +new Date() //开始滑动的时间
- if (isEnd.value == false) {
- text.value = ''
- moveBlockBackgroundColor.value = '#337ab7'
- leftBarBorderColor.value = '#337AB7'
- iconColor.value = '#fff'
- e.stopPropagation()
- status.value = true
- }
- }
- //鼠标移动
- const move = (e) => {
- e = e || window.event
- if (status.value && isEnd.value == false) {
- if (!e.touches) {
- //兼容PC端
- var x = e.clientX
- } else {
- //兼容移动端
- var x = e.touches[0].pageX
- }
- var bar_area_left = barArea.value.getBoundingClientRect().left
- var move_block_left = x - bar_area_left //小方块相对于父元素的left值
- if (
- move_block_left >=
- barArea.value.offsetWidth - parseInt(parseInt(blockSize.value.width) / 2) - 2
- ) {
- move_block_left =
- barArea.value.offsetWidth - parseInt(parseInt(blockSize.value.width) / 2) - 2
- }
- if (move_block_left <= 0) {
- move_block_left = parseInt(parseInt(blockSize.value.width) / 2)
- }
- //拖动后小方块的left值
- moveBlockLeft.value = move_block_left - startLeft.value + 'px'
- leftBarWidth.value = move_block_left - startLeft.value + 'px'
- }
- }
- //鼠标松开
- const end = () => {
- endMovetime.value = +new Date()
- //判断是否重合
- if (status.value && isEnd.value == false) {
- var moveLeftDistance = parseInt((moveBlockLeft.value || '').replace('px', ''))
- moveLeftDistance = (moveLeftDistance * 310) / parseInt(setSize.imgWidth)
- let data = {
- captchaType: captchaType.value,
- pointJson: secretKey.value
- ? aesEncrypt(JSON.stringify({ x: moveLeftDistance, y: 5.0 }), secretKey.value)
- : JSON.stringify({ x: moveLeftDistance, y: 5.0 }),
- token: backToken.value
- }
- reqCheck(data).then((res) => {
- if (res.repCode == '0000') {
- moveBlockBackgroundColor.value = '#5cb85c'
- leftBarBorderColor.value = '#5cb85c'
- iconColor.value = '#fff'
- iconClass.value = 'icon-check'
- showRefresh.value = false
- isEnd.value = true
- if (mode.value == 'pop') {
- setTimeout(() => {
- proxy.$parent.clickShow = false
- refresh()
- }, 1500)
- }
- passFlag.value = true
- tipWords.value = `${((endMovetime.value - startMoveTime.value) / 1000).toFixed(2)}s
- ${t('captcha.success')}`
- var captchaVerification = secretKey.value
- ? aesEncrypt(
- backToken.value + '---' + JSON.stringify({ x: moveLeftDistance, y: 5.0 }),
- secretKey.value
- )
- : backToken.value + '---' + JSON.stringify({ x: moveLeftDistance, y: 5.0 })
- setTimeout(() => {
- tipWords.value = ''
- proxy.$parent.closeBox()
- proxy.$parent.$emit('success', { captchaVerification })
- }, 1000)
- } else {
- moveBlockBackgroundColor.value = '#d9534f'
- leftBarBorderColor.value = '#d9534f'
- iconColor.value = '#fff'
- iconClass.value = 'icon-close'
- passFlag.value = false
- setTimeout(function () {
- refresh()
- }, 1000)
- proxy.$parent.$emit('error', proxy)
- tipWords.value = t('captcha.fail')
- setTimeout(() => {
- tipWords.value = ''
- }, 1000)
- }
- })
- status.value = false
- }
- }
- const refresh = async () => {
- showRefresh.value = true
- finishText.value = ''
- transitionLeft.value = 'left .3s'
- moveBlockLeft.value = 0
- leftBarWidth.value = undefined
- transitionWidth.value = 'width .3s'
- leftBarBorderColor.value = '#ddd'
- moveBlockBackgroundColor.value = '#fff'
- iconColor.value = '#000'
- iconClass.value = 'icon-right'
- isEnd.value = false
- await getPictrue()
- setTimeout(() => {
- transitionWidth.value = ''
- transitionLeft.value = ''
- text.value = explain.value
- }, 300)
- }
- // 请求背景图片和验证图片
- const getPictrue = async () => {
- let data = {
- captchaType: captchaType.value
- }
- const res = await getCode(data)
- if (res.repCode == '0000') {
- backImgBase.value = res.repData.originalImageBase64
- blockBackImgBase.value = res.repData.jigsawImageBase64
- backToken.value = res.repData.token
- secretKey.value = res.repData.secretKey
- } else {
- tipWords.value = res.repMsg
- }
- }
- </script>
|