feat: add verification comp【31315a7f】
							parent
							
								
									1112409a3b
								
							
						
					
					
						commit
						eeb19808c9
					
				|  | @ -37,9 +37,11 @@ | ||||||
|     "vue": "catalog:", |     "vue": "catalog:", | ||||||
|     "vue-json-viewer": "catalog:", |     "vue-json-viewer": "catalog:", | ||||||
|     "vue-router": "catalog:", |     "vue-router": "catalog:", | ||||||
|     "vue-tippy": "catalog:" |     "vue-tippy": "catalog:", | ||||||
|  |     "crypto-js": "catalog:" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@types/qrcode": "catalog:" |     "@types/qrcode": "catalog:", | ||||||
|  |     "@types/crypto-js": "catalog:" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -4,3 +4,5 @@ export { default as PointSelectionCaptchaCard } from './point-selection-captcha/ | ||||||
| export { default as SliderCaptcha } from './slider-captcha/index.vue'; | export { default as SliderCaptcha } from './slider-captcha/index.vue'; | ||||||
| export { default as SliderRotateCaptcha } from './slider-rotate-captcha/index.vue'; | export { default as SliderRotateCaptcha } from './slider-rotate-captcha/index.vue'; | ||||||
| export type * from './types'; | export type * from './types'; | ||||||
|  | 
 | ||||||
|  | export { default as Verification } from './verification/index.vue'; | ||||||
|  | @ -0,0 +1,304 @@ | ||||||
|  | <script lang="ts" setup> | ||||||
|  | import type { VerificationProps } from '../types'; | ||||||
|  | 
 | ||||||
|  | import { | ||||||
|  |   type ComponentInternalInstance, | ||||||
|  |   getCurrentInstance, | ||||||
|  |   nextTick, | ||||||
|  |   onMounted, | ||||||
|  |   reactive, | ||||||
|  |   ref, | ||||||
|  |   toRefs, | ||||||
|  | } from 'vue'; | ||||||
|  | 
 | ||||||
|  | import { $t } from '@vben/locales'; | ||||||
|  | 
 | ||||||
|  | import { aesEncrypt } from '../utils/ase'; | ||||||
|  | import { resetSize } from '../utils/util'; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * VerifyPoints | ||||||
|  |  * @description 点选 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | // const props = defineProps({ | ||||||
|  | //   barSize: { | ||||||
|  | //     default() { | ||||||
|  | //       return { | ||||||
|  | //         height: '40px', | ||||||
|  | //         width: '310px', | ||||||
|  | //       }; | ||||||
|  | //     }, | ||||||
|  | //     type: Object, | ||||||
|  | //   }, | ||||||
|  | //   captchaType: { | ||||||
|  | //     default() { | ||||||
|  | //       return 'VerifyPoints'; | ||||||
|  | //     }, | ||||||
|  | //     type: String, | ||||||
|  | //   }, | ||||||
|  | //   imgSize: { | ||||||
|  | //     default() { | ||||||
|  | //       return { | ||||||
|  | //         height: '155px', | ||||||
|  | //         width: '310px', | ||||||
|  | //       }; | ||||||
|  | //     }, | ||||||
|  | //     type: Object, | ||||||
|  | //   }, | ||||||
|  | //   // 弹出式pop,固定fixed | ||||||
|  | //   mode: { | ||||||
|  | //     default: 'fixed', | ||||||
|  | //     type: String, | ||||||
|  | //   }, | ||||||
|  | //   // 间隔 | ||||||
|  | //   vSpace: { | ||||||
|  | //     default: 5, | ||||||
|  | //     type: Number, | ||||||
|  | //   }, | ||||||
|  | // }); | ||||||
|  | 
 | ||||||
