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

90 lines
2.2 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.

/**
* 部门树工具函数
*
* 部门树结构处理工具函数
* 包括:构建部门树、克隆节点、排序等功能
*
* @created 2025-01-XX(从 page.tsx 提取)
* @utils
*/
import { getDepartmentCollator } from '@/lib/departments'
import type { Department, DepartmentNode } from '../_components/types'
const cloneNode = (node: DepartmentNode, children: DepartmentNode[] = []) => ({
...node,
children,
})
export const buildDepartmentTree = (
departments: Department[] = [],
collator: Intl.Collator = getDepartmentCollator(),
): DepartmentNode[] => {
if (!departments.length) return []
const nodeMap = new Map<string, DepartmentNode>()
departments.forEach((dept) => {
nodeMap.set(dept.name, {
id: dept.id,
name: dept.name,
fullName: dept.name,
children: [],
})
})
const roots: DepartmentNode[] = []
departments.forEach((dept) => {
const node = nodeMap.get(dept.name)
if (!node) {
return
}
const lastDashIndex = dept.name.lastIndexOf('-')
if (lastDashIndex === -1) {
roots.push(node)
} else {
const parentName = dept.name.substring(0, lastDashIndex)
const parentNode = nodeMap.get(parentName)
if (parentNode) {
parentNode.children.push(node)
} else {
roots.push(node)
}
}
})
const sortNodes = (nodes: DepartmentNode[]) => {
nodes.sort((a, b) => collator.compare(a.fullName, b.fullName))
nodes.forEach((child) => sortNodes(child.children))
}
sortNodes(roots)
return roots
}
export const filterDepartmentTree = (
tree: DepartmentNode[],
term: string,
): DepartmentNode[] => {
const normalized = term.trim().toLowerCase()
if (!normalized) return tree
const filterNodes = (nodes: DepartmentNode[]): DepartmentNode[] =>
nodes
.map((node) => {
const matchesSelf =
node.name.toLowerCase().includes(normalized) ||
node.fullName.toLowerCase().includes(normalized)
const filteredChildren = filterNodes(node.children)
return matchesSelf || filteredChildren.length
? cloneNode(node, filteredChildren)
: null
})
.filter((node): node is DepartmentNode => Boolean(node))
return filterNodes(tree)
}