Files
tonePage/tonecn/src/components/Common/RotationVerification.vue
2024-09-29 23:22:04 +08:00

199 lines
9.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang='ts'>
/**
* 旋转图像验证码组件
* @event success 验证成功
* @event fail 验证失败
* @requires ServerSDK
* @since 1.0.2
*/
import { request, type BaseResponseData } from '@/lib/request';
import { onBeforeMount, onMounted, ref } from 'vue';
let imageBase64 = ref('');
const emit = defineEmits(['fail', 'success'])
let onVerifying = ref(false);
let onVerifyFail = ref(false);
onBeforeMount(async () => {
try {
let res: BaseResponseData = await request.get('captcha')
localStorage.setItem('captcha-session', res.data.session)
imageBase64.value = res.data.imgPreStr + res.data.img;
} catch (error) {
console.log("获取图像验证码失败:" + error);
emit('fail');
}
})
onMounted(() => {
let slider = document.getElementById('RV-slider');
let imageEle = document.getElementById('RV-image');
let isDragging = false;// 正在移动标志位
let silderMoveable = true;// 是否可以开始移动标识位
let startX: number;
let deltaX: number;// 拖动距离
if(!slider || !imageEle){
throw new Error('element is null')
}
slider.addEventListener('mousedown', function (e) {
if (silderMoveable) {
isDragging = true;
startX = e.clientX;
onVerifyFail.value = false;
}
})
slider.addEventListener('touchstart', function (e) {
if (silderMoveable) {
e.preventDefault();
isDragging = true;
startX = e.touches[0].clientX;
onVerifyFail.value = false;
}
}, { passive: false });
document.addEventListener('mousemove', function (e) {
if (isDragging) {
silderMoveable = false;// 产生了位移,则需等待验证后才可再次移动
deltaX = e.clientX - startX;
// 对位移距离限幅
if (deltaX < 0)
deltaX = 0;
if (deltaX > 200)
deltaX = 200;
// 调整滑块条位置样式
slider.style.transform = ` translateX(${deltaX}px)`;
// 调整图片旋转样式 200 -> 360映射 y = 9/5x
imageEle.style.transform = `rotate(${deltaX * 9 / 5}deg)`
}
});
document.addEventListener('touchmove', function (e) {
if (isDragging) {
e.preventDefault();
silderMoveable = false;
deltaX = e.touches[0].clientX - startX;
if (deltaX < 0) deltaX = 0;
if (deltaX > 200) deltaX = 200;
slider.style.transform = `translateX(${deltaX}px)`;
imageEle.style.transform = `rotate(${deltaX * 9 / 5}deg)`;
}
}, { passive: false });
document.addEventListener('mouseup', async () => {
if (isDragging) {
isDragging = false;
if (!deltaX) {
silderMoveable = true;// 位移距离为0无需验证可以继续移动
} else {
try {
onVerifying.value = true;
let res: BaseResponseData = await request.post('checkCaptcha', {
session: localStorage.getItem('captcha-session'),
rotateDeg: deltaX * 9 / 5
})
switch (res.code) {
case 0:
// 验证成功
emit('success');
break;
case -5002:
// 可以再试一次
onVerifyFail.value = true;
slider.style.transition = "transform 0.6s";
slider.style.transform = "translateX(0px)";
imageEle.style.transition = "transform 0.6s";
imageEle.style.transform = "rotate(0deg)";
setTimeout(() => {
isDragging = false;
silderMoveable = true;
slider.style.transition = "transform 0s";
imageEle.style.transition = "transform 0s";
}, 600);
break;
default:
console.log('验证session过期、不存在、服务器错误')
emit('fail');
break;
}
} catch (error) {
console.log("图像验证码错误:" + error);
emit('fail');
} finally {
onVerifying.value = false;
}
}
}
});
document.addEventListener('touchend', async () => {
if (isDragging) {
isDragging = false;
if (!deltaX) {
silderMoveable = true;// 位移距离为0无需验证可以继续移动
} else {
try {
onVerifying.value = true;
let res: BaseResponseData = await request.post('checkCaptcha', {
session: localStorage.getItem('captcha-session'),
rotateDeg: deltaX * 9 / 5
})
switch (res.code) {
case 0:
// 验证成功
emit('success');
break;
case -5002:
// 可以再试一次
onVerifyFail.value = true;
slider.style.transition = "transform 0.6s";
slider.style.transform = "translateX(0px)";
imageEle.style.transition = "transform 0.6s";
imageEle.style.transform = "rotate(0deg)";
setTimeout(() => {
isDragging = false;
silderMoveable = true;
slider.style.transition = "transform 0s";
imageEle.style.transition = "transform 0s";
}, 600);
break;
default:
console.log('验证session过期、不存在、服务器错误')
emit('fail');
break;
}
} catch (error) {
console.log("图像验证码错误:" + error);
emit('fail');
} finally {
onVerifying.value = false;
}
}
}
});
})
</script>
<template>
<transition name="el-fade-in-linear">
<div class="fixed w-full h-full inset-0 bg-[#00000022] z-[2000] flex justify-center items-center" @click="$emit('fail')">
<div class="w-[300px] h-[400px] bg-white flex flex-col items-center rounded-[15px]" onclick="event.stopPropagation()">
<div class="mt-[25px] text-[#888]">安全验证</div>
<div class="mt-[8px]">{{ onVerifying ? "正在验证,请稍后..." : (onVerifyFail ? "验证失败,请再试一次" : "拖动滑块,使图片角度为水平")
}}
</div>
<div class="mt-[28px] w-[160px] h-[160px] rounded-full flex justify-center items-center overflow-hidden">
<img class="w-[226px] h-[226px] bg-gray-400 object-cover" :src="imageBase64" alt="" id="RV-image">
</div>
<div class="w-[240px] h-[40px] rounded-[20px] bg-slate-200 mt-[25px] flex items-center">
<div class="w-[45px] h-[45px] leading-[45px] bg-white rounded-full shadow-md text-center cursor-pointer relative translate-x-0" id="RV-slider">
<svg t="1706696449802" class="absolute left-[14px] top-[14px]" viewBox="0 0 1024 1024" fill="#666" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="1924" width="18" height="18">
<path
d="M567.32505 547.18536c20.970614-21.479197 20.970614-56.307424 0-77.790714L185.251168 77.115332c-20.971637-21.47715-54.975079-21.47715-75.948763 0-20.973684 21.484314-20.973684 56.30947 0 77.793784l344.188016 353.383446-344.188016 353.384469c-20.973684 21.484314-20.973684 56.311517 0 77.79276 20.971637 21.482267 54.975079 21.482267 75.948763 0l382.072858-392.280337 0.001024-0.004094zM440.60802 154.908092l344.18597 353.383446-344.18597 353.385493c-20.973684 21.484314-20.973684 56.311517 0 77.79276 20.972661 21.482267 54.975079 21.482267 75.949786 0l382.074905-392.281361c20.966521-21.478174 20.966521-56.307424 0-77.790714L516.555759 77.115332c-20.972661-21.47715-54.975079-21.47715-75.949786 0-20.971637 21.48329-20.971637 56.30947 0.002047 77.79276z"
p-id="1925"></path>
</svg>
</div>
</div>
</div>
</div>
</transition>
</template>