VerifyPoints.vue 6.8 KB

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