inleft
2022-02-09 9bcb19959eeb9da9bde2561e7278f6d0a55eb151
commit | author | age
9bcb19 1 <template>
I 2   <div style="position: relative;">
3     <div
4       :style="{height: (parseInt(setSize.imgHeight) + vSpace) + 'px'}"
5       class="verify-img-out"
6       v-if="type === '2'"
7     >
8       <div
9         :style="{width: setSize.imgWidth,
10                  height: setSize.imgHeight,}"
11         class="verify-img-panel">
12         <img :src="'data:image/png;base64,'+backImgBase" alt="" style="width:100%;height:100%;display:block">
13         <div @click="refresh" class="verify-refresh" v-show="showRefresh"><i class="iconfont icon-refresh"></i>
14         </div>
15         <transition name="tips">
16           <span :class="passFlag ?'suc-bg':'err-bg'" class="verify-tips" v-if="tipWords">{{ tipWords }}</span>
17         </transition>
18       </div>
19     </div>
20     <!-- 公共部分 -->
21     <div
22       :style="{width: setSize.imgWidth,
23                height: barSize.height,
24                'line-height':barSize.height}"
25       class="verify-bar-area">
26       <span class="verify-msg" v-text="text"></span>
27       <div
28         :style="{width: (leftBarWidth!==undefined)?leftBarWidth: barSize.height, height: barSize.height, 'border-color': leftBarBorderColor, transaction: transitionWidth}"
29         class="verify-left-bar">
30         <span class="verify-msg" v-text="finishText"></span>
31         <div
32           :style="{width: barSize.height, height: barSize.height, 'background-color': moveBlockBackgroundColor, left: moveBlockLeft, transition: transitionLeft}"
33           @mousedown="start"
34           @touchstart="start"
35           class="verify-move-block">
36           <i
37             :class="['verify-icon iconfont', iconClass]"
38             :style="{color: iconColor}"></i>
39           <div
40             :style="{'width':Math.floor(parseInt(setSize.imgWidth)*47/310)+ 'px',
41                      'height': setSize.imgHeight,
42                      'top':'-' + (parseInt(setSize.imgHeight) + vSpace) + 'px',
43                      'background-size': setSize.imgWidth + ' ' + setSize.imgHeight,
44             }"
45             class="verify-sub-block"
46             v-if="type === '2'">
47             <img :src="'data:image/png;base64,'+blockBackImgBase" alt="" style="width:100%;height:100%;display:block">
48           </div>
49         </div>
50       </div>
51     </div>
52   </div>
53 </template>
54 <script type="text/babel">
55     /**
56      * VerifySlide
57      * @description 滑块
58      * */
59     import { aesEncrypt } from './../utils/ase'
60     import { resetSize } from './../utils/util'
61     import { reqGet, reqCheck } from '@/api/modular/system/loginManage'
62
63     //  "captchaType":"blockPuzzle",
64     export default {
65         name: 'VerifySlide',
66         props: {
67             // eslint-disable-next-line vue/require-default-prop
68             captchaType: {
69                 type: String
70             },
71             type: {
72                 type: String,
73                 default: '1'
74             },
75             // 弹出式pop,固定fixed
76             mode: {
77                 type: String,
78                 default: 'fixed'
79             },
80             vSpace: {
81                 type: Number,
82                 default: 5
83             },
84             explain: {
85                 type: String,
86                 default: '向右滑动完成验证'
87             },
88             imgSize: {
89                 type: Object,
90                 default() {
91                     return {
92                         width: '310px',
93                         height: '155px'
94                     }
95                 }
96             },
97             blockSize: {
98                 type: Object,
99                 default() {
100                     return {
101                         width: '50px',
102                         height: '50px'
103                     }
104                 }
105             },
106             barSize: {
107                 type: Object,
108                 default() {
109                     return {
110                         width: '310px',
111                         height: '40px'
112                     }
113                 }
114             }
115         },
116         data() {
117             return {
118                 secretKey: '', // 后端返回的加密秘钥 字段
119                 passFlag: '', // 是否通过的标识
120                 backImgBase: '', // 验证码背景图片
121                 blockBackImgBase: '', // 验证滑块的背景图片
122                 backToken: '', // 后端返回的唯一token值
123                 startMoveTime: '', // 移动开始的时间
124                 endMovetime: '', // 移动结束的时间
125                 tipsBackColor: '', // 提示词的背景颜色
126                 tipWords: '',
127                 text: '',
128                 finishText: '',
129                 setSize: {
130                     imgHeight: 0,
131                     imgWidth: 0,
132                     barHeight: 0,
133                     barWidth: 0
134                 },
135                 top: 0,
136                 left: 0,
137                 moveBlockLeft: undefined,
138                 leftBarWidth: undefined,
139                 // 移动中样式
140                 moveBlockBackgroundColor: undefined,
141                 leftBarBorderColor: '#ddd',
142                 iconColor: undefined,
143                 iconClass: 'icon-right',
144                 status: false, // 鼠标状态
145                 isEnd: false,        // 是够验证完成
146                 showRefresh: true,
147                 transitionLeft: '',
148                 transitionWidth: ''
149             }
150         },
151         computed: {
152             barArea() {
153                 return this.$el.querySelector('.verify-bar-area')
154             },
155             resetSize() {
156                 return resetSize
157             }
158         },
159         methods: {
160             init() {
161                 this.text = this.explain
162                 this.getPictrue()
163                 this.$nextTick(() => {
164                     const setSize = this.resetSize(this)    // 重新设置宽度高度
165                     for (const key in setSize) {
166                         this.$set(this.setSize, key, setSize[key])
167                     }
168                     this.$parent.$emit('ready', this)
169                 })
170
171                 var _this = this
172
173                 window.removeEventListener('touchmove', function (e) {
174                     _this.move(e)
175                 })
176                 window.removeEventListener('mousemove', function (e) {
177                     _this.move(e)
178                 })
179
180                 // 鼠标松开
181                 window.removeEventListener('touchend', function () {
182                     _this.end()
183                 })
184                 window.removeEventListener('mouseup', function () {
185                     _this.end()
186                 })
187
188                 window.addEventListener('touchmove', function (e) {
189                     _this.move(e)
190                 })
191                 window.addEventListener('mousemove', function (e) {
192                     _this.move(e)
193                 })
194
195                 // 鼠标松开
196                 window.addEventListener('touchend', function () {
197                     _this.end()
198                 })
199                 window.addEventListener('mouseup', function () {
200                     _this.end()
201                 })
202             },
203
204             // 鼠标按下
205             start: function (e) {
206                 e = e || window.event
207                 if (!e.touches) { // 兼容PC端
208                     var x = e.clientX
209                 } else { // 兼容移动端
210                     // eslint-disable-next-line no-redeclare
211                     var x = e.touches[0].pageX
212                 }
213                 this.startLeft = Math.floor(x - this.barArea.getBoundingClientRect().left)
214                 this.startMoveTime = +new Date() // 开始滑动的时间
215                 // eslint-disable-next-line eqeqeq
216                 if (this.isEnd == false) {
217                     this.text = ''
218                     this.moveBlockBackgroundColor = '#337ab7'
219                     this.leftBarBorderColor = '#337AB7'
220                     this.iconColor = '#fff'
221                     e.stopPropagation()
222                     this.status = true
223                 }
224             },
225             // 鼠标移动
226             move: function (e) {
227                 e = e || window.event
228                 // eslint-disable-next-line eqeqeq
229                 if (this.status && this.isEnd == false) {
230                     if (!e.touches) { // 兼容PC端
231                         var x = e.clientX
232                     } else { // 兼容移动端
233                         // eslint-disable-next-line no-redeclare
234                         var x = e.touches[0].pageX
235                     }
236                     // eslint-disable-next-line camelcase
237                     var bar_area_left = this.barArea.getBoundingClientRect().left
238                     // eslint-disable-next-line camelcase
239                     var move_block_left = x - bar_area_left // 小方块相对于父元素的left值
240                     // eslint-disable-next-line camelcase
241                     if (move_block_left >= this.barArea.offsetWidth - parseInt(parseInt(this.blockSize.width) / 2) - 2) {
242                         // eslint-disable-next-line camelcase
243                         move_block_left = this.barArea.offsetWidth - parseInt(parseInt(this.blockSize.width) / 2) - 2
244                     }
245                     // eslint-disable-next-line camelcase
246                     if (move_block_left <= 0) {
247                         // eslint-disable-next-line camelcase
248                         move_block_left = parseInt(parseInt(this.blockSize.width) / 2)
249                     }
250                     // 拖动后小方块的left值
251                     // eslint-disable-next-line camelcase
252                     this.moveBlockLeft = (move_block_left - this.startLeft) + 'px'
253                     // eslint-disable-next-line camelcase
254                     this.leftBarWidth = (move_block_left - this.startLeft) + 'px'
255                 }
256             },
257
258             // 鼠标松开
259             end: function () {
260                 this.endMovetime = +new Date()
261                 var _this = this
262                 // 判断是否重合
263                 // eslint-disable-next-line eqeqeq
264                 if (this.status && this.isEnd == false) {
265                     var moveLeftDistance = parseInt((this.moveBlockLeft || '').replace('px', ''))
266                     moveLeftDistance = moveLeftDistance * 310 / parseInt(this.setSize.imgWidth)
267                     const data = {
268                         captchaType: this.captchaType,
269                         'pointJson': this.secretKey ? aesEncrypt(JSON.stringify({ x: moveLeftDistance, y: 5.0 }), this.secretKey) : JSON.stringify({ x: moveLeftDistance, y: 5.0 }),
270                         'token': this.backToken
271                     }
272                     reqCheck(data).then(res => {
273                         // eslint-disable-next-line eqeqeq
274                         if (res.repCode == '0000') {
275                             this.moveBlockBackgroundColor = '#5cb85c'
276                             this.leftBarBorderColor = '#5cb85c'
277                             this.iconColor = '#fff'
278                             this.iconClass = 'icon-check'
279                             this.showRefresh = false
280                             this.isEnd = true
281                             // eslint-disable-next-line eqeqeq
282                             if (this.mode == 'pop') {
283                                 setTimeout(() => {
284                                     this.$parent.clickShow = false
285                                     this.refresh()
286                                 }, 1500)
287                             }
288                             this.passFlag = true
289                             this.tipWords = `${((this.endMovetime - this.startMoveTime) / 1000).toFixed(2)}s验证成功`
290                             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 })
291                             setTimeout(() => {
292                                 this.tipWords = ''
293                                 this.$parent.closeBox()
294                                 this.$parent.$emit('success', { captchaVerification })
295                             }, 1000)
296                         } else {
297                             this.moveBlockBackgroundColor = '#d9534f'
298                             this.leftBarBorderColor = '#d9534f'
299                             this.iconColor = '#fff'
300                             this.iconClass = 'icon-close'
301                             this.passFlag = false
302                             setTimeout(function () {
303                                 _this.refresh()
304                             }, 1000)
305                             this.$parent.$emit('error', this)
306                             this.tipWords = '验证失败'
307                             setTimeout(() => {
308                                     this.tipWords = ''
309                             }, 1000)
310                         }
311                     })
312                     this.status = false
313                 }
314             },
315
316             refresh: function () {
317                 this.showRefresh = true
318                 this.finishText = ''
319
320                 this.transitionLeft = 'left .3s'
321                 this.moveBlockLeft = 0
322
323                 this.leftBarWidth = undefined
324                 this.transitionWidth = 'width .3s'
325
326                 this.leftBarBorderColor = '#ddd'
327                 this.moveBlockBackgroundColor = '#fff'
328                 this.iconColor = '#000'
329                 this.iconClass = 'icon-right'
330                 this.isEnd = false
331
332                 this.getPictrue()
333                 setTimeout(() => {
334                     this.transitionWidth = ''
335                     this.transitionLeft = ''
336                     this.text = this.explain
337                 }, 300)
338             },
339
340             // 请求背景图片和验证图片
341             getPictrue() {
342                 const data = {
343                     captchaType: this.captchaType
344                 }
345                 reqGet(data).then(res => {
346                     // eslint-disable-next-line eqeqeq
347                     if (res.repCode == '0000') {
348                         this.backImgBase = res.repData.originalImageBase64
349                         this.blockBackImgBase = res.repData.jigsawImageBase64
350                         this.backToken = res.repData.token
351                         this.secretKey = res.repData.secretKey
352                     } else {
353                         this.tipWords = res.repMsg
354                     }
355                 })
356             }
357         },
358         watch: {
359             // type变化则全面刷新
360             type: {
361                 immediate: true,
362                 handler() {
363                     this.init()
364                 }
365             }
366         },
367         mounted() {
368             // 禁止拖拽
369             this.$el.onselectstart = function () {
370                 return false
371             }
372         }
373     }
374 </script>