import type { Permission } from '@/types/admin' export type PermissionTreeNode = Permission & { children?: PermissionTreeNode[] } export type PermissionMatcher = (permission: Permission) => boolean function groupByParent(permissions: Permission[]) { const childrenByParent = new Map() permissions.forEach((permission) => { const siblings = childrenByParent.get(permission.parentId) ?? [] siblings.push(permission) childrenByParent.set(permission.parentId, siblings) }) childrenByParent.forEach((siblings) => { siblings.sort((left, right) => left.sort - right.sort) }) return childrenByParent } export function buildPermissionTree( permissions: Permission[], matches: PermissionMatcher = () => true, ): PermissionTreeNode[] { const childrenByParent = groupByParent(permissions) function buildNode(permission: Permission, ancestors: Set): PermissionTreeNode | null { if (ancestors.has(permission.id)) return null const nextAncestors = new Set(ancestors).add(permission.id) const children = (childrenByParent.get(permission.id) ?? []) .map((child) => buildNode(child, nextAncestors)) .filter((child): child is PermissionTreeNode => child !== null) if (!matches(permission) && children.length === 0) return null return { ...permission, ...(children.length ? { children } : {}), } } return (childrenByParent.get(null) ?? []) .map((permission) => buildNode(permission, new Set())) .filter((node): node is PermissionTreeNode => node !== null) } export function getDescendantIds(permissions: Permission[], permissionId: string): string[] { const childrenByParent = groupByParent(permissions) const visited = new Set([permissionId]) const descendants: string[] = [] const queue = [...(childrenByParent.get(permissionId) ?? [])] while (queue.length) { const current = queue.shift() if (!current || visited.has(current.id)) continue visited.add(current.id) descendants.push(current.id) queue.push(...(childrenByParent.get(current.id) ?? [])) } return descendants } export function summarizePermissionSelection(permissions: Permission[], selectedIds: string[]) { const selected = new Set(selectedIds) const selectedPermissions = permissions.filter((permission) => selected.has(permission.id)) return { menuCount: selectedPermissions.filter((permission) => permission.type === '菜单').length, actionCount: selectedPermissions.filter((permission) => ['按钮', '接口'].includes(permission.type)).length, } }