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/VerifyPoints.vue |  268 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 268 insertions(+), 0 deletions(-)

diff --git a/src/components/verifition/Verify/VerifyPoints.vue b/src/components/verifition/Verify/VerifyPoints.vue
new file mode 100644
index 0000000..71cecd3
--- /dev/null
+++ b/src/components/verifition/Verify/VerifyPoints.vue
@@ -0,0 +1,268 @@
+<template>
+  <div
+    style="position: relative"
+  >
+    <div class="verify-img-out">
+      <div
+        class="verify-img-panel"
+        :style="{'width': setSize.imgWidth,
+                 'height': setSize.imgHeight,
+                 'background-size' : setSize.imgWidth + ' '+ setSize.imgHeight,
+                 'margin-bottom': vSpace + 'px'}"
+      >
+        <div v-show="showRefresh" class="verify-refresh" style="z-index:3" @click="refresh">
+          <i class="iconfont icon-refresh" />
+        </div>
+        <img
+          ref="canvas"
+          :src="pointBackImgBase?('data:image/png;base64,'+pointBackImgBase):defaultImg"
+          alt=""
+          style="width:100%;height:100%;display:block"
+          @click="bindingClick?canvasClick($event):undefined"
+        >
+
+        <div
+          v-for="(tempPoint, index) in tempPoints"
+          :key="index"
+          class="point-area"
+          :style="{
+            'background-color':'#1abd6c',
+            color:'#fff',
+            'z-index':9999,
+            width:'20px',
+            height:'20px',
+            'text-align':'center',
+            'line-height':'20px',
+            'border-radius': '50%',
+            position:'absolute',
+            top:parseInt(tempPoint.y-10) + 'px',
+            left:parseInt(tempPoint.x-10) + 'px'
+          }"
+        >
+          {{ index + 1 }}
+        </div>
+      </div>
+    </div>
+    <!-- 'height': this.barSize.height, -->
+    <div
+      class="verify-bar-area"
+      :style="{'width': setSize.imgWidth,
+               'color': this.barAreaColor,
+               'border-color': this.barAreaBorderColor,
+               'line-height':this.barSize.height}"
+    >
+      <span class="verify-msg">{{ text }}</span>
+    </div>
+  </div>
+</template>
+<script type="text/babel">
+/**
+     * VerifyPoints
+     * @description 点选
+     * */
+import { resetSize, _code_chars, _code_color1, _code_color2 } from './../utils/util'
+import { aesEncrypt } from './../utils/ase'
+import { reqGet, reqCheck } from './../api/index'
+
+export default {
+  name: 'VerifyPoints',
+  props: {
+    // 弹出式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'
+        }
+      }
+    },
+    defaultImg: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    return {
+      secretKey: '', // 后端返回的ase加密秘钥
+      checkNum: 3, // 默认需要点击的字数
+      fontPos: [], // 选中的坐标信息
+      checkPosArr: [], // 用户点击的坐标
+      num: 1, // 点击的记数
+      pointBackImgBase: '', // 后端获取到的背景图片
+      poinTextList: [], // 后端返回的点击字体顺序
+      backToken: '', // 后端返回的token值
+      setSize: {
+        imgHeight: 0,
+        imgWidth: 0,
+        barHeight: 0,
+        barWidth: 0
+      },
+      tempPoints: [],
+      text: '',
+      barAreaColor: undefined,
+      barAreaBorderColor: undefined,
+      showRefresh: true,
+      bindingClick: true
+    }
+  },
+  computed: {
+    resetSize() {
+      return resetSize
+    }
+  },
+  watch: {
+    // type变化则全面刷新
+    type: {
+      immediate: true,
+      handler() {
+        this.init()
+      }
+    }
+  },
+  mounted() {
+    // 禁止拖拽
+    this.$el.onselectstart = function() {
+      return false
+    }
+  },
+  methods: {
+    init() {
+      // 加载页面
+      this.fontPos.splice(0, this.fontPos.length)
+      this.checkPosArr.splice(0, this.checkPosArr.length)
+      this.num = 1
+      this.getPictrue()
+      this.$nextTick(() => {
+        this.setSize = this.resetSize(this)	// 重新设置宽度高度
+        this.$parent.$emit('ready', this)
+      })
+    },
+    canvasClick(e) {
+      this.checkPosArr.push(this.getMousePos(this.$refs.canvas, e))
+      if (this.num == this.checkNum) {
+        this.num = this.createPoint(this.getMousePos(this.$refs.canvas, e))
+        // 按比例转换坐标值
+        this.checkPosArr = this.pointTransfrom(this.checkPosArr, this.setSize)
+        // 等创建坐标执行完
+        setTimeout(() => {
+          // var flag = this.comparePos(this.fontPos, this.checkPosArr);
+          // 发送后端请求
+          var captchaVerification = this.secretKey ? aesEncrypt(this.backToken + '---' + JSON.stringify(this.checkPosArr), this.secretKey) : this.backToken + '---' + JSON.stringify(this.checkPosArr)
+          const data = {
+            captchaType: this.captchaType,
+            'pointJson': this.secretKey ? aesEncrypt(JSON.stringify(this.checkPosArr), this.secretKey) : JSON.stringify(this.checkPosArr),
+            'token': this.backToken
+          }
+          reqCheck(data).then(res => {
+            if (res.repCode == '0000') {
+              this.barAreaColor = '#4cae4c'
+              this.barAreaBorderColor = '#5cb85c'
+              this.text = '验证成功'
+              this.bindingClick = false
+              if (this.mode == 'pop') {
+                setTimeout(() => {
+                  this.$parent.clickShow = false
+                  this.refresh()
+                }, 1500)
+              }
+              this.$parent.$emit('success', { captchaVerification })
+            } else {
+              this.$parent.$emit('error', this)
+              this.barAreaColor = '#d9534f'
+              this.barAreaBorderColor = '#d9534f'
+              this.text = '验证失败'
+              setTimeout(() => {
+                this.refresh()
+              }, 700)
+            }
+          })
+        }, 400)
+      }
+      if (this.num < this.checkNum) {
+        this.num = this.createPoint(this.getMousePos(this.$refs.canvas, e))
+      }
+    },
+
+    // 获取坐标
+    getMousePos: function(obj, e) {
+      var x = e.offsetX
+      var y = e.offsetY
+      return { x, y }
+    },
+    // 创建坐标点
+    createPoint: function(pos) {
+      this.tempPoints.push(Object.assign({}, pos))
+      return ++this.num
+    },
+    refresh: function() {
+      this.tempPoints.splice(0, this.tempPoints.length)
+      this.barAreaColor = '#000'
+      this.barAreaBorderColor = '#ddd'
+      this.bindingClick = true
+      this.fontPos.splice(0, this.fontPos.length)
+      this.checkPosArr.splice(0, this.checkPosArr.length)
+      this.num = 1
+      this.getPictrue()
+      this.text = '验证失败'
+      this.showRefresh = true
+    },
+
+    // 请求背景图片和验证图片
+    getPictrue() {
+      const data = {
+        captchaType: this.captchaType,
+        clientUid: localStorage.getItem('point'),
+        ts: Date.now(), // 现在的时间戳
+      }
+      reqGet(data).then(res => {
+        if (res.repCode == '0000') {
+          this.pointBackImgBase = res.repData.originalImageBase64
+          this.backToken = res.repData.token
+          this.secretKey = res.repData.secretKey
+          this.poinTextList = res.repData.wordList
+          this.text = '请依次点击【' + this.poinTextList.join(',') + '】'
+        } else {
+          this.text = res.repMsg
+        }
+
+        // 判断接口请求次数是否失效
+        if (res.repCode == '6201') {
+          this.pointBackImgBase = null
+        }
+      })
+    },
+    // 坐标转换函数
+    pointTransfrom(pointArr, imgSize) {
+      var newPointArr = pointArr.map(p => {
+        const x = Math.round(310 * p.x / parseInt(imgSize.imgWidth))
+        const y = Math.round(155 * p.y / parseInt(imgSize.imgHeight))
+        return { x, y }
+      })
+      // console.log(newPointArr,"newPointArr");
+      return newPointArr
+    }
+  },
+}
+</script>

--
Gitblit v1.9.3