import { useCallback, useMemo } from "react"; import type { PermissionContext } from "./types.js"; /** * usePermission - 权限查询 Hook * * 用途:L2 路由级 + L3 组件级视口控制。 * 权限点命名遵循 F7 裁决:`_`(如 `EXAM_READ`)。 * 数据范围用后缀 `_OWN`/`_CHILD`(如 `GRADE_READ_CHILD`)。 * * 注意:权限数据由调用方注入(apps/* 从 iam /iam/permissions/effective 获取后传入)。 * 本 hook 不直接调 API,保持纯客户端逻辑。 * * @example * const { hasPermission, hasAny, hasAll } = usePermission({ permissions, dataScope, roles }); * * if (hasPermission("EXAM_CREATE")) { ... } * if (hasPermission("GRADE_READ_CHILD")) { ... } // 数据范围后缀 */ export interface UsePermissionProps { /** 权限上下文(从 iam /iam/permissions/effective 获取) */ context: PermissionContext | null; } export interface UsePermissionReturn { /** 检查是否拥有指定权限点 */ hasPermission: (perm: string) => boolean; /** 检查是否拥有任一权限点 */ hasAny: (...perms: string[]) => boolean; /** 检查是否拥有全部权限点 */ hasAll: (...perms: string[]) => boolean; /** 检查是否拥有指定角色 */ hasRole: (role: string) => boolean; /** 当前数据范围 */ dataScope: PermissionContext["dataScope"] | null; } export function usePermission({ context, }: UsePermissionProps): UsePermissionReturn { const permissions = context?.permissions ?? []; const roles = context?.roles ?? []; const dataScope = context?.dataScope ?? null; const permissionSet = useMemo(() => new Set(permissions), [permissions]); const roleSet = useMemo(() => new Set(roles), [roles]); const hasPermission = useCallback( (perm: string): boolean => permissionSet.has(perm), [permissionSet], ); const hasAny = useCallback( (...perms: string[]): boolean => perms.some((p) => permissionSet.has(p)), [permissionSet], ); const hasAll = useCallback( (...perms: string[]): boolean => perms.every((p) => permissionSet.has(p)), [permissionSet], ); const hasRole = useCallback( (role: string): boolean => roleSet.has(role), [roleSet], ); return { hasPermission, hasAny, hasAll, hasRole, dataScope, }; }