108 lines
2.4 KiB
TypeScript
108 lines
2.4 KiB
TypeScript
"use client";
|
||
|
||
import {
|
||
createContext,
|
||
useContext,
|
||
useState,
|
||
useEffect,
|
||
useCallback,
|
||
type ReactNode,
|
||
} from "react";
|
||
import {
|
||
getToken,
|
||
getUser,
|
||
login as loginApi,
|
||
logout as logoutApi,
|
||
} from "@/lib/auth";
|
||
import type { CurrentUser } from "@/types/view-models";
|
||
|
||
interface AuthContextValue {
|
||
user: CurrentUser | null;
|
||
isAuthenticated: boolean;
|
||
isLoading: boolean;
|
||
hasPermission: (perm: string) => boolean;
|
||
hasAnyPermission: (perms: string[]) => boolean;
|
||
login: (email: string, password: string) => Promise<void>;
|
||
logout: () => void;
|
||
}
|
||
|
||
const AuthContext = createContext<AuthContextValue | null>(null);
|
||
|
||
export function AuthProvider({ children }: { children: ReactNode }) {
|
||
const [user, setUserState] = useState<CurrentUser | null>(null);
|
||
const [isLoading, setIsLoading] = useState(true);
|
||
|
||
useEffect(() => {
|
||
const token = getToken();
|
||
const stored = getUser();
|
||
if (token && stored) {
|
||
setUserState(stored);
|
||
}
|
||
setIsLoading(false);
|
||
}, []);
|
||
|
||
const login = useCallback(async (email: string, password: string) => {
|
||
const result = await loginApi(email, password);
|
||
setUserState(result.user);
|
||
}, []);
|
||
|
||
const logout = useCallback(() => {
|
||
setUserState(null);
|
||
logoutApi();
|
||
}, []);
|
||
|
||
const hasPermission = useCallback(
|
||
(perm: string) => {
|
||
if (!user) return false;
|
||
if (user.permissions.includes("*")) return true;
|
||
return user.permissions.includes(perm);
|
||
},
|
||
[user],
|
||
);
|
||
|
||
const hasAnyPermission = useCallback(
|
||
(perms: string[]) => {
|
||
if (!user) return false;
|
||
if (user.permissions.includes("*")) return true;
|
||
return perms.some((p) => user.permissions.includes(p));
|
||
},
|
||
[user],
|
||
);
|
||
|
||
return (
|
||
<AuthContext.Provider
|
||
value={{
|
||
user,
|
||
isAuthenticated: user !== null,
|
||
isLoading,
|
||
hasPermission,
|
||
hasAnyPermission,
|
||
login,
|
||
logout,
|
||
}}
|
||
>
|
||
{children}
|
||
</AuthContext.Provider>
|
||
);
|
||
}
|
||
|
||
export function useAuth(): AuthContextValue {
|
||
const ctx = useContext(AuthContext);
|
||
if (!ctx) {
|
||
throw new Error("useAuth must be used within AuthProvider");
|
||
}
|
||
return ctx;
|
||
}
|
||
|
||
/** 权限 Hook(复用 AuthProvider) */
|
||
export function usePermission() {
|
||
const { user, hasPermission, hasAnyPermission } = useAuth();
|
||
return {
|
||
hasPermission,
|
||
hasAnyPermission,
|
||
permissions: user?.permissions ?? [],
|
||
dataScope: user?.dataScope ?? "SELF",
|
||
roles: user?.roles ?? [],
|
||
};
|
||
}
|