feat: 忘记密码增设局部焦点提示及发信成功30秒防刷置灰倒计时锁

This commit is contained in:
pllx
2026-07-01 11:16:09 +08:00
parent 94236e25eb
commit 563ac99348
2 changed files with 50 additions and 8 deletions
+48 -6
View File
@@ -12,6 +12,19 @@ function getCsrfToken() {
return document.querySelector('meta[name="csrf-token"]')?.getAttribute("content") ?? "";
}
/**
* 获取当前应当使用的局部消息框元素。
*
* @returns {HTMLDivElement|null}
*/
function getActiveAlertBox() {
const stepDetect = document.getElementById("step-detect");
if (stepDetect && stepDetect.style.display !== "none") {
return document.getElementById("alert-detect");
}
return document.getElementById("alert-email");
}
/**
* 展示找回密码页面提示。
*
@@ -20,7 +33,7 @@ function getCsrfToken() {
* @returns {void}
*/
function showAlert(message, type) {
const alertBox = document.getElementById("alert-box");
const alertBox = getActiveAlertBox();
if (!alertBox) {
return;
}
@@ -28,6 +41,9 @@ function showAlert(message, type) {
alertBox.textContent = message;
alertBox.className = type === "success" ? "alert alert-success" : "alert alert-error";
alertBox.style.display = "block";
// 平滑滚动提示框到可视区域
alertBox.scrollIntoView({ behavior: "smooth", block: "nearest" });
}
/**
@@ -36,9 +52,13 @@ function showAlert(message, type) {
* @returns {void}
*/
function hideAlert() {
const alertBox = document.getElementById("alert-box");
if (alertBox) {
alertBox.style.display = "none";
const alertDetect = document.getElementById("alert-detect");
const alertEmail = document.getElementById("alert-email");
if (alertDetect) {
alertDetect.style.display = "none";
}
if (alertEmail) {
alertEmail.style.display = "none";
}
}
@@ -206,6 +226,8 @@ async function submitPasswordRecovery(event) {
}
hideAlert();
let isSentSuccess = false;
try {
const emailInput = document.getElementById("email");
const emailVal = emailInput instanceof HTMLInputElement ? emailInput.value.trim() : "";
@@ -231,6 +253,7 @@ async function submitPasswordRecovery(event) {
if (body.status === "success") {
showAlert(body.message, "success");
isSentSuccess = true;
return;
}
@@ -240,8 +263,27 @@ async function submitPasswordRecovery(event) {
showAlert("网络发送异常,请稍后再试。", "error");
} finally {
if (submitButton instanceof HTMLButtonElement) {
submitButton.disabled = false;
submitButton.innerText = "发送重置邮件";
if (isSentSuccess) {
// 成功时启动 30 秒置灰倒计时锁定
let seconds = 30;
submitButton.disabled = true;
submitButton.innerText = `${seconds}秒内不能重复发送`;
const timer = setInterval(() => {
seconds--;
if (seconds <= 0) {
clearInterval(timer);
submitButton.disabled = false;
submitButton.innerText = "二次验证并发送重置邮件";
} else {
submitButton.innerText = `${seconds}秒内不能重复发送`;
}
}, 1000);
} else {
// 校验失败,立刻解除禁用供重新编辑
submitButton.disabled = false;
submitButton.innerText = "二次验证并发送重置邮件";
}
}
}
}
+2 -2
View File
@@ -295,12 +295,11 @@
<div class="eyebrow">PASSWORD RECOVERY</div>
<h1 id="recovery-title">忘记密码</h1>
<div id="alert-box" class="alert" aria-live="polite"></div>
<!-- ================== 步骤一:检测账号昵称 ================== -->
<div id="step-detect" class="step-panel">
<p class="lead">请输入您的聊天室用户昵称,小助手将智能查询并为您提供最安全的重置方案。</p>
<form id="account-detect-form" action="{{ route('password.check_account') }}">
<div id="alert-detect" class="alert" aria-live="polite"></div>
<label for="username">账号昵称</label>
<input
id="username"
@@ -355,6 +354,7 @@
<div id="masked-email-hint" style="margin-bottom: 14px; font-size: 13.5px; color: var(--gold); font-weight: bold; line-height: 1.6; padding: 10px; border: 1px dashed rgba(198,163,91,0.3); background: rgba(198,163,91,0.02);"></div>
<form id="password-recovery-form" data-password-email-url="{{ route('password.email') }}">
<div id="alert-email" class="alert" aria-live="polite"></div>
<label for="email">二次安全确认:请输入绑定的完整邮箱</label>
<input
id="email"