From 2a2c222c2f3f1800e182e7720dc89ef988b88e46 Mon Sep 17 00:00:00 2001 From: andy Date: Wed, 15 Jul 2026 14:59:16 +0700 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=99=BB=E5=BD=95=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E7=A0=81=E9=94=81=E5=AE=9A=E4=BA=A4=E4=BA=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/loginSms.test.ts | 44 +++++++++++++++++++++++++++++++++++++++ src/api/loginSms.ts | 28 +++++++++++++++++++++++++ src/pages/login/index.vue | 30 +++++++++++++++++++++++--- 3 files changed, 99 insertions(+), 3 deletions(-) diff --git a/src/api/loginSms.test.ts b/src/api/loginSms.test.ts index 2bd4750..5358e93 100644 --- a/src/api/loginSms.test.ts +++ b/src/api/loginSms.test.ts @@ -3,6 +3,8 @@ import { describe, it } from "node:test"; import { buildCaptchaImageUrl, buildSendMobileCodeRequest, + isImageCaptchaLocked, + resolveImageCaptchaInteractionState, resolveLoginErrorMessage, } from "./loginSms.ts"; @@ -63,4 +65,46 @@ describe("login sms api helpers", () => { "网络错误", ); }); + + it("locks image captcha while sms countdown is active", () => { + assert.equal(isImageCaptchaLocked(60), true); + assert.equal(isImageCaptchaLocked(1), true); + assert.equal(isImageCaptchaLocked(0), false); + }); + + it("resolves captcha field and refresh button interaction state", () => { + assert.deepEqual( + resolveImageCaptchaInteractionState({ + smsSending: false, + smsCountdown: 60, + }), + { + disabled: true, + clearable: false, + refreshDisabled: true, + }, + ); + assert.deepEqual( + resolveImageCaptchaInteractionState({ + smsSending: false, + smsCountdown: 0, + }), + { + disabled: false, + clearable: true, + refreshDisabled: false, + }, + ); + assert.deepEqual( + resolveImageCaptchaInteractionState({ + smsSending: true, + smsCountdown: 0, + }), + { + disabled: true, + clearable: false, + refreshDisabled: true, + }, + ); + }); }); diff --git a/src/api/loginSms.ts b/src/api/loginSms.ts index a4a639e..d37e7b2 100644 --- a/src/api/loginSms.ts +++ b/src/api/loginSms.ts @@ -10,6 +10,17 @@ export interface CaptchaImageUrlOptions { cacheBust?: number | string; } +export interface ImageCaptchaInteractionParams { + smsSending: boolean; + smsCountdown: number; +} + +export interface ImageCaptchaInteractionState { + disabled: boolean; + clearable: boolean; + refreshDisabled: boolean; +} + function trimEndSlash(value: string): string { return value.replace(/\/+$/, ""); } @@ -39,6 +50,23 @@ export function createCaptchaRandomStr(): string { return `${Date.now()}${Math.random().toString(36).slice(2, 10)}`; } +export function isImageCaptchaLocked(smsCountdown: number): boolean { + return smsCountdown > 0; +} + +export function resolveImageCaptchaInteractionState({ + smsSending, + smsCountdown, +}: ImageCaptchaInteractionParams): ImageCaptchaInteractionState { + const disabled = smsSending || isImageCaptchaLocked(smsCountdown); + + return { + disabled, + clearable: !disabled, + refreshDisabled: disabled, + }; +} + export function buildCaptchaImageUrl( randomStr: string, options: CaptchaImageUrlOptions = {}, diff --git a/src/pages/login/index.vue b/src/pages/login/index.vue index 78fb13c..a0a4a7b 100644 --- a/src/pages/login/index.vue +++ b/src/pages/login/index.vue @@ -16,11 +16,14 @@ -