2026-08-03 18:49:18 +08:00
|
|
|
import type { Permission } from '@/modules/iam/types'
|
2026-07-30 17:59:43 +08:00
|
|
|
|
|
|
|
|
export type PermissionTreeNode = Permission & { children?: PermissionTreeNode[] }
|
|
|
|
|
export type PermissionMatcher = (permission: Permission) => boolean
|
|
|
|
|
|
|
|
|
|
function groupByParent(permissions: Permission[]) {
|
|
|
|
|
const childrenByParent = new Map<string | null, Permission[]>()
|
|
|
|
|
|
|
|
|
|
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<string>): 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 {
|
2026-08-13 11:57:44 +08:00
|
|
|
menuCount: selectedPermissions.filter((permission) => ['菜单', '页面'].includes(permission.type)).length,
|
2026-07-30 17:59:43 +08:00
|
|
|
actionCount: selectedPermissions.filter((permission) => ['按钮', '接口'].includes(permission.type)).length,
|
|
|
|
|
}
|
|
|
|
|
}
|