From 089bf5d2378b3c4a61d795b2a92bede2c193b771 Mon Sep 17 00:00:00 2001
From: admin <344137771@qq.com>
Date: Tue, 06 Jan 2026 11:22:58 +0800
Subject: [PATCH] 1

---
 src/components/verifition/Verify/VerifySlide.vue |  378 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 378 insertions(+), 0 deletions(-)

diff --git a/src/components/verifition/Verify/VerifySlide.vue b/src/components/verifition/Verify/VerifySlide.vue
new file mode 100644
index 0000000..535e5fa
--- /dev/null
+++ b/src/components/verifition/Verify/VerifySlide.vue
@@ -0,0 +1,378 @@
+<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="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 { reqGet, reqCheck } from './../api/index'
+
+//  "captchaType":"blockPuzzle",
+export default {
+  name: 'VerifySlide',
+  props: {
+    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: '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: ''
+    }
+  },
+  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
+    }
+    console.log(this.defaultImg)
+  },
+  methods: {
+    init() {
+      this.text = this.explain
+      this.getPictrue()
+      this.$nextTick(() => {
+        const setSize = this.resetSize(this)	// 重新设置宽度高度
+        for (const key in setSize) {
+          this.$set(this.setSize, key, setSize[key])
+        }
+        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: function() {
+      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 data = {
+          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
+        }
+        reqCheck(data).then(res => {
+          res = res.data
+          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.$parent.closeBox()
+              this.$parent.$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.$parent.$emit('error', this)
+            this.tipWords = '验证失败'
+            setTimeout(() => {
+              this.tipWords = ''
+            }, 1000)
+          }
+        })
+        this.status = false
+      }
+    },
+
+    refresh: function() {
+      this.showRefresh = true
+      this.finishText = ''
+
+      this.transitionLeft = 'left .3s'
+      this.moveBlockLeft = 0
+
+      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.transitionWidth = ''
+        this.transitionLeft = ''
+        this.text = this.explain
+      }, 300)
+    },
+
+    // 请求背景图片和验证图片
+    getPictrue() {
+      const data = {
+        captchaType: this.captchaType,
+        clientUid: localStorage.getItem('slider'),
+        ts: Date.now(), // 现在的时间戳
+      }
+      reqGet(data).then(res => {
+        if (res.data.repCode == '0000') {
+          this.backImgBase = res.data.repData.originalImageBase64
+          this.blockBackImgBase = res.data.repData.jigsawImageBase64
+          this.backToken = res.data.repData.token
+          this.secretKey = res.data.repData.secretKey
+        } else {
+          this.tipWords = res.data.repMsg
+        }
+
+        // 判断接口请求次数是否失效
+        if (res.data.repCode == '6201') {
+          this.backImgBase = null
+          this.blockBackImgBase = null
+        }
+      })
+    },
+  },
+}
+</script>
+

--
Gitblit v1.9.3