新增: - ForgotPasswordModal — 手机号+短信验证码重置密码 (AuthAPI.resetPassword) - ChangePasswordModal — 当前密码验证后修改密码 (AuthAPI.changePassword) - useSmsCooldown Hook — 通用短信发送冷却逻辑,供注册/忘记密码复用 - PasswordSetting — 设置页账号安全区块,双选项:修改密码 / 短信验证码重置 修改: - LoginForm \"忘记密码?\" 链接接入 ForgotPasswordModal(替换 TODO) - LoginPage 移除 edition 业务版本 UI 区分,登录/注册 Tab 全局统一 - 设置页 Section 组件移入 blocks/ 子目录(git mv 保留历史) - auth.ts sendSms URL 修正: /sms/send → /send-sms 清理: - settings/index.ts 移除 4 个未使用 re-export,精简为仅 SettingsPage - navbar/index.ts 移除未使用 re-export,精简为仅 NavBar 文档: - WORKLOG.md 新增 2026-06-08 工作日志 - ARCHITECTURE.md / PROJECT.md 更新设置页目录结构与新组件 - TODO.md 忘记密码流程标记已完成 + 短信人机验证列入后期优化
58 lines
1.8 KiB
TypeScript
58 lines
1.8 KiB
TypeScript
// ============================================================
|
||
// useSmsCooldown — 短信验证码发送冷却 Hook
|
||
//
|
||
// 从 RegisterForm 提取,供所有需要短信验证码的场景复用:
|
||
// - 注册(RegisterForm)
|
||
// - 忘记密码(ForgotPasswordModal)
|
||
// ============================================================
|
||
|
||
import { useState, useCallback, useRef, useEffect } from 'react';
|
||
|
||
export interface SmsCooldownState {
|
||
/** 是否在冷却中 */
|
||
cooldown: boolean;
|
||
/** 冷却剩余秒数 */
|
||
secondsLeft: number;
|
||
/** 开始冷却 */
|
||
startCooldown: () => void;
|
||
}
|
||
|
||
export function useSmsCooldown(cooldownSeconds: number = 60): SmsCooldownState {
|
||
const [cooldown, setCooldown] = useState(false);
|
||
const [secondsLeft, setSecondsLeft] = useState(0);
|
||
const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
||
|
||
const startCooldown = useCallback(() => {
|
||
// 清理之前的计时器(防止重复点击导致多个计时器叠加)
|
||
if (timerRef.current) {
|
||
clearInterval(timerRef.current);
|
||
}
|
||
setCooldown(true);
|
||
setSecondsLeft(cooldownSeconds);
|
||
timerRef.current = setInterval(() => {
|
||
setSecondsLeft((prev) => {
|
||
if (prev <= 1) {
|
||
if (timerRef.current) {
|
||
clearInterval(timerRef.current);
|
||
timerRef.current = null;
|
||
}
|
||
setCooldown(false);
|
||
return 0;
|
||
}
|
||
return prev - 1;
|
||
});
|
||
}, 1000);
|
||
}, [cooldownSeconds]);
|
||
|
||
// 组件卸载时清理计时器
|
||
useEffect(() => {
|
||
return () => {
|
||
if (timerRef.current) {
|
||
clearInterval(timerRef.current);
|
||
}
|
||
};
|
||
}, []);
|
||
|
||
return { cooldown, secondsLeft, startCooldown };
|
||
}
|