From 55e90c2434ebd712e762e6a731f1705ce648f7bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Fri, 24 Jul 2026 22:25:30 +0800 Subject: [PATCH] =?UTF-8?q?feat(login):=20=E4=BC=98=E5=8C=96=E6=89=8B?= =?UTF-8?q?=E6=9C=BA=E5=8F=B7=E9=AA=8C=E8=AF=81=E7=A0=81=E5=8F=91=E9=80=81?= =?UTF-8?q?=E9=80=BB=E8=BE=91=EF=BC=8C=E5=89=8D3=E6=AC=A1=E5=85=8D?= =?UTF-8?q?=E5=9B=BE=E5=BD=A2=E9=AA=8C=E8=AF=81=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增本地存储计数,记录每个手机号发送次数 - 前3次发送验证码无需弹出图形验证码弹窗,提升用户体验 - 第4次及以后需通过图形验证码验证后才发送短信 - 发送失败时自动刷新图形验证码并显示错误信息 - 补充异常处理,确保发送按钮状态正确重置 - 代码无类型错误,构建验证通过 --- .workbuddy/memory/2026-07-24.md | 7 +++ src/views/passport/login/index.vue | 95 ++++++++++++++++++++---------- 2 files changed, 72 insertions(+), 30 deletions(-) diff --git a/.workbuddy/memory/2026-07-24.md b/.workbuddy/memory/2026-07-24.md index 62c3181..368e032 100644 --- a/.workbuddy/memory/2026-07-24.md +++ b/.workbuddy/memory/2026-07-24.md @@ -53,3 +53,10 @@ - 失败时自动刷新图形验证码;弹窗关闭时重置 `codeLoading`。 - 新增 i18n 键 `login.forgetPage.captchaTitle`、`captchaPlaceholder`、`sendNow`(zh_CN/en)。 - `vue-tsc` 本次新增代码无类型错误;`vite build --outDir dist-verify-captcha` 编译通过。 + +## 优化:登录页手机号验证码前 3 次免图形验证 +- 修改 `src/views/passport/login/index.vue`:手机号登录 Tab 下,「发送验证码」按钮由直接弹窗改为先计数判断。 +- 用 `localStorage` 按 `login_sms_send_count_${phone}` 记录每个手机号的发送次数。 +- 同一个手机号前 3 次直接调用 `sendSmsCaptcha`;第 4 次起弹出原有图形验证码弹窗,输入正确并点击「立即发送」后才真正发送。 +- 失败时自动刷新图形验证码;补充了 `.catch`/`.finally`,避免发送异常时按钮一直 loading。 +- `vue-tsc` 本次新增代码无类型错误;`vite build --outDir dist-verify-login` 编译通过。 diff --git a/src/views/passport/login/index.vue b/src/views/passport/login/index.vue index 7223084..71521ac 100644 --- a/src/views/passport/login/index.vue +++ b/src/views/passport/login/index.vue @@ -174,7 +174,7 @@ 发送验证码 已发送 {{ countdownTime }} s @@ -223,7 +223,7 @@ size="large" placeholder="请输入图形验证码" allow-clear - @pressEnter="sendCode" + @pressEnter="() => sendCode(imgCode.value)" /> @@ -234,7 +234,7 @@ size="large" type="primary" :loading="codeLoading" - @click="sendCode" + @click="() => sendCode(imgCode.value)" > 立即发送 @@ -443,6 +443,27 @@ const countdownTime = ref(0); // 验证码倒计时定时器 let countdownTimer: number | null = null; + + // 同一个手机号前 3 次发送不需要图形验证码 + const FREE_SEND_TIMES = 3; + + // 根据手机号生成发送次数缓存 key + const getSendCountKey = () => `login_sms_send_count_${form.phone}`; + + // 读取当前手机号已发送次数 + const getSendCount = () => { + const key = getSendCountKey(); + if (!key) return 0; + const count = localStorage.getItem(key); + return count ? Number(count) || 0 : 0; + }; + + // 增加发送次数 + const increaseSendCount = () => { + const key = getSendCountKey(); + if (!key) return; + localStorage.setItem(key, String(getSendCount() + 1)); + }; // 多用户选择账号登录 const showSelectLoginUser = ref(false); const admins = ref([]); @@ -492,42 +513,56 @@ ] }); - /* 显示发送短信验证码弹窗 */ - const openImgCodeModal = () => { + /* 处理发送短信验证码按钮点击 */ + const handleSendCode = () => { if (!form.phone) { message.error('请输入手机号码'); return; } - imgCode.value = ''; - changeCaptcha(); - visible.value = true; + if (getSendCount() >= FREE_SEND_TIMES) { + imgCode.value = ''; + changeCaptcha(); + visible.value = true; + } else { + sendCode(); + } }; /* 发送短信验证码 */ - const sendCode = () => { - if (!imgCode.value) { - message.error('请输入图形验证码'); - return; - } - if (text.value !== imgCode.value.toLowerCase()) { - message.error('图形验证码不正确'); - return; + const sendCode = (captchaCode?: string) => { + if (captchaCode !== undefined) { + if (!captchaCode) { + message.error('请输入图形验证码'); + return; + } + if (text.value !== captchaCode.toLowerCase()) { + message.error('图形验证码不正确'); + return; + } } codeLoading.value = true; - sendSmsCaptcha({ phone: form.phone }).then(() => { - message.success('短信验证码发送成功, 请注意查收!'); - visible.value = false; - codeLoading.value = false; - countdownTime.value = 30; - // 开始对按钮进行倒计时 - countdownTimer = window.setInterval(() => { - if (countdownTime.value <= 1) { - countdownTimer && clearInterval(countdownTimer); - countdownTimer = null; - } - countdownTime.value--; - }, 1000); - }); + sendSmsCaptcha({ phone: form.phone }) + .then(() => { + message.success('短信验证码发送成功, 请注意查收!'); + visible.value = false; + increaseSendCount(); + countdownTime.value = 30; + // 开始对按钮进行倒计时 + countdownTimer = window.setInterval(() => { + if (countdownTime.value <= 1) { + countdownTimer && clearInterval(countdownTimer); + countdownTimer = null; + } + countdownTime.value--; + }, 1000); + }) + .catch((e: Error) => { + message.error(e.message); + changeCaptcha(); + }) + .finally(() => { + codeLoading.value = false; + }); }; // const { clearValidate, validate, validateInfos } = useForm(form, rules);