|  | defineOptions({ | ||||||
|  |   name: 'VerifyPoints', | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | const props = withDefaults(defineProps<VerificationProps>(), { | ||||||
|  |   barSize: () => ({ | ||||||
|  |     height: '40px', | ||||||
|  |     width: '310px', | ||||||
|  |   }), | ||||||
|  |   captchaType: 'clickWord', | ||||||
|  |   imgSize: () => ({ | ||||||
|  |     height: '155px', | ||||||
|  |     width: '310px', | ||||||
|  |   }), | ||||||
|  |   mode: 'fixed', | ||||||
|  |   space: 5, | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | const emit = defineEmits(['onSuccess', 'onError', 'onClose', 'onReady']); | ||||||
|  | 
 | ||||||
|  | const { captchaType, mode, checkCaptchaApi, getCaptchaApi } = toRefs(props); | ||||||
|  | const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||||
|  | const secretKey = ref(); // 后端返回的ase加密秘钥 | ||||||
|  | const checkNum = ref(3); // 默认需要点击的字数 | ||||||
|  | const fontPos = reactive<any[]>([]); // 选中的坐标信息 | ||||||
|  | const checkPosArr = reactive<any[]>([]); // 用户点击的坐标 | ||||||
|  | const num = ref(1); // 点击的记数 | ||||||
|  | const pointBackImgBase = ref(); // 后端获取到的背景图片 | ||||||
|  | const poinTextList = ref<any[]>([]); // 后端返回的点击字体顺序 | ||||||
|  | const backToken = ref(); // 后端返回的token值 | ||||||
|  | const setSize = reactive({ | ||||||
|  |   barHeight: 0, | ||||||
|  |   barWidth: 0, | ||||||
|  |   imgHeight: 0, | ||||||
|  |   imgWidth: 0, | ||||||
|  | }); | ||||||
|  | const tempPoints = reactive<any[]>([]); | ||||||
|  | const text = ref(); | ||||||
|  | const barAreaColor = ref(); | ||||||
|  | const barAreaBorderColor = ref(); | ||||||
|  | const showRefresh = ref(true); | ||||||
|  | const bindingClick = ref(true); | ||||||
|  | 
 | ||||||
|  | function init() { | ||||||
|  |   // 加载页面 | ||||||
|  |   fontPos.splice(0, fontPos.length); | ||||||
|  |   checkPosArr.splice(0, checkPosArr.length); | ||||||
|  |   num.value = 1; | ||||||
|  |   getPictrue(); | ||||||
|  |   nextTick(() => { | ||||||
|  |     const { barHeight, barWidth, imgHeight, imgWidth } = resetSize(proxy); | ||||||
|  |     setSize.imgHeight = imgHeight; | ||||||
|  |     setSize.imgWidth = imgWidth; | ||||||
|  |     setSize.barHeight = barHeight; | ||||||
|  |     setSize.barWidth = barWidth; | ||||||
|  |     emit('onReady', proxy); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | onMounted(() => { | ||||||
|  |   // 禁止拖拽 | ||||||
|  |   init(); | ||||||
|  |   proxy?.$el?.addEventListener('selectstart', () => { | ||||||
|  |     return false; | ||||||
|  |   }); | ||||||
|  | }); | ||||||
|  | const canvas = ref(null); | ||||||
|  | 
 | ||||||
|  | // 获取坐标 | ||||||
|  | const getMousePos = function (obj: any, e: any) { | ||||||
|  |   const x = e.offsetX; | ||||||
|  |   const y = e.offsetY; | ||||||
|  |   return { x, y }; | ||||||
|  | }; | ||||||
|  | // 创建坐标点 | ||||||
|  | const createPoint = function (pos: any) { | ||||||
|  |   tempPoints.push(Object.assign({}, pos)); | ||||||
|  |   return num.value + 1; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // 坐标转换函数 | ||||||
|  | const pointTransfrom = function (pointArr: any, imgSize: any) { | ||||||
|  |   const newPointArr = pointArr.map((p: any) => { | ||||||
|  |     const x = Math.round((310 * p.x) / Number.parseInt(imgSize.imgWidth)); | ||||||
|  |     const y = Math.round((155 * p.y) / Number.parseInt(imgSize.imgHeight)); | ||||||
|  |     return { x, y }; | ||||||
|  |   }); | ||||||
|  |   return newPointArr; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const refresh = async function () { | ||||||
|  |   tempPoints.splice(0, tempPoints.length); | ||||||
|  |   barAreaColor.value = '#000'; | ||||||
|  |   barAreaBorderColor.value = '#ddd'; | ||||||
|  |   bindingClick.value = true; | ||||||
|  |   fontPos.splice(0, fontPos.length); | ||||||
|  |   checkPosArr.splice(0, checkPosArr.length); | ||||||
|  |   num.value = 1; | ||||||
|  |   await getPictrue(); | ||||||
|  |   showRefresh.value = true; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | function canvasClick(e: any) { | ||||||
|  |   checkPosArr.push(getMousePos(canvas, e)); | ||||||
|  |   if (num.value === checkNum.value) { | ||||||
|  |     num.value = createPoint(getMousePos(canvas, e)); | ||||||
|  |     // 按比例转换坐标值 | ||||||
|  |     const arr = pointTransfrom(checkPosArr, setSize); | ||||||
|  |     checkPosArr.length = 0; | ||||||
|  |     checkPosArr.push(...arr); | ||||||
|  |     // 等创建坐标执行完 | ||||||
|  |     setTimeout(() => { | ||||||
|  |       // var flag = this.comparePos(this.fontPos, this.checkPosArr); | ||||||
|  |       // 发送后端请求 | ||||||
|  |       const captchaVerification = secretKey.value | ||||||
|  |         ? aesEncrypt( | ||||||
|  |             `${backToken.value}---${JSON.stringify(checkPosArr)}`, | ||||||
|  |             secretKey.value, | ||||||
|  |           ) | ||||||
|  |         : `${backToken.value}---${JSON.stringify(checkPosArr)}`; | ||||||
|  |       const data = { | ||||||
|  |         captchaType: captchaType.value, | ||||||
|  |         pointJson: secretKey.value | ||||||
|  |           ? aesEncrypt(JSON.stringify(checkPosArr), secretKey.value) | ||||||
|  |           : JSON.stringify(checkPosArr), | ||||||
|  |         token: backToken.value, | ||||||
|  |       }; | ||||||
|  |       checkCaptchaApi?.value?.(data).then((response: any) => { | ||||||
|  |         const res = response.data; | ||||||
|  |         if (res.repCode === '0000') { | ||||||
|  |           barAreaColor.value = '#4cae4c'; | ||||||
|  |           barAreaBorderColor.value = '#5cb85c'; | ||||||
|  |           text.value = $t('ui.captcha.success'); | ||||||
|  |           bindingClick.value = false; | ||||||
|  |           if (mode.value === 'pop') { | ||||||
|  |             setTimeout(() => { | ||||||
|  |               emit('onClose'); | ||||||
|  |               refresh(); | ||||||
|  |             }, 1500); | ||||||
|  |           } | ||||||
|  |           emit('onSuccess', { captchaVerification }); | ||||||
|  |         } else { | ||||||
|  |           emit('onError', proxy); | ||||||
|  |           barAreaColor.value = '#d9534f'; | ||||||
|  |           barAreaBorderColor.value = '#d9534f'; | ||||||
|  |           text.value = $t('ui.captcha.sliderRotateFailTip'); | ||||||
|  |           setTimeout(() => { | ||||||
|  |             refresh(); | ||||||
|  |           }, 700); | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |     }, 400); | ||||||
|  |   } | ||||||
|  |   if (num.value < checkNum.value) | ||||||
|  |     num.value = createPoint(getMousePos(canvas, e)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 请求背景图片和验证图片 | ||||||
|  | async function getPictrue() { | ||||||
|  |   const data = { | ||||||
|  |     captchaType: captchaType.value, | ||||||
|  |   }; | ||||||
|  |   const res = await getCaptchaApi?.value?.(data); | ||||||
|  | 
 | ||||||
|  |   if (res?.data?.repCode === '0000') { | ||||||
|  |     pointBackImgBase.value = `data:image/png;base64,${res?.data?.repData?.originalImageBase64}`; | ||||||
|  |     backToken.value = res.data.repData.token; | ||||||
|  |     secretKey.value = res.data.repData.secretKey; | ||||||
|  |     poinTextList.value = res.data.repData.wordList; | ||||||
|  |     text.value = `${$t('ui.captcha.point')}【${poinTextList.value.join(',')}】`; | ||||||
|  |   } else { | ||||||
|  |     text.value = res?.data?.repMsg; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | defineExpose({ | ||||||
|  |   init, | ||||||
|  |   refresh, | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |   <div style="position: relative"> | ||||||
|  |     <div class="verify-img-out"> | ||||||
|  |       <div | ||||||
|  |         :style="{ | ||||||
|  |           width: setSize.imgWidth, | ||||||
|  |           height: setSize.imgHeight, | ||||||
|  |           'background-size': `${setSize.imgWidth} ${setSize.imgHeight}`, | ||||||
|  |           'margin-bottom': `${space}px`, | ||||||
|  |         }" | ||||||
|  |         class="verify-img-panel" | ||||||
|  |       > | ||||||
|  |         <div | ||||||
|  |           v-show="showRefresh" | ||||||
|  |           class="verify-refresh" | ||||||
|  |           style="z-index: 3" | ||||||
|  |           @click="refresh" | ||||||
|  |         > | ||||||
|  |           <i class="iconfont icon-refresh"></i> | ||||||
|  |         </div> | ||||||
|  |         <img | ||||||
|  |           ref="canvas" | ||||||
|  |           :src="pointBackImgBase" | ||||||
|  |           alt="" | ||||||
|  |           style="display: block; width: 100%; height: 100%" | ||||||
|  |           @click="bindingClick ? canvasClick($event) : undefined" | ||||||
|  |         /> | ||||||
|  | 
 | ||||||
|  |         <div | ||||||
|  |           v-for="(tempPoint, index) in tempPoints" | ||||||
|  |           :key="index" | ||||||
|  |           :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: `${tempPoint.y - 10}px`, | ||||||
|  |             left: `${tempPoint.x - 10}px`, | ||||||
|  |           }" | ||||||
|  |           class="point-area" | ||||||
|  |         > | ||||||
|  |           {{ index + 1 }} | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <!-- 'height': this.barSize.height, --> | ||||||
|  |     <div | ||||||
|  |       :style="{ | ||||||
|  |         width: setSize.imgWidth, | ||||||
|  |         color: barAreaColor, | ||||||
|  |         'border-color': barAreaBorderColor, | ||||||
|  |         'line-height': barSize.height, | ||||||
|  |       }" | ||||||
|  |       class="verify-bar-area" | ||||||
|  |     > | ||||||
|  |       <span class="verify-msg">{{ text }}</span> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  | @ -0,0 +1,376 @@ | ||||||
|  | <script lang="ts" setup> | ||||||
|  | import type { VerificationProps } from '../types'; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * VerifySlide | ||||||
|  |  * @description 滑块 | ||||||
|  |  */ | ||||||
|  | import { | ||||||
|  |   computed, | ||||||
|  |   getCurrentInstance, | ||||||
|  |   nextTick, | ||||||
|  |   onMounted, | ||||||
|  |   reactive, | ||||||
|  |   ref, | ||||||
|  |   toRefs, | ||||||
|  | } from 'vue'; | ||||||
|  | 
 | ||||||
|  | import { $t } from '@vben/locales'; | ||||||
|  | 
 | ||||||
|  | import { aesEncrypt } from './../utils/ase'; | ||||||
|  | import { resetSize } from './../utils/util'; | ||||||
|  | 
 | ||||||
|  | const props = withDefaults(defineProps<VerificationProps>(), { | ||||||
|  |   barSize: () => ({ | ||||||
|  |     height: '40px', | ||||||
|  |     width: '310px', | ||||||
|  |   }), | ||||||
|  |   blockSize: () => ({ | ||||||
|  |     height: '50px', | ||||||
|  |     width: '50px', | ||||||
|  |   }), | ||||||
|  |   captchaType: 'blockPuzzle', | ||||||
|  |   explain: '', | ||||||
|  |   imgSize: () => ({ | ||||||
|  |     height: '155px', | ||||||
|  |     width: '310px', | ||||||
|  |   }), | ||||||
|  |   mode: 'fixed', | ||||||
|  |   type: '1', | ||||||
|  |   space: 5, | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | const emit = defineEmits(['onSuccess', 'onError', 'onClose']); | ||||||
|  | 
 | ||||||
|  | const { | ||||||
|  |   blockSize, | ||||||
|  |   captchaType, | ||||||
|  |   explain, | ||||||
|  |   mode, | ||||||
|  |   checkCaptchaApi, | ||||||
|  |   getCaptchaApi, | ||||||
|  | } = toRefs(props); | ||||||
|  | 
 | ||||||
|  | const { proxy } = getCurrentInstance()!; | ||||||
|  | const secretKey = ref(); // 后端返回的ase加密秘钥 | ||||||
|  | const passFlag = ref(); // 是否通过的标识 | ||||||
|  | const backImgBase = ref(); // 验证码背景图片 | ||||||
|  | const blockBackImgBase = ref(); // 验证滑块的背景图片 | ||||||
|  | const backToken = ref(); // 后端返回的唯一token值 | ||||||
|  | const startMoveTime = ref(); // 移动开始的时间 | ||||||
|  | const endMovetime = ref(); // 移动结束的时间 | ||||||
|  | const tipWords = ref(); | ||||||
|  | const text = ref(); | ||||||
|  | const finishText = ref(); | ||||||
|  | const setSize = reactive({ | ||||||
|  |   barHeight: '0px', | ||||||
|  |   barWidth: '0px', | ||||||
|  |   imgHeight: '0px', | ||||||
|  |   imgWidth: '0px', | ||||||
|  | }); | ||||||
|  | const moveBlockLeft = ref(); | ||||||
|  | const leftBarWidth = ref(); | ||||||
|  | // 移动中样式 | ||||||
|  | const moveBlockBackgroundColor = ref(); | ||||||
|  | const leftBarBorderColor = ref('#ddd'); | ||||||
|  | const iconColor = ref(); | ||||||
|  | const iconClass = ref('icon-right'); | ||||||
|  | const status = ref(false); // 鼠标状态 | ||||||
|  | const isEnd = ref(false); // 是够验证完成 | ||||||
|  | const showRefresh = ref(true); | ||||||
|  | const transitionLeft = ref(); | ||||||
|  | const transitionWidth = ref(); | ||||||
|  | const startLeft = ref(0); | ||||||
|  | 
 | ||||||
|  | const barArea = computed(() => { | ||||||
|  |   return proxy?.$el.querySelector('.verify-bar-area'); | ||||||
|  | }); | ||||||
|  | function init() { | ||||||
|  |   text.value = | ||||||
|  |     explain.value === '' ? $t('ui.captcha.sliderDefaultText') : explain.value; | ||||||
|  | 
 | ||||||
|  |   getPictrue(); | ||||||
|  |   nextTick(() => { | ||||||
|  |     const { barHeight, barWidth, imgHeight, imgWidth } = resetSize(proxy); | ||||||
|  |     setSize.imgHeight = imgHeight; | ||||||
|  |     setSize.imgWidth = imgWidth; | ||||||
|  |     setSize.barHeight = barHeight; | ||||||
|  |     setSize.barWidth = barWidth; | ||||||
|  |     proxy?.$parent?.$emit('ready', proxy); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   window.removeEventListener('touchmove', move); | ||||||
|  |   window.removeEventListener('mousemove', move); | ||||||
|  | 
 | ||||||
|  |   // 鼠标松开 | ||||||
|  |   window.removeEventListener('touchend', end); | ||||||
|  |   window.removeEventListener('mouseup', end); | ||||||
|  | 
 | ||||||
|  |   window.addEventListener('touchmove', move); | ||||||
|  |   window.addEventListener('mousemove', move); | ||||||
|  | 
 | ||||||
|  |   // 鼠标松开 | ||||||
|  |   window.addEventListener('touchend', end); | ||||||
|  |   window.addEventListener('mouseup', end); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | onMounted(() => { | ||||||
|  |   // 禁止拖拽 | ||||||
|  |   init(); | ||||||
|  |   proxy?.$el.addEventListener('selectstart', () => { | ||||||
|  |     return false; | ||||||
|  |   }); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | // 鼠标按下 | ||||||
|  | function start(e: MouseEvent | TouchEvent) { | ||||||
|  |   const x = | ||||||
|  |     ((e as TouchEvent).touches | ||||||
|  |       ? (e as TouchEvent).touches[0]?.pageX | ||||||
|  |       : (e as MouseEvent).clientX) || 0; | ||||||
|  |   startLeft.value = Math.floor(x - barArea.value.getBoundingClientRect().left); | ||||||
|  |   startMoveTime.value = Date.now(); // 开始滑动的时间 | ||||||
|  |   if (isEnd.value === false) { | ||||||
|  |     text.value = ''; | ||||||
|  |     moveBlockBackgroundColor.value = '#337ab7'; | ||||||
|  |     leftBarBorderColor.value = '#337AB7'; | ||||||
|  |     iconColor.value = '#fff'; | ||||||
|  |     e.stopPropagation(); | ||||||
|  |     status.value = true; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | // 鼠标移动 | ||||||
|  | function move(e: MouseEvent | TouchEvent) { | ||||||
|  |   if (status.value && isEnd.value === false) { | ||||||
|  |     const x = | ||||||
|  |       ((e as TouchEvent).touches | ||||||
|  |         ? (e as TouchEvent).touches[0]?.pageX | ||||||
|  |         : (e as MouseEvent).clientX) || 0; | ||||||
|  |     const bar_area_left = barArea.value.getBoundingClientRect().left; | ||||||
|  |     let move_block_left = x - bar_area_left; // 小方块相对于父元素的left值 | ||||||
|  |     if ( | ||||||
|  |       move_block_left >= | ||||||
|  |       barArea.value.offsetWidth - Number.parseInt(blockSize.value.width) / 2 - 2 | ||||||
|  |     ) | ||||||
|  |       move_block_left = | ||||||
|  |         barArea.value.offsetWidth - | ||||||
|  |         Number.parseInt(blockSize.value.width) / 2 - | ||||||
|  |         2; | ||||||
|  | 
 | ||||||
|  |     if (move_block_left <= 0) | ||||||
|  |       move_block_left = Number.parseInt(blockSize.value.width) / 2; | ||||||
|  | 
 | ||||||
|  |     // 拖动后小方块的left值 | ||||||
|  |     moveBlockLeft.value = `${move_block_left - startLeft.value}px`; | ||||||
|  |     leftBarWidth.value = `${move_block_left - startLeft.value}px`; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 鼠标松开 | ||||||
|  | function end() { | ||||||
|  |   endMovetime.value = Date.now(); | ||||||
|  |   // 判断是否重合 | ||||||
|  |   if (status.value && isEnd.value === false) { | ||||||
|  |     let moveLeftDistance = Number.parseInt( | ||||||
|  |       (moveBlockLeft.value || '').replace('px', ''), | ||||||
|  |     ); | ||||||
|  |     moveLeftDistance = | ||||||
|  |       (moveLeftDistance * 310) / Number.parseInt(setSize.imgWidth); | ||||||
|  |     const data = { | ||||||
|  |       captchaType: captchaType.value, | ||||||
|  |       pointJson: secretKey.value | ||||||
|  |         ? aesEncrypt( | ||||||
|  |             JSON.stringify({ x: moveLeftDistance, y: 5 }), | ||||||
|  |             secretKey.value, | ||||||
|  |           ) | ||||||
|  |         : JSON.stringify({ x: moveLeftDistance, y: 5 }), | ||||||
|  |       token: backToken.value, | ||||||
|  |     }; | ||||||
|  |     checkCaptchaApi?.value?.(data).then((response) => { | ||||||
|  |       const res = response.data; | ||||||
|  |       if (res.repCode === '0000') { | ||||||
|  |         moveBlockBackgroundColor.value = '#5cb85c'; | ||||||
|  |         leftBarBorderColor.value = '#5cb85c'; | ||||||
|  |         iconColor.value = '#fff'; | ||||||
|  |         iconClass.value = 'icon-check'; | ||||||
|  |         showRefresh.value = false; | ||||||
|  |         isEnd.value = true; | ||||||
|  |         if (mode.value === 'pop') { | ||||||
|  |           setTimeout(() => { | ||||||
|  |             emit('onClose'); | ||||||
|  |             refresh(); | ||||||
|  |           }, 1500); | ||||||
|  |         } | ||||||
|  |         passFlag.value = true; | ||||||
|  |         tipWords.value = `${((endMovetime.value - startMoveTime.value) / 1000).toFixed(2)}s | ||||||
|  |             ${$t('ui.captcha.title')}`; | ||||||
|  |         const captchaVerification = secretKey.value | ||||||
|  |           ? aesEncrypt( | ||||||
|  |               `${backToken.value}---${JSON.stringify({ x: moveLeftDistance, y: 5 })}`, | ||||||
|  |               secretKey.value, | ||||||
|  |             ) | ||||||
|  |           : `${backToken.value}---${JSON.stringify({ x: moveLeftDistance, y: 5 })}`; | ||||||
|  |         setTimeout(() => { | ||||||
|  |           tipWords.value = ''; | ||||||
|  |           emit('onSuccess', { captchaVerification }); | ||||||
|  |           emit('onClose'); | ||||||
|  |         }, 1000); | ||||||
|  |       } else { | ||||||
|  |         moveBlockBackgroundColor.value = '#d9534f'; | ||||||
|  |         leftBarBorderColor.value = '#d9534f'; | ||||||
|  |         iconColor.value = '#fff'; | ||||||
|  |         iconClass.value = 'icon-close'; | ||||||
|  |         passFlag.value = false; | ||||||
|  |         setTimeout(() => { | ||||||
|  |           refresh(); | ||||||
|  |         }, 1000); | ||||||
|  |         emit('onError', proxy); | ||||||
|  |         tipWords.value = $t('ui.captcha.sliderRotateFailTip'); | ||||||
|  |         setTimeout(() => { | ||||||
|  |           tipWords.value = ''; | ||||||
|  |         }, 1000); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |     status.value = false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | async function refresh() { | ||||||
|  |   showRefresh.value = true; | ||||||
|  |   finishText.value = ''; | ||||||
|  | 
 | ||||||
|  |   transitionLeft.value = 'left .3s'; | ||||||
|  |   moveBlockLeft.value = 0; | ||||||
|  | 
 | ||||||
|  |   leftBarWidth.value = undefined; | ||||||
|  |   transitionWidth.value = 'width .3s'; | ||||||
|  | 
 | ||||||
|  |   leftBarBorderColor.value = '#ddd'; | ||||||
|  |   moveBlockBackgroundColor.value = '#fff'; | ||||||
|  |   iconColor.value = '#000'; | ||||||
|  |   iconClass.value = 'icon-right'; | ||||||
|  |   isEnd.value = false; | ||||||
|  | 
 | ||||||
|  |   await getPictrue(); | ||||||
|  |   setTimeout(() => { | ||||||
|  |     transitionWidth.value = ''; | ||||||
|  |     transitionLeft.value = ''; | ||||||
|  |     text.value = explain.value; | ||||||
|  |   }, 300); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 请求背景图片和验证图片 | ||||||
|  | async function getPictrue() { | ||||||
|  |   const data = { | ||||||
|  |     captchaType: captchaType.value, | ||||||
|  |   }; | ||||||
|  |   const res = await getCaptchaApi?.value?.(data); | ||||||
|  | 
 | ||||||
|  |   if (res?.data?.repCode === '0000') { | ||||||
|  |     backImgBase.value = `data:image/png;base64,${res?.data?.repData?.originalImageBase64}`; | ||||||
|  |     blockBackImgBase.value = `data:image/png;base64,${res?.data?.repData?.jigsawImageBase64}`; | ||||||
|  |     backToken.value = res.data.repData.token; | ||||||
|  |     secretKey.value = res.data.repData.secretKey; | ||||||
|  |   } else { | ||||||
|  |     tipWords.value = res?.data?.repMsg; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | defineExpose({ | ||||||
|  |   init, | ||||||
|  |   refresh, | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |   <div style="position: relative"> | ||||||
|  |     <div | ||||||
|  |       v-if="type === '2'" | ||||||
|  |       :style="{ height: `${Number.parseInt(setSize.imgHeight) + space}px` }" | ||||||
|  |       class="verify-img-out" | ||||||
|  |     > | ||||||
|  |       <div | ||||||
|  |         :style="{ width: setSize.imgWidth, height: setSize.imgHeight }" | ||||||
|  |         class="verify-img-panel" | ||||||
|  |       > | ||||||
|  |         <img | ||||||
|  |           :src="backImgBase" | ||||||
|  |           alt="" | ||||||
|  |           style="display: block; width: 100%; height: 100%" | ||||||
|  |         /> | ||||||
|  |         <div v-show="showRefresh" class="verify-refresh" @click="refresh"> | ||||||
|  |           <i class="iconfont icon-refresh"></i> | ||||||
|  |         </div> | ||||||
|  |         <transition name="tips"> | ||||||
|  |           <span | ||||||
|  |             v-if="tipWords" | ||||||
|  |             :class="passFlag ? 'suc-bg' : 'err-bg'" | ||||||
|  |             class="verify-tips" | ||||||
|  |           > | ||||||
|  |             {{ tipWords }} | ||||||
|  |           </span> | ||||||
|  |         </transition> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <!-- 公共部分 --> | ||||||
|  |     <div | ||||||
|  |       :style="{ | ||||||
|  |         width: setSize.imgWidth, | ||||||
|  |         height: barSize.height, | ||||||
|  |         'line-height': barSize.height, | ||||||
|  |       }" | ||||||
|  |       class="verify-bar-area" | ||||||
|  |     > | ||||||
|  |       <span class="verify-msg" v-text="text"></span> | ||||||
|  |       <div | ||||||
|  |         :style="{ | ||||||
|  |           width: leftBarWidth !== undefined ? leftBarWidth : barSize.height, | ||||||
|  |           height: barSize.height, | ||||||
|  |           'border-color': leftBarBorderColor, | ||||||
|  |           transition: transitionWidth, | ||||||
|  |         }" | ||||||
|  |         class="verify-left-bar" | ||||||
|  |       > | ||||||
|  |         <span class="verify-msg" v-text="finishText"></span> | ||||||
|  |         <div | ||||||
|  |           :style="{ | ||||||
|  |             width: barSize.height, | ||||||
|  |             height: barSize.height, | ||||||
|  |             'background-color': moveBlockBackgroundColor, | ||||||
|  |             left: moveBlockLeft, | ||||||
|  |             transition: transitionLeft, | ||||||
|  |           }" | ||||||
|  |           class="verify-move-block" | ||||||
|  |           @mousedown="start" | ||||||
|  |           @touchstart="start" | ||||||
|  |         > | ||||||
|  |           <i | ||||||
|  |             :class="[iconClass]" | ||||||
|  |             :style="{ color: iconColor }" | ||||||
|  |             class="iconfont verify-icon" | ||||||
|  |           ></i> | ||||||
|  |           <div | ||||||
|  |             v-if="type === '2'" | ||||||
|  |             :style="{ | ||||||
|  |               width: `${Math.floor((Number.parseInt(setSize.imgWidth) * 47) / 310)}px`, | ||||||
|  |               height: setSize.imgHeight, | ||||||
|  |               top: `-${Number.parseInt(setSize.imgHeight) + space}px`, | ||||||
|  |               'background-size': `${setSize.imgWidth} ${setSize.imgHeight}`, | ||||||
|  |             }" | ||||||
|  |             class="verify-sub-block" | ||||||
|  |           > | ||||||
|  |             <img | ||||||
|  |               :src="blockBackImgBase" | ||||||
|  |               alt="" | ||||||
|  |               style=" | ||||||
|  |                 display: block; | ||||||
|  |                 width: 100%; | ||||||
|  |                 height: 100%; | ||||||
|  |                 -webkit-user-drag: none; | ||||||
|  |               " | ||||||
|  |             /> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  | @ -0,0 +1,3 @@ | ||||||
|  | export { default as VerifyPoints } from './VerifyPoints.vue'; | ||||||
|  | 
 | ||||||
|  | export { default as VerifySlide } from './VerifySlide.vue'; | ||||||
|  | @ -0,0 +1,150 @@ | ||||||
|  | <script setup lang="ts"> | ||||||
|  | /** | ||||||
|  |  * Verify 验证码组件 | ||||||
|  |  * @description 分发验证码使用 | ||||||
|  |  */ | ||||||
|  | import type { VerificationProps } from './types'; | ||||||
|  | 
 | ||||||
|  | import { defineAsyncComponent, markRaw, ref, toRefs, watchEffect } from 'vue'; | ||||||
|  | 
 | ||||||
|  | import './style/verify.css'; | ||||||
|  | 
 | ||||||
|  | defineOptions({ | ||||||
|  |   name: 'Verification', | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | const props = withDefaults(defineProps<VerificationProps>(), { | ||||||
|  |   arith: 0, | ||||||
|  |   barSize: () => ({ | ||||||
|  |     height: '40px', | ||||||
|  |     width: '310px', | ||||||
|  |   }), | ||||||
|  |   blockSize: () => ({ | ||||||
|  |     height: '50px', | ||||||
|  |     width: '50px', | ||||||
|  |   }), | ||||||
|  |   captchaType: 'blockPuzzle', | ||||||
|  |   explain: '', | ||||||
|  |   figure: 0, | ||||||
|  |   imgSize: () => ({ | ||||||
|  |     height: '155px', | ||||||
|  |     width: '310px', | ||||||
|  |   }), | ||||||
|  |   mode: 'fixed', | ||||||
|  |   space: 5, | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | const emit = defineEmits(['onSuccess', 'onError', 'onClose', 'onReady']); | ||||||
|  | 
 | ||||||
|  | const VerifyPoints = defineAsyncComponent( | ||||||
|  |   () => import('./Verify/VerifyPoints.vue'), | ||||||
|  | ); | ||||||
|  | const VerifySlide = defineAsyncComponent( | ||||||
|  |   () => import('./Verify/VerifySlide.vue'), | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | const { captchaType, mode, checkCaptchaApi, getCaptchaApi } = toRefs(props); | ||||||
|  | const verifyType = ref(); | ||||||
|  | const componentType = ref(); | ||||||
|  | 
 | ||||||
|  | const instance = ref<InstanceType<typeof VerifyPoints | typeof VerifySlide>>(); | ||||||
|  | 
 | ||||||
|  | const showBox = ref(false); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * refresh | ||||||
|  |  * @description 刷新 | ||||||
|  |  */ | ||||||
|  | const refresh = () => { | ||||||
|  |   if (instance.value && instance.value.refresh) instance.value.refresh(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const show = () => { | ||||||
|  |   if (mode.value === 'pop') showBox.value = true; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const onError = (proxy: any) => { | ||||||
|  |   emit('onError', proxy); | ||||||
|  |   refresh(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const onReady = (proxy: any) => { | ||||||
|  |   emit('onReady', proxy); | ||||||
|  |   refresh(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const onClose = () => { | ||||||
|  |   emit('onClose'); | ||||||
|  |   showBox.value = false; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const onSuccess = (data: any) => { | ||||||
|  |   emit('onSuccess', data); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | watchEffect(() => { | ||||||
|  |   switch (captchaType.value) { | ||||||
|  |     case 'blockPuzzle': { | ||||||
|  |       verifyType.value = '2'; | ||||||
|  |       componentType.value = markRaw(VerifySlide); | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |     case 'clickWord': { | ||||||
|  |       verifyType.value = ''; | ||||||
|  |       componentType.value = markRaw(VerifyPoints); | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | defineExpose({ | ||||||
|  |   onClose, | ||||||
|  |   onError, | ||||||
|  |   onReady, | ||||||
|  |   onSuccess, | ||||||
|  |   show, | ||||||
|  |   refresh, | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |   <div v-show="showBox"> | ||||||
|  |     <div | ||||||
|  |       :class="mode === 'pop' ? 'verifybox' : ''" | ||||||
|  |       :style="{ 'max-width': `${parseInt(imgSize.width) + 20}px` }" | ||||||
|  |     > | ||||||
|  |       <div v-if="mode === 'pop'" class="verifybox-top"> | ||||||
|  |         {{ $t('ui.captcha.title') }} | ||||||
|  |         <span class="verifybox-close" @click="onClose"> | ||||||
|  |           <i class="iconfont icon-close"></i> | ||||||
|  |         </span> | ||||||
|  |       </div> | ||||||
|  |       <div | ||||||
|  |         :style="{ padding: mode === 'pop' ? '10px' : '0' }" | ||||||
|  |         class="verifybox-bottom" | ||||||
|  |       > | ||||||
|  |         <component | ||||||
|  |           :is="componentType" | ||||||
|  |           v-if="componentType" | ||||||
|  |           ref="instance" | ||||||
|  |           :arith="arith" | ||||||
|  |           :bar-size="barSize" | ||||||
|  |           :block-size="blockSize" | ||||||
|  |           :captcha-type="captchaType" | ||||||
|  |           :check-captcha-api="checkCaptchaApi" | ||||||
|  |           :explain="explain" | ||||||
|  |           :figure="figure" | ||||||
|  |           :get-captcha-api="getCaptchaApi" | ||||||
|  |           :img-size="imgSize" | ||||||
|  |           :mode="mode" | ||||||
|  |           :space="space" | ||||||
|  |           :type="verifyType" | ||||||
|  |           @on-close="onClose" | ||||||
|  |           @on-error="onError" | ||||||
|  |           @on-ready="onReady" | ||||||
|  |           @on-success="onSuccess" | ||||||
|  |         /> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										25
									
								
								packages/effects/common-ui/src/components/captcha/verification/types/index.d.ts
								
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										25
									
								
								packages/effects/common-ui/src/components/captcha/verification/types/index.d.ts
								
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,25 @@ | ||||||
|  | interface VerificationProps { | ||||||
|  |   arith?: number; | ||||||
|  |   barSize?: { | ||||||
|  |     height: string; | ||||||
|  |     width: string; | ||||||
|  |   }; | ||||||
|  |   blockSize?: { | ||||||
|  |     height: string; | ||||||
|  |     width: string; | ||||||
|  |   }; | ||||||
|  |   captchaType?: 'blockPuzzle' | 'clickWord'; | ||||||
|  |   explain?: string; | ||||||
|  |   figure?: number; | ||||||
|  |   imgSize?: { | ||||||
|  |     height: string; | ||||||
|  |     width: string; | ||||||
|  |   }; | ||||||
|  |   mode?: 'fixed' | 'pop'; | ||||||
|  |   space?: number; | ||||||
|  |   type?: '1' | '2'; | ||||||
|  |   checkCaptchaApi?: (data: any) => Promise<any>; | ||||||
|  |   getCaptchaApi?: (data: any) => Promise<any>; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export type { VerificationProps }; | ||||||
|  | @ -0,0 +1,15 @@ | ||||||
|  | import CryptoJS from 'crypto-js'; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @word 要加密的内容 | ||||||
|  |  * @keyWord String  服务器随机返回的关键字 | ||||||
|  |  */ | ||||||
|  | export function aesEncrypt(word: string, keyWord = 'XwKsGlMcdPMEhR1B') { | ||||||
|  |   const key = CryptoJS.enc.Utf8.parse(keyWord); | ||||||
|  |   const src = CryptoJS.enc.Utf8.parse(word); | ||||||
|  |   const encrypted = CryptoJS.AES.encrypt(src, key, { | ||||||
|  |     mode: CryptoJS.mode.ECB, | ||||||
|  |     padding: CryptoJS.pad.Pkcs7, | ||||||
|  |   }); | ||||||
|  |   return encrypted.toString(); | ||||||
|  | } | ||||||
|  | @ -0,0 +1,102 @@ | ||||||
|  | export function resetSize(vm: any) { | ||||||
|  |   const EmployeeWindow = window as any; | ||||||
|  |   const parentWidth = | ||||||
|  |     vm.$el.parentNode.offsetWidth || EmployeeWindow.offsetWidth; | ||||||
|  |   const parentHeight = | ||||||
|  |     vm.$el.parentNode.offsetHeight || EmployeeWindow.offsetHeight; | ||||||
|  |   const img_width = vm.imgSize.width.includes('%') | ||||||
|  |     ? `${(Number.parseInt(vm.imgSize.width) / 100) * parentWidth}px` | ||||||
|  |     : vm.imgSize.width; | ||||||
|  | 
 | ||||||
|  |   const img_height = vm.imgSize.height.includes('%') | ||||||
|  |     ? `${(Number.parseInt(vm.imgSize.height) / 100) * parentHeight}px` | ||||||
|  |     : vm.imgSize.height; | ||||||
|  | 
 | ||||||
|  |   const bar_width = vm.barSize.width.includes('%') | ||||||
|  |     ? `${(Number.parseInt(vm.barSize.width) / 100) * parentWidth}px` | ||||||
|  |     : vm.barSize.width; | ||||||
|  | 
 | ||||||
|  |   const bar_height = vm.barSize.height.includes('%') | ||||||
|  |     ? `${(Number.parseInt(vm.barSize.height) / 100) * parentHeight}px` | ||||||
|  |     : vm.barSize.height; | ||||||
|  | 
 | ||||||
|  |   return { | ||||||
|  |     barHeight: bar_height, | ||||||
|  |     barWidth: bar_width, | ||||||
|  |     imgHeight: img_height, | ||||||
|  |     imgWidth: img_width, | ||||||
|  |   }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export const _code_chars = [ | ||||||
|  |   1, | ||||||
|  |   2, | ||||||
|  |   3, | ||||||
|  |   4, | ||||||
|  |   5, | ||||||
|  |   6, | ||||||
|  |   7, | ||||||
|  |   8, | ||||||
|  |   9, | ||||||
|  |   'a', | ||||||
|  |   'b', | ||||||
|  |   'c', | ||||||
|  |   'd', | ||||||
|  |   'e', | ||||||
|  |   'f', | ||||||
|  |   'g', | ||||||
|  |   'h', | ||||||
|  |   'i', | ||||||
|  |   'j', | ||||||
|  |   'k', | ||||||
|  |   'l', | ||||||
|  |   'm', | ||||||
|  |   'n', | ||||||
|  |   'o', | ||||||
|  |   'p', | ||||||
|  |   'q', | ||||||
|  |   'r', | ||||||
|  |   's', | ||||||
|  |   't', | ||||||
|  |   'u', | ||||||
|  |   'v', | ||||||
|  |   'w', | ||||||
|  |   'x', | ||||||
|  |   'y', | ||||||
|  |   'z', | ||||||
|  |   'A', | ||||||
|  |   'B', | ||||||
|  |   'C', | ||||||
|  |   'D', | ||||||
|  |   'E', | ||||||
|  |   'F', | ||||||
|  |   'G', | ||||||
|  |   'H', | ||||||
|  |   'I', | ||||||
|  |   'J', | ||||||
|  |   'K', | ||||||
|  |   'L', | ||||||
|  |   'M', | ||||||
|  |   'N', | ||||||
|  |   'O', | ||||||
|  |   'P', | ||||||
|  |   'Q', | ||||||
|  |   'R', | ||||||
|  |   'S', | ||||||
|  |   'T', | ||||||
|  |   'U', | ||||||
|  |   'V', | ||||||
|  |   'W', | ||||||
|  |   'X', | ||||||
|  |   'Y', | ||||||
|  |   'Z', | ||||||
|  | ]; | ||||||
|  | export const _code_color1 = ['#fffff0', '#f0ffff', '#f0fff0', '#fff0f0']; | ||||||
|  | export const _code_color2 = [ | ||||||
|  |   '#FF0033', | ||||||
|  |   '#006699', | ||||||
|  |   '#993366', | ||||||
|  |   '#FF9900', | ||||||
|  |   '#66CC66', | ||||||
|  |   '#FF33CC', | ||||||
|  | ]; | ||||||
|  | @ -78,6 +78,9 @@ catalogs: | ||||||
|     '@types/archiver': |     '@types/archiver': | ||||||
|       specifier: ^6.0.3 |       specifier: ^6.0.3 | ||||||
|       version: 6.0.3 |       version: 6.0.3 | ||||||
|  |     '@types/crypto-js': | ||||||
|  |       specifier: ^4.2.2 | ||||||
|  |       version: 4.2.2 | ||||||
|     '@types/eslint': |     '@types/eslint': | ||||||
|       specifier: ^9.6.1 |       specifier: ^9.6.1 | ||||||
|       version: 9.6.1 |       version: 9.6.1 | ||||||
|  | @ -183,6 +186,9 @@ catalogs: | ||||||
|     cross-env: |     cross-env: | ||||||
|       specifier: ^7.0.3 |       specifier: ^7.0.3 | ||||||
|       version: 7.0.3 |       version: 7.0.3 | ||||||
|  |     crypto-js: | ||||||
|  |       specifier: ^4.2.0 | ||||||
|  |       version: 4.2.0 | ||||||
|     cspell: |     cspell: | ||||||
|       specifier: ^8.17.5 |       specifier: ^8.17.5 | ||||||
|       version: 8.17.5 |       version: 8.17.5 | ||||||
|  | @ -1530,6 +1536,9 @@ importers: | ||||||
|       '@vueuse/integrations': |       '@vueuse/integrations': | ||||||
|         specifier: 'catalog:' |         specifier: 'catalog:' | ||||||
|         version: 12.8.2(async-validator@4.2.5)(axios@1.8.2)(change-case@5.4.4)(focus-trap@7.6.4)(nprogress@0.2.0)(qrcode@1.5.4)(sortablejs@1.15.6)(typescript@5.8.2) |         version: 12.8.2(async-validator@4.2.5)(axios@1.8.2)(change-case@5.4.4)(focus-trap@7.6.4)(nprogress@0.2.0)(qrcode@1.5.4)(sortablejs@1.15.6)(typescript@5.8.2) | ||||||
|  |       crypto-js: | ||||||
|  |         specifier: 'catalog:' | ||||||
|  |         version: 4.2.0 | ||||||
|       qrcode: |       qrcode: | ||||||
|         specifier: 'catalog:' |         specifier: 'catalog:' | ||||||
|         version: 1.5.4 |         version: 1.5.4 | ||||||
|  | @ -1549,6 +1558,9 @@ importers: | ||||||
|         specifier: 'catalog:' |         specifier: 'catalog:' | ||||||
|         version: 6.6.0(vue@3.5.13(typescript@5.8.2)) |         version: 6.6.0(vue@3.5.13(typescript@5.8.2)) | ||||||
|     devDependencies: |     devDependencies: | ||||||
|  |       '@types/crypto-js': | ||||||
|  |         specifier: 'catalog:' | ||||||
|  |         version: 4.2.2 | ||||||
|       '@types/qrcode': |       '@types/qrcode': | ||||||
|         specifier: 'catalog:' |         specifier: 'catalog:' | ||||||
|         version: 1.5.5 |         version: 1.5.5 | ||||||
|  | @ -3534,22 +3546,22 @@ packages: | ||||||
|     resolution: {integrity: sha512-nmG512G8QOABsserleechwHGZxzKSAlggGf9hQX0nltvSwyKNVuB/4o6iFeG2OnjXK253r8p8eSDOZf8PgFdWw==} |     resolution: {integrity: sha512-nmG512G8QOABsserleechwHGZxzKSAlggGf9hQX0nltvSwyKNVuB/4o6iFeG2OnjXK253r8p8eSDOZf8PgFdWw==} | ||||||
|     engines: {node: '>= 16'} |     engines: {node: '>= 16'} | ||||||
| 
 | 
 | ||||||
|   '@intlify/message-compiler@11.0.0-rc.1': |  | ||||||
|     resolution: {integrity: sha512-TGw2uBfuTFTegZf/BHtUQBEKxl7Q/dVGLoqRIdw8lFsp9g/53sYn5iD+0HxIzdYjbWL6BTJMXCPUHp9PxDTRPw==} |  | ||||||
|     engines: {node: '>= 16'} |  | ||||||
| 
 |  | ||||||
|   '@intlify/message-compiler@11.1.2': |   '@intlify/message-compiler@11.1.2': | ||||||
|     resolution: {integrity: sha512-T/xbNDzi+Yv0Qn2Dfz2CWCAJiwNgU5d95EhhAEf4YmOgjCKktpfpiUSmLcBvK1CtLpPQ85AMMQk/2NCcXnNj1g==} |     resolution: {integrity: sha512-T/xbNDzi+Yv0Qn2Dfz2CWCAJiwNgU5d95EhhAEf4YmOgjCKktpfpiUSmLcBvK1CtLpPQ85AMMQk/2NCcXnNj1g==} | ||||||
|     engines: {node: '>= 16'} |     engines: {node: '>= 16'} | ||||||
| 
 | 
 | ||||||
|   '@intlify/shared@11.0.0-rc.1': |   '@intlify/message-compiler@12.0.0-alpha.2': | ||||||
|     resolution: {integrity: sha512-8tR1xe7ZEbkabTuE/tNhzpolygUn9OaYp9yuYAF4MgDNZg06C3Qny80bes2/e9/Wm3aVkPUlCw6WgU7mQd0yEg==} |     resolution: {integrity: sha512-PD9C+oQbb7BF52hec0+vLnScaFkvnfX+R7zSbODYuRo/E2niAtGmHd0wPvEMsDhf9Z9b8f/qyDsVeZnD/ya9Ug==} | ||||||
|     engines: {node: '>= 16'} |     engines: {node: '>= 16'} | ||||||
| 
 | 
 | ||||||
|   '@intlify/shared@11.1.2': |   '@intlify/shared@11.1.2': | ||||||
|     resolution: {integrity: sha512-dF2iMMy8P9uKVHV/20LA1ulFLL+MKSbfMiixSmn6fpwqzvix38OIc7ebgnFbBqElvghZCW9ACtzKTGKsTGTWGA==} |     resolution: {integrity: sha512-dF2iMMy8P9uKVHV/20LA1ulFLL+MKSbfMiixSmn6fpwqzvix38OIc7ebgnFbBqElvghZCW9ACtzKTGKsTGTWGA==} | ||||||
|     engines: {node: '>= 16'} |     engines: {node: '>= 16'} | ||||||
| 
 | 
 | ||||||
|  |   '@intlify/shared@12.0.0-alpha.2': | ||||||
|  |     resolution: {integrity: sha512-P2DULVX9nz3y8zKNqLw9Es1aAgQ1JGC+kgpx5q7yLmrnAKkPR5MybQWoEhxanefNJgUY5ehsgo+GKif59SrncA==} | ||||||
|  |     engines: {node: '>= 16'} | ||||||
|  | 
 | ||||||
|   '@intlify/unplugin-vue-i18n@6.0.3': |   '@intlify/unplugin-vue-i18n@6.0.3': | ||||||
|     resolution: {integrity: sha512-9ZDjBlhUHtgjRl23TVcgfJttgu8cNepwVhWvOv3mUMRDAhjW0pur1mWKEUKr1I8PNwE4Gvv2IQ1xcl4RL0nG0g==} |     resolution: {integrity: sha512-9ZDjBlhUHtgjRl23TVcgfJttgu8cNepwVhWvOv3mUMRDAhjW0pur1mWKEUKr1I8PNwE4Gvv2IQ1xcl4RL0nG0g==} | ||||||
|     engines: {node: '>= 18'} |     engines: {node: '>= 18'} | ||||||
|  | @ -4232,6 +4244,9 @@ packages: | ||||||
|   '@types/conventional-commits-parser@5.0.1': |   '@types/conventional-commits-parser@5.0.1': | ||||||
|     resolution: {integrity: sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ==} |     resolution: {integrity: sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ==} | ||||||
| 
 | 
 | ||||||
|  |   '@types/crypto-js@4.2.2': | ||||||
|  |     resolution: {integrity: sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==} | ||||||
|  | 
 | ||||||
|   '@types/doctrine@0.0.9': |   '@types/doctrine@0.0.9': | ||||||
|     resolution: {integrity: sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==} |     resolution: {integrity: sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==} | ||||||
| 
 | 
 | ||||||
|  | @ -5367,6 +5382,9 @@ packages: | ||||||
|   crossws@0.3.4: |   crossws@0.3.4: | ||||||
|     resolution: {integrity: sha512-uj0O1ETYX1Bh6uSgktfPvwDiPYGQ3aI4qVsaC/LWpkIzGj1nUYm5FK3K+t11oOlpN01lGbprFCH4wBlKdJjVgw==} |     resolution: {integrity: sha512-uj0O1ETYX1Bh6uSgktfPvwDiPYGQ3aI4qVsaC/LWpkIzGj1nUYm5FK3K+t11oOlpN01lGbprFCH4wBlKdJjVgw==} | ||||||
| 
 | 
 | ||||||
|  |   crypto-js@4.2.0: | ||||||
|  |     resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} | ||||||
|  | 
 | ||||||
|   crypto-random-string@2.0.0: |   crypto-random-string@2.0.0: | ||||||
|     resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} |     resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} | ||||||
|     engines: {node: '>=8'} |     engines: {node: '>=8'} | ||||||
|  | @ -12279,8 +12297,8 @@ snapshots: | ||||||
| 
 | 
 | ||||||
|   '@intlify/bundle-utils@10.0.0(vue-i18n@11.1.2(vue@3.5.13(typescript@5.8.2)))': |   '@intlify/bundle-utils@10.0.0(vue-i18n@11.1.2(vue@3.5.13(typescript@5.8.2)))': | ||||||
|     dependencies: |     dependencies: | ||||||
|       '@intlify/message-compiler': 11.0.0-rc.1 |       '@intlify/message-compiler': 12.0.0-alpha.2 | ||||||
|       '@intlify/shared': 11.0.0-rc.1 |       '@intlify/shared': 12.0.0-alpha.2 | ||||||
|       acorn: 8.14.1 |       acorn: 8.14.1 | ||||||
|       escodegen: 2.1.0 |       escodegen: 2.1.0 | ||||||
|       estree-walker: 2.0.2 |       estree-walker: 2.0.2 | ||||||
|  | @ -12296,20 +12314,20 @@ snapshots: | ||||||
|       '@intlify/message-compiler': 11.1.2 |       '@intlify/message-compiler': 11.1.2 | ||||||
|       '@intlify/shared': 11.1.2 |       '@intlify/shared': 11.1.2 | ||||||
| 
 | 
 | ||||||
|   '@intlify/message-compiler@11.0.0-rc.1': |  | ||||||
|     dependencies: |  | ||||||
|       '@intlify/shared': 11.0.0-rc.1 |  | ||||||
|       source-map-js: 1.2.1 |  | ||||||
| 
 |  | ||||||
|   '@intlify/message-compiler@11.1.2': |   '@intlify/message-compiler@11.1.2': | ||||||
|     dependencies: |     dependencies: | ||||||
|       '@intlify/shared': 11.1.2 |       '@intlify/shared': 11.1.2 | ||||||
|       source-map-js: 1.2.1 |       source-map-js: 1.2.1 | ||||||
| 
 | 
 | ||||||
|   '@intlify/shared@11.0.0-rc.1': {} |   '@intlify/message-compiler@12.0.0-alpha.2': | ||||||
|  |     dependencies: | ||||||
|  |       '@intlify/shared': 12.0.0-alpha.2 | ||||||
|  |       source-map-js: 1.2.1 | ||||||
| 
 | 
 | ||||||
|   '@intlify/shared@11.1.2': {} |   '@intlify/shared@11.1.2': {} | ||||||
| 
 | 
 | ||||||
|  |   '@intlify/shared@12.0.0-alpha.2': {} | ||||||
|  | 
 | ||||||
|   '@intlify/unplugin-vue-i18n@6.0.3(@vue/compiler-dom@3.5.13)(eslint@9.22.0(jiti@2.4.2))(rollup@4.35.0)(typescript@5.8.2)(vue-i18n@11.1.2(vue@3.5.13(typescript@5.8.2)))(vue@3.5.13(typescript@5.8.2))': |   '@intlify/unplugin-vue-i18n@6.0.3(@vue/compiler-dom@3.5.13)(eslint@9.22.0(jiti@2.4.2))(rollup@4.35.0)(typescript@5.8.2)(vue-i18n@11.1.2(vue@3.5.13(typescript@5.8.2)))(vue@3.5.13(typescript@5.8.2))': | ||||||
|     dependencies: |     dependencies: | ||||||
|       '@eslint-community/eslint-utils': 4.4.1(eslint@9.22.0(jiti@2.4.2)) |       '@eslint-community/eslint-utils': 4.4.1(eslint@9.22.0(jiti@2.4.2)) | ||||||
|  | @ -13055,6 +13073,8 @@ snapshots: | ||||||
|     dependencies: |     dependencies: | ||||||
|       '@types/node': 22.13.10 |       '@types/node': 22.13.10 | ||||||
| 
 | 
 | ||||||
|  |   '@types/crypto-js@4.2.2': {} | ||||||
|  | 
 | ||||||
|   '@types/doctrine@0.0.9': {} |   '@types/doctrine@0.0.9': {} | ||||||
| 
 | 
 | ||||||
|   '@types/eslint@9.6.1': |   '@types/eslint@9.6.1': | ||||||
|  | @ -14410,6 +14430,8 @@ snapshots: | ||||||
|     dependencies: |     dependencies: | ||||||
|       uncrypto: 0.1.3 |       uncrypto: 0.1.3 | ||||||
| 
 | 
 | ||||||
|  |   crypto-js@4.2.0: {} | ||||||
|  | 
 | ||||||
|   crypto-random-string@2.0.0: {} |   crypto-random-string@2.0.0: {} | ||||||
| 
 | 
 | ||||||
|   cspell-config-lib@8.17.5: |   cspell-config-lib@8.17.5: | ||||||
|  |  | ||||||
|  | @ -50,6 +50,7 @@ catalog: | ||||||
|   '@types/postcss-import': ^14.0.3 |   '@types/postcss-import': ^14.0.3 | ||||||
|   '@types/qrcode': ^1.5.5 |   '@types/qrcode': ^1.5.5 | ||||||
|   '@types/sortablejs': ^1.15.8 |   '@types/sortablejs': ^1.15.8 | ||||||
|  |   '@types/crypto-js': ^4.2.2 | ||||||
|   '@typescript-eslint/eslint-plugin': ^8.26.0 |   '@typescript-eslint/eslint-plugin': ^8.26.0 | ||||||
|   '@typescript-eslint/parser': ^8.26.0 |   '@typescript-eslint/parser': ^8.26.0 | ||||||
|   '@vee-validate/zod': ^4.15.0 |   '@vee-validate/zod': ^4.15.0 | ||||||
|  | @ -76,6 +77,7 @@ catalog: | ||||||
|   commitlint-plugin-function-rules: ^4.0.1 |   commitlint-plugin-function-rules: ^4.0.1 | ||||||
|   consola: ^3.4.0 |   consola: ^3.4.0 | ||||||
|   cross-env: ^7.0.3 |   cross-env: ^7.0.3 | ||||||
|  |   crypto-js: ^4.2.0 | ||||||
|   cspell: ^8.17.5 |   cspell: ^8.17.5 | ||||||
|   cssnano: ^7.0.6 |   cssnano: ^7.0.6 | ||||||
|   cz-git: ^1.11.1 |   cz-git: ^1.11.1 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 YunaiV
						YunaiV