flnxi-Wu/app/admin/_hooks/usePermissions.ts
2025-11-22 17:56:24 +08:00

104 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* usePermissions Hook
*
* 权限检查Hook
* 统一管理用户权限检查逻辑
* 包括:是否可管理用户、是否超级管理员等
*
* @created 2025-01-XX(从 page.tsx 提取)
* @hook
*/
'use client'
import { useCallback, useMemo } from 'react'
import { buildDepartmentDescendants, isDepartmentWithinScope } from '@/lib/departments'
import type { Department, User } from '../_components/types'
interface UsePermissionsOptions {
sessionUser?: Record<string, any> | null
users: User[]
departments: Department[]
}
export default function usePermissions({
sessionUser,
users,
departments,
}: UsePermissionsOptions) {
const currentUserId = sessionUser?.id as string | undefined
const currentUserRecord = useMemo(
() => (currentUserId ? users.find((user) => user.id === currentUserId) : undefined),
[currentUserId, users],
)
const currentIsSuperAdmin = useMemo(
() => Boolean(currentUserRecord?.isSuperAdmin ?? sessionUser?.isSuperAdmin),
[currentUserRecord, sessionUser],
)
const currentRole = (sessionUser?.role ?? currentUserRecord?.role) as
| 'ADMIN'
| 'USER'
| undefined
const currentIsAdminRole = useMemo(
() => currentIsSuperAdmin || currentRole === 'ADMIN' || currentUserRecord?.role === 'ADMIN',
[currentIsSuperAdmin, currentRole, currentUserRecord?.role],
)
const currentManagedDepartment = useMemo(
() => currentUserRecord?.managedDepartment ?? sessionUser?.managedDepartment,
[currentUserRecord?.managedDepartment, sessionUser?.managedDepartment],
)
const currentDepartmentScope = useMemo(() => {
const fallback = (currentUserRecord?.department || '').trim() || undefined
return currentManagedDepartment || fallback
}, [currentManagedDepartment, currentUserRecord?.department])
const departmentDescendantsMap = useMemo(
() => buildDepartmentDescendants(departments),
[departments],
)
const canManageUser = useCallback(
(target: User) => {
if (!currentUserId) return false
if (currentIsSuperAdmin) return true
if (target.isSuperAdmin) return false
const targetDept = (target.department || '').trim()
if (!targetDept && currentIsAdminRole) {
return true
}
if (currentDepartmentScope) {
return isDepartmentWithinScope(
currentDepartmentScope,
target.department,
departmentDescendantsMap,
)
}
return target.id === currentUserId
},
[
currentDepartmentScope,
currentIsAdminRole,
currentIsSuperAdmin,
currentUserId,
departmentDescendantsMap,
],
)
return {
currentUserId,
currentIsSuperAdmin,
canManageUser,
}
}