VerifyPoints.vue 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. <template>
  2. <div style="position: relative" >
  3. <div class="verify-img-out">
  4. <div
  5. class="verify-img-panel"
  6. :style="{'width': setSize.imgWidth,
  7. 'height': setSize.imgHeight,
  8. 'background-size' : setSize.imgWidth + ' '+ setSize.imgHeight,
  9. 'margin-bottom': vSpace + 'px'}"
  10. >
  11. <div v-show="showRefresh" class="verify-refresh" style="z-index:3" @click="refresh">
  12. <i class="iconfont icon-refresh" />
  13. </div>
  14. <img
  15. ref="canvas"
  16. :src="pointBackImgBase?('data:image/png;base64,'+pointBackImgBase):defaultImg"
  17. alt=""
  18. style="width:100%;height:100%;display:block"
  19. @click="bindingClick?canvasClick($event):undefined"
  20. >
  21. <div
  22. v-for="(tempPoint, index) in tempPoints"
  23. :key="index"
  24. class="point-area"
  25. :style="{
  26. 'background-color':'#1abd6c',
  27. color:'#fff',
  28. 'z-index':9999,
  29. width:'20px',
  30. height:'20px',
  31. 'text-align':'center',
  32. 'line-height':'20px',
  33. 'border-radius': '50%',
  34. position:'absolute',
  35. top:parseInt(tempPoint.y-10) + 'px',
  36. left:parseInt(tempPoint.x-10) + 'px'
  37. }"
  38. >
  39. {{ index + 1 }}
  40. </div>
  41. </div>
  42. </div>
  43. <!-- 'height': this.barSize.height, -->
  44. <div
  45. class="verify-bar-area"
  46. :style="{'width': setSize.imgWidth,
  47. 'color': this.barAreaColor,
  48. 'border-color': this.barAreaBorderColor,
  49. 'line-height':this.barSize.height}"
  50. >
  51. <span class="verify-msg">{{ text }}</span>
  52. </div>
  53. </div>
  54. </template>
  55. <script type="text/babel">
  56. /**
  57. * VerifyPoints
  58. * @description 点选
  59. * */
  60. import { resetSize } from './../utils/util'
  61. import { aesEncrypt } from '@/utils/ase'
  62. import { reqGet, reqCheck } from './../api/index'
  63. export default {
  64. name: 'VerifyPoints',
  65. props: {
  66. // 弹出式pop,固定fixed
  67. mode: {
  68. type: String,
  69. default: 'fixed'
  70. },
  71. captchaType: {
  72. type: String,
  73. },
  74. // 间隔
  75. vSpace: {
  76. type: Number,
  77. default: 5
  78. },
  79. imgSize: {
  80. type: Object,
  81. default() {
  82. return {
  83. width: '310px',
  84. height: '155px'
  85. }
  86. }
  87. },
  88. barSize: {
  89. type: Object,
  90. default() {
  91. return {
  92. width: '310px',
  93. height: '40px'
  94. }
  95. }
  96. },
  97. defaultImg: {
  98. type: String,
  99. default: ''
  100. }
  101. },
  102. data() {
  103. return {
  104. secretKey: '', // 后端返回的ase加密秘钥
  105. checkNum: 3, // 默认需要点击的字数
  106. fontPos: [], // 选中的坐标信息
  107. checkPosArr: [], // 用户点击的坐标
  108. num: 1, // 点击的记数
  109. pointBackImgBase: '', // 后端获取到的背景图片
  110. poinTextList: [], // 后端返回的点击字体顺序
  111. backToken: '', // 后端返回的token值
  112. setSize: {
  113. imgHeight: 0,
  114. imgWidth: 0,
  115. barHeight: 0,
  116. barWidth: 0
  117. },
  118. tempPoints: [],
  119. text: '',
  120. barAreaColor: undefined,
  121. barAreaBorderColor: undefined,
  122. showRefresh: true,
  123. bindingClick: true
  124. }
  125. },
  126. computed: {
  127. resetSize() {
  128. return resetSize
  129. }
  130. },
  131. watch: {
  132. // type变化则全面刷新
  133. type: {
  134. immediate: true,
  135. handler() {
  136. this.init()
  137. }
  138. }
  139. },
  140. mounted() {
  141. // 禁止拖拽
  142. this.$el.onselectstart = function() {
  143. return false
  144. }
  145. },
  146. methods: {
  147. init() {
  148. // 加载页面
  149. this.fontPos.splice(0, this.fontPos.length)
  150. this.checkPosArr.splice(0, this.checkPosArr.length)
  151. this.num = 1
  152. this.getPictrue()
  153. this.$nextTick(() => {
  154. this.setSize = this.resetSize(this) // 重新设置宽度高度
  155. this.$parent.$emit('ready', this)
  156. })
  157. },
  158. canvasClick(e) {
  159. this.checkPosArr.push(this.getMousePos(this.$refs.canvas, e))
  160. if (this.num === this.checkNum) {
  161. this.num = this.createPoint(this.getMousePos(this.$refs.canvas, e))
  162. // 按比例转换坐标值
  163. this.checkPosArr = this.pointTransfrom(this.checkPosArr, this.setSize)
  164. // 等创建坐标执行完
  165. setTimeout(() => {
  166. // var flag = this.comparePos(this.fontPos, this.checkPosArr);
  167. // 发送后端请求
  168. const captchaVerification = this.secretKey ? aesEncrypt(this.backToken + '---' + JSON.stringify(this.checkPosArr), this.secretKey) : this.backToken + '---' + JSON.stringify(this.checkPosArr)
  169. const data = {
  170. captchaType: this.captchaType,
  171. 'pointJson': this.secretKey ? aesEncrypt(JSON.stringify(this.checkPosArr), this.secretKey) : JSON.stringify(this.checkPosArr),
  172. 'token': this.backToken
  173. }
  174. reqCheck(data).then(res => {
  175. if (res.repCode === '0000') {
  176. this.barAreaColor = '#4cae4c'
  177. this.barAreaBorderColor = '#5cb85c'
  178. this.text = '验证成功'
  179. this.bindingClick = false
  180. if (this.mode === 'pop') {
  181. setTimeout(() => {
  182. this.$parent.clickShow = false
  183. this.refresh()
  184. }, 1500)
  185. }
  186. this.$parent.$emit('success', { captchaVerification })
  187. } else {
  188. this.$parent.$emit('error', this)
  189. this.barAreaColor = '#d9534f'
  190. this.barAreaBorderColor = '#d9534f'
  191. this.text = '验证失败'
  192. setTimeout(() => {
  193. this.refresh()
  194. }, 700)
  195. }
  196. })
  197. }, 400)
  198. }
  199. if (this.num < this.checkNum) {
  200. this.num = this.createPoint(this.getMousePos(this.$refs.canvas, e))
  201. }
  202. },
  203. // 获取坐标
  204. getMousePos: function(obj, e) {
  205. const x = e.offsetX
  206. const y = e.offsetY
  207. return { x, y }
  208. },
  209. // 创建坐标点
  210. createPoint: function(pos) {
  211. this.tempPoints.push(Object.assign({}, pos))
  212. return ++this.num
  213. },
  214. refresh: function() {
  215. this.tempPoints.splice(0, this.tempPoints.length)
  216. this.barAreaColor = '#000'
  217. this.barAreaBorderColor = '#ddd'
  218. this.bindingClick = true
  219. this.fontPos.splice(0, this.fontPos.length)
  220. this.checkPosArr.splice(0, this.checkPosArr.length)
  221. this.num = 1
  222. this.getPictrue()
  223. this.text = '验证失败'
  224. this.showRefresh = true
  225. },
  226. // 请求背景图片和验证图片
  227. getPictrue() {
  228. const data = {
  229. captchaType: this.captchaType,
  230. clientUid: localStorage.getItem('point'),
  231. ts: Date.now(), // 现在的时间戳
  232. }
  233. reqGet(data).then(res => {
  234. if (res.repCode === '0000') {
  235. this.pointBackImgBase = res.repData.originalImageBase64
  236. this.backToken = res.repData.token
  237. this.secretKey = res.repData.secretKey
  238. this.poinTextList = res.repData.wordList
  239. this.text = '请依次点击【' + this.poinTextList.join(',') + '】'
  240. } else {
  241. this.text = res.repMsg
  242. }
  243. // 判断接口请求次数是否失效
  244. if (res.repCode === '6201') {
  245. this.pointBackImgBase = null
  246. }
  247. })
  248. },
  249. // 坐标转换函数
  250. pointTransfrom(pointArr, imgSize) {
  251. const newPointArr = pointArr.map(p => {
  252. const x = Math.round(310 * p.x / parseInt(imgSize.imgWidth))
  253. const y = Math.round(155 * p.y / parseInt(imgSize.imgHeight))
  254. return { x, y }
  255. })
  256. // console.log(newPointArr,"newPointArr");
  257. return newPointArr
  258. }
  259. },
  260. }
  261. </script>