feat(login): 优化手机号验证码发送逻辑,前3次免图形验证码
- 新增本地存储计数,记录每个手机号发送次数 - 前3次发送验证码无需弹出图形验证码弹窗,提升用户体验 - 第4次及以后需通过图形验证码验证后才发送短信 - 发送失败时自动刷新图形验证码并显示错误信息 - 补充异常处理,确保发送按钮状态正确重置 - 代码无类型错误,构建验证通过
This commit is contained in:
@@ -53,3 +53,10 @@
|
|||||||
- 失败时自动刷新图形验证码;弹窗关闭时重置 `codeLoading`。
|
- 失败时自动刷新图形验证码;弹窗关闭时重置 `codeLoading`。
|
||||||
- 新增 i18n 键 `login.forgetPage.captchaTitle`、`captchaPlaceholder`、`sendNow`(zh_CN/en)。
|
- 新增 i18n 键 `login.forgetPage.captchaTitle`、`captchaPlaceholder`、`sendNow`(zh_CN/en)。
|
||||||
- `vue-tsc` 本次新增代码无类型错误;`vite build --outDir dist-verify-captcha` 编译通过。
|
- `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` 编译通过。
|
||||||
|
|||||||
@@ -174,7 +174,7 @@
|
|||||||
<a-button
|
<a-button
|
||||||
class="login-captcha"
|
class="login-captcha"
|
||||||
:disabled="!!countdownTime"
|
:disabled="!!countdownTime"
|
||||||
@click="openImgCodeModal"
|
@click="handleSendCode"
|
||||||
>
|
>
|
||||||
<span v-if="!countdownTime">发送验证码</span>
|
<span v-if="!countdownTime">发送验证码</span>
|
||||||
<span v-else>已发送 {{ countdownTime }} s</span>
|
<span v-else>已发送 {{ countdownTime }} s</span>
|
||||||
@@ -223,7 +223,7 @@
|
|||||||
size="large"
|
size="large"
|
||||||
placeholder="请输入图形验证码"
|
placeholder="请输入图形验证码"
|
||||||
allow-clear
|
allow-clear
|
||||||
@pressEnter="sendCode"
|
@pressEnter="() => sendCode(imgCode.value)"
|
||||||
/>
|
/>
|
||||||
<a-button class="login-captcha">
|
<a-button class="login-captcha">
|
||||||
<img alt="" :src="captcha" @click="changeCaptcha" />
|
<img alt="" :src="captcha" @click="changeCaptcha" />
|
||||||
@@ -234,7 +234,7 @@
|
|||||||
size="large"
|
size="large"
|
||||||
type="primary"
|
type="primary"
|
||||||
:loading="codeLoading"
|
:loading="codeLoading"
|
||||||
@click="sendCode"
|
@click="() => sendCode(imgCode.value)"
|
||||||
>
|
>
|
||||||
立即发送
|
立即发送
|
||||||
</a-button>
|
</a-button>
|
||||||
@@ -443,6 +443,27 @@
|
|||||||
const countdownTime = ref(0);
|
const countdownTime = ref(0);
|
||||||
// 验证码倒计时定时器
|
// 验证码倒计时定时器
|
||||||
let countdownTimer: number | null = null;
|
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<boolean>(false);
|
const showSelectLoginUser = ref<boolean>(false);
|
||||||
const admins = ref<User[]>([]);
|
const admins = ref<User[]>([]);
|
||||||
@@ -492,32 +513,39 @@
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
/* 显示发送短信验证码弹窗 */
|
/* 处理发送短信验证码按钮点击 */
|
||||||
const openImgCodeModal = () => {
|
const handleSendCode = () => {
|
||||||
if (!form.phone) {
|
if (!form.phone) {
|
||||||
message.error('请输入手机号码');
|
message.error('请输入手机号码');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (getSendCount() >= FREE_SEND_TIMES) {
|
||||||
imgCode.value = '';
|
imgCode.value = '';
|
||||||
changeCaptcha();
|
changeCaptcha();
|
||||||
visible.value = true;
|
visible.value = true;
|
||||||
|
} else {
|
||||||
|
sendCode();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 发送短信验证码 */
|
/* 发送短信验证码 */
|
||||||
const sendCode = () => {
|
const sendCode = (captchaCode?: string) => {
|
||||||
if (!imgCode.value) {
|
if (captchaCode !== undefined) {
|
||||||
|
if (!captchaCode) {
|
||||||
message.error('请输入图形验证码');
|
message.error('请输入图形验证码');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (text.value !== imgCode.value.toLowerCase()) {
|
if (text.value !== captchaCode.toLowerCase()) {
|
||||||
message.error('图形验证码不正确');
|
message.error('图形验证码不正确');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
codeLoading.value = true;
|
codeLoading.value = true;
|
||||||
sendSmsCaptcha({ phone: form.phone }).then(() => {
|
sendSmsCaptcha({ phone: form.phone })
|
||||||
|
.then(() => {
|
||||||
message.success('短信验证码发送成功, 请注意查收!');
|
message.success('短信验证码发送成功, 请注意查收!');
|
||||||
visible.value = false;
|
visible.value = false;
|
||||||
codeLoading.value = false;
|
increaseSendCount();
|
||||||
countdownTime.value = 30;
|
countdownTime.value = 30;
|
||||||
// 开始对按钮进行倒计时
|
// 开始对按钮进行倒计时
|
||||||
countdownTimer = window.setInterval(() => {
|
countdownTimer = window.setInterval(() => {
|
||||||
@@ -527,6 +555,13 @@
|
|||||||
}
|
}
|
||||||
countdownTime.value--;
|
countdownTime.value--;
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
})
|
||||||
|
.catch((e: Error) => {
|
||||||
|
message.error(e.message);
|
||||||
|
changeCaptcha();
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
codeLoading.value = false;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user