feat: 增加基于图片拼图切片平移的验证码

pull/168/head^2
chenweiran 2025-07-04 10:23:47 +08:00
parent bbd8a53d9d
commit 8ccd01ade5
3 changed files with 16 additions and 10 deletions

View File

@ -53,7 +53,7 @@ const state = reactive({
startTime: 0, startTime: 0,
endTime: 0, endTime: 0,
pieceX: 0, pieceX: 0,
PieceY: 0, pieceY: 0,
moveDistance: 0, moveDistance: 0,
isPassing: false, isPassing: false,
showTip: false, showTip: false,
@ -73,10 +73,10 @@ function setLeft(val: string) {
const verifyTip = computed(() => { const verifyTip = computed(() => {
return state.isPassing return state.isPassing
? $t('ui.captcha.sliderRotateSuccessTip', [ ? $t('ui.captcha.sliderTranslateSuccessTip', [
((state.endTime - state.startTime) / 1000).toFixed(1), ((state.endTime - state.startTime) / 1000).toFixed(1),
]) ])
: $t('ui.captcha.sliderRotateFailTip'); : $t('ui.captcha.sliderTranslateFailTip');
}); });
function handleStart() { function handleStart() {
state.startTime = Date.now(); state.startTime = Date.now();
@ -93,7 +93,7 @@ function handleDragEnd() {
const { pieceX } = state; const { pieceX } = state;
const { diffDistance } = props; const { diffDistance } = props;
if (Math.abs(pieceX - state.moveDistance) >= (diffDistance || 10)) { if (Math.abs(pieceX - state.moveDistance) >= (diffDistance || 5)) {
setLeft('0'); setLeft('0');
state.moveDistance = 0; state.moveDistance = 0;
} else { } else {
@ -161,7 +161,7 @@ function initCanvas() {
pieceCanvasCtx.drawImage(img, 0, 0, canvasWidth, canvasHeight); pieceCanvasCtx.drawImage(img, 0, 0, canvasWidth, canvasHeight);
const pieceLength = squareLength + 2 * circleRadius + 3; const pieceLength = squareLength + 2 * circleRadius + 3;
const sx = state.pieceX; const sx = state.pieceX;
const sy = state.PieceY - 2 * circleRadius - 1; const sy = state.pieceY - 2 * circleRadius - 1;
const imageData = pieceCanvasCtx.getImageData( const imageData = pieceCanvasCtx.getImageData(
sx, sx,
sy, sy,
@ -185,12 +185,12 @@ function draw(ctx1: CanvasRenderingContext2D, ctx2: CanvasRenderingContext2D) {
squareLength + 2 * circleRadius, squareLength + 2 * circleRadius,
canvasWidth - (squareLength + 2 * circleRadius), canvasWidth - (squareLength + 2 * circleRadius),
); );
state.PieceY = getRandomNumberByRange( state.pieceY = getRandomNumberByRange(
3 * circleRadius, 3 * circleRadius,
canvasHeight - (squareLength + 2 * circleRadius), canvasHeight - (squareLength + 2 * circleRadius),
); );
drawPiece(ctx1, state.pieceX, state.PieceY, CanvasOpr.Fill); drawPiece(ctx1, state.pieceX, state.pieceY, CanvasOpr.Fill);
drawPiece(ctx2, state.pieceX, state.PieceY, CanvasOpr.Clip); drawPiece(ctx2, state.pieceX, state.pieceY, CanvasOpr.Clip);
} }
// //
@ -246,7 +246,7 @@ function resume() {
state.dragging = false; state.dragging = false;
state.isPassing = false; state.isPassing = false;
state.pieceX = 0; state.pieceX = 0;
state.PieceY = 0; state.pieceY = 0;
basicEl.resume(); basicEl.resume();
resetCanvas(); resetCanvas();
@ -290,7 +290,7 @@ onMounted(() => {
{{ verifyTip }} {{ verifyTip }}
</div> </div>
<div v-if="!state.dragging" class="bg-black/30"> <div v-if="!state.dragging" class="bg-black/30">
{{ defaultTip || $t('ui.captcha.sliderRotateDefaultTip') }} {{ defaultTip || $t('ui.captcha.sliderTranslateDefaultTip') }}
</div> </div>
</div> </div>
</div> </div>

View File

@ -32,8 +32,11 @@
"sliderDefaultText": "Slider and drag", "sliderDefaultText": "Slider and drag",
"alt": "Supports img tag src attribute value", "alt": "Supports img tag src attribute value",
"sliderRotateDefaultTip": "Click picture to refresh", "sliderRotateDefaultTip": "Click picture to refresh",
"sliderTranslateDefaultTip": "Click picture to refresh",
"sliderRotateFailTip": "Validation failed", "sliderRotateFailTip": "Validation failed",
"sliderRotateSuccessTip": "Validation successful, time {0} seconds", "sliderRotateSuccessTip": "Validation successful, time {0} seconds",
"sliderTranslateFailTip": "Validation failed",
"sliderTranslateSuccessTip": "Validation successful, time {0} seconds",
"refreshAriaLabel": "Refresh captcha", "refreshAriaLabel": "Refresh captcha",
"confirmAriaLabel": "Confirm selection", "confirmAriaLabel": "Confirm selection",
"confirm": "Confirm", "confirm": "Confirm",

View File

@ -31,8 +31,11 @@
"sliderSuccessText": "验证通过", "sliderSuccessText": "验证通过",
"sliderDefaultText": "请按住滑块拖动", "sliderDefaultText": "请按住滑块拖动",
"sliderRotateDefaultTip": "点击图片可刷新", "sliderRotateDefaultTip": "点击图片可刷新",
"sliderTranslateDefaultTip": "点击图片可刷新",
"sliderRotateFailTip": "验证失败", "sliderRotateFailTip": "验证失败",
"sliderRotateSuccessTip": "验证成功,耗时{0}秒", "sliderRotateSuccessTip": "验证成功,耗时{0}秒",
"sliderTranslateFailTip": "验证失败",
"sliderTranslateSuccessTip": "验证成功,耗时{0}秒",
"alt": "支持img标签src属性值", "alt": "支持img标签src属性值",
"refreshAriaLabel": "刷新验证码", "refreshAriaLabel": "刷新验证码",
"confirmAriaLabel": "确认选择", "confirmAriaLabel": "确认选择",