import { createContext, useContext, useEffect, useState, ReactNode, useCallback } from 'react'; import { authService } from '../lib/authService'; import { ApiErrorMessages } from '../types/api'; import type { UserInfo } from '../types/api'; interface AuthContextType { user: UserInfo | null; token: string | null; loading: boolean; initializing: boolean; // 新增初始化状态 signIn: (email: string, password: string) => Promise<{ error: Error | null }>; signUp: (email: string, password: string) => Promise<{ error: Error | null }>; signOut: () => Promise; isAuthenticated: boolean; } const AuthContext = createContext(undefined); export function AuthProvider({ children }: { children: ReactNode }) { // 直接在 useState 初始化函数中同步恢复会话 const [user, setUser] = useState(() => { try { const session = authService.restoreSession(); return session ? session.user : null; } catch { return null; } }); const [token, setToken] = useState(() => { try { const session = authService.restoreSession(); return session ? session.token : null; } catch { return null; } }); const [loading, setLoading] = useState(false); const [initializing, setInitializing] = useState(false); // 不需要初始化过程了,因为是同步的 // 不再需要 useEffect 里的 restoreSession /** * 从错误对象中提取用户友好的错误消息 */ const getErrorMessage = (error: unknown, fallback: string): string => { // 检查是否是 ApiError(通过 code 属性判断,避免 instanceof 在热更新时失效) if (error && typeof error === 'object' && 'code' in error) { const apiError = error as { code: number; message: string }; return ApiErrorMessages[apiError.code] || apiError.message || fallback; } if (error instanceof Error) { return error.message; } return fallback; }; /** * 登录 */ const signIn = useCallback(async (email: string, password: string) => { setLoading(true); try { const result = await authService.login({ email, password }); setUser(result.user); setToken(result.token); return { error: null }; } catch (error) { const message = getErrorMessage(error, '登录失败'); return { error: new Error(message) }; } finally { setLoading(false); } }, []); /** * 注册 */ const signUp = useCallback(async (email: string, password: string) => { setLoading(true); try { const result = await authService.register({ email, password }); setUser(result.user); setToken(result.token); return { error: null }; } catch (error) { const message = getErrorMessage(error, '注册失败'); return { error: new Error(message) }; } finally { setLoading(false); } }, []); /** * 登出 */ const signOut = useCallback(async () => { setLoading(true); try { authService.logout(); setUser(null); setToken(null); } finally { setLoading(false); } }, []); const value: AuthContextType = { user, token, loading, initializing, signIn, signUp, signOut, isAuthenticated: !!user && !!token, }; return {children}; } export function useAuth() { const context = useContext(AuthContext); if (context === undefined) { throw new Error('useAuth must be used within an AuthProvider'); } return context; }