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