import { createContext, useContext, useEffect, useState, type ReactNode } from 'react' import { authLogin, authLogout, AUTH_EXPIRED_EVENT, clearSession, getUserName, setSession, TOKEN_KEY, USER_KEY } from '../api/client' interface AuthState { token: string username: string login: (u: string, p: string) => Promise logout: () => void } const Ctx = createContext({ token: '', username: '', login: async () => {}, logout: () => {} }) export function AuthProvider({ children }: { children: ReactNode }) { const [token, setToken] = useState(() => localStorage.getItem(TOKEN_KEY) || '') const [username, setUsername] = useState(() => localStorage.getItem(USER_KEY) || '') const login = async (u: string, p: string) => { const data = await authLogin(u, p) setSession(data.token, data.username) setToken(data.token) setUsername(data.username) } const logout = () => { // 先吊销服务端令牌(fire-and-forget,失败不阻塞退出),再清理本地 authLogout().catch(() => {}) clearSession() setToken('') setUsername('') } // 任何请求命中 401(登录态无效/过期)时,同步清空内存态, // AppLayout 会立即自动跳转到登录页。 useEffect(() => { const onExpired = () => { clearSession() setToken('') setUsername('') } window.addEventListener(AUTH_EXPIRED_EVENT, onExpired) return () => window.removeEventListener(AUTH_EXPIRED_EVENT, onExpired) }, []) return {children} } export const useAuth = () => useContext(Ctx)