refactor: CSS 拆分 + auth 持久化提取 + 目录整理
- globals.css 拆分为 4 文件:tokens.css(颜色)/ transitions.css(过渡)/ base.css(重置)/ globals.css(入口) - 提取 auth-persistence.ts 到 services/,解除 AppProvider→pages/login/hooks 反向依赖 - use-auth-state.ts 精简为纯 React Hook,持久化逻辑委托给 services/auth-persistence.ts - components/common/ → components/ui/(目录名语义更清晰) - TypeScript + Vite 构建通过 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,7 @@ import { UserOutlined, LockOutlined } from '@ant-design/icons';
|
||||
|
||||
import { loginFields } from '../config/login-fields';
|
||||
import { validateForm } from '../config/validators';
|
||||
import { LegalTextModal } from '@/components/common/LegalTextModal';
|
||||
import { LegalTextModal } from '@/components/ui/LegalTextModal';
|
||||
import type { LoginFormValues } from '../types';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { useState, useCallback, useRef } from 'react';
|
||||
import { Input, Button, Checkbox, Typography } from 'antd';
|
||||
|
||||
import { LegalTextModal } from '@/components/common/LegalTextModal';
|
||||
import { LegalTextModal } from '@/components/ui/LegalTextModal';
|
||||
import {
|
||||
UserOutlined,
|
||||
LockOutlined,
|
||||
|
||||
@@ -1,76 +1,34 @@
|
||||
// ============================================================
|
||||
// useAuthState — 记住账号 / 自动登录 状态管理
|
||||
// useAuthState — 记住账号 / 自动登录 表单状态 Hook
|
||||
//
|
||||
// "记住密码":下次打开页面自动回填用户名(不再存储密码)
|
||||
// "自动登录":登录成功时标记,AppProvider 启动时用 refresh_token 静默续期
|
||||
//
|
||||
// 持久化逻辑已提取到 services/auth-persistence.ts,
|
||||
// 此处仅负责 React 组件状态(useState + useCallback)。
|
||||
//
|
||||
// 安全:
|
||||
// - 密码从不持久化存储(access_token / refresh_token 由 safeStorage 加密保护)
|
||||
// - 安全性由 refresh_token + access_token 的 JWT 双重机制 + OS 密钥链保障
|
||||
// ============================================================
|
||||
|
||||
import { useState, useCallback } from 'react';
|
||||
import {
|
||||
saveAuth,
|
||||
clearSavedAuth,
|
||||
getSavedUsername,
|
||||
getSavedRemember,
|
||||
getSavedAutoLogin,
|
||||
} from '@/services/auth-persistence';
|
||||
|
||||
const STORAGE_KEY = 'ele-heixiu-auth';
|
||||
|
||||
interface StoredAuth {
|
||||
/** 上次登录的用户名(表单回填用) */
|
||||
username: string;
|
||||
/** 是否记住用户名(勾选后表单自动回填用户名) */
|
||||
remember: boolean;
|
||||
/** 是否勾选了自动登录(AppProvider 据此决定启动时是否刷新 token) */
|
||||
autoLogin: boolean;
|
||||
}
|
||||
|
||||
function readAuth(): StoredAuth | null {
|
||||
try {
|
||||
const raw = localStorage.getItem(STORAGE_KEY);
|
||||
if (!raw) return null;
|
||||
return JSON.parse(raw) as StoredAuth;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function writeAuth(auth: StoredAuth): void {
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(auth));
|
||||
} catch {
|
||||
/* 静默 */
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- 工具函数(不依赖 React,AppProvider 可直接调用)----------
|
||||
|
||||
/** 读取自动登录标记 */
|
||||
export function getAutoLoginFlag(): boolean {
|
||||
return readAuth()?.autoLogin || false;
|
||||
}
|
||||
|
||||
/** 仅清除自动登录标记(保留用户名,下次还能回填表单) */
|
||||
export function clearAutoLoginFlag(): void {
|
||||
const auth = readAuth();
|
||||
if (!auth) return;
|
||||
writeAuth({ ...auth, autoLogin: false });
|
||||
}
|
||||
|
||||
/** 清除所有保存的认证信息 */
|
||||
export function clearSavedAuth(): void {
|
||||
try {
|
||||
localStorage.removeItem(STORAGE_KEY);
|
||||
} catch {
|
||||
/* 静默 */
|
||||
}
|
||||
}
|
||||
export { getAutoLoginFlag, clearAutoLoginFlag, clearSavedAuth } from '@/services/auth-persistence';
|
||||
|
||||
// ---------- Hook ----------
|
||||
|
||||
export function useAuthState() {
|
||||
const saved = readAuth();
|
||||
|
||||
const [username, setUsername] = useState(saved?.username || '');
|
||||
const [remember, setRemember] = useState(saved?.remember || false);
|
||||
const [autoLogin, setAutoLogin] = useState(saved?.autoLogin || false);
|
||||
const [username, setUsername] = useState(getSavedUsername);
|
||||
const [remember, setRemember] = useState(getSavedRemember);
|
||||
const [autoLogin, setAutoLogin] = useState(getSavedAutoLogin);
|
||||
|
||||
const handleRememberChange = useCallback((checked: boolean) => {
|
||||
setRemember(checked);
|
||||
@@ -93,16 +51,11 @@ export function useAuthState() {
|
||||
* @param doRemember - 是否勾选"记住用户名"
|
||||
* @param doAutoLogin - 是否勾选"自动登录"
|
||||
*/
|
||||
const saveAuth = useCallback(
|
||||
const handleSaveAuth = useCallback(
|
||||
(user: string, _password: string, doRemember: boolean, doAutoLogin: boolean) => {
|
||||
setUsername(user);
|
||||
if (doRemember || doAutoLogin) {
|
||||
const payload: StoredAuth = {
|
||||
username: user,
|
||||
remember: doRemember,
|
||||
autoLogin: doAutoLogin,
|
||||
};
|
||||
writeAuth(payload);
|
||||
saveAuth(user, doRemember, doAutoLogin);
|
||||
}
|
||||
},
|
||||
[],
|
||||
@@ -115,6 +68,6 @@ export function useAuthState() {
|
||||
setUsername,
|
||||
handleRememberChange,
|
||||
handleAutoLoginChange,
|
||||
saveAuth,
|
||||
saveAuth: handleSaveAuth,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user