/** * 部门工具函数 * * 提供部门层级结构处理、权限范围检查等功能 * 参考 flnxi_sucai 项目的实现逻辑 */ /** * 标准化部门名称(去除空白字符) */ const normalizeName = (name?: string | null): string => { return (name || '').trim() } /** * 构建部门后裔映射 * 返回一个Map,key是部门名称,value是该部门的所有后裔部门名称集合 * * @param departments 部门列表 * @returns Map> 部门名称到其后裔部门名称集合的映射 */ export function buildDepartmentDescendants( departments: Array<{ id: string; name: string; parentId?: string | null }> ): Map> { // 构建部门ID到部门的映射 const deptMap = new Map() departments.forEach(dept => { deptMap.set(dept.id, dept) }) // 构建部门名称到部门的映射 const nameToDeptMap = new Map() departments.forEach(dept => { const normalizedName = normalizeName(dept.name) if (normalizedName) { nameToDeptMap.set(normalizedName, dept) } }) // 构建子部门映射(parentId -> children) const childrenMap = new Map() departments.forEach(dept => { if (dept.parentId && deptMap.has(dept.parentId)) { const parent = deptMap.get(dept.parentId)! const parentName = normalizeName(parent.name) if (parentName) { if (!childrenMap.has(parentName)) { childrenMap.set(parentName, []) } childrenMap.get(parentName)!.push(normalizeName(dept.name)) } } }) // 构建后裔映射(递归收集所有后裔) const descendantMap = new Map>() const visit = (deptName: string): Set => { if (descendantMap.has(deptName)) { return descendantMap.get(deptName)! } const descendants = new Set([deptName]) const children = childrenMap.get(deptName) || [] children.forEach(childName => { visit(childName).forEach(desc => descendants.add(desc)) }) descendantMap.set(deptName, descendants) return descendants } // 遍历所有部门,构建后裔映射 departments.forEach(dept => { const deptName = normalizeName(dept.name) if (deptName) { visit(deptName) } }) return descendantMap } /** * 检查目标部门是否在权限范围内 * * @param scope 权限范围部门名称(当前用户的部门或管理范围) * @param target 目标部门名称(要检查的部门) * @param descendantMap 部门后裔映射(可选,如果不提供则使用简单的字符串匹配) * @returns boolean 目标部门是否在权限范围内 */ export function isDepartmentWithinScope( scope: string | null | undefined, target: string | null | undefined, descendantMap?: Map> ): boolean { const normalizedScope = normalizeName(scope) const normalizedTarget = normalizeName(target) if (!normalizedScope || !normalizedTarget) { return false } // 完全匹配 if (normalizedScope === normalizedTarget) { return true } // 如果有后裔映射,检查目标是否是范围部门的后裔 if (descendantMap) { const scopedDescendants = descendantMap.get(normalizedScope) if (scopedDescendants?.has(normalizedTarget)) { return true } } // 回退到简单的层级匹配(如果使用名称层级结构,如:父部门-子部门) // 注意:当前项目使用 parentId,这个匹配可能不准确,但作为备用方案 return normalizedTarget.startsWith(`${normalizedScope}-`) } /** * 获取部门排序比较器(中文拼音排序) */ export function getDepartmentCollator(): Intl.Collator { return new Intl.Collator('zh-Hans-CN-u-co-pinyin', { numeric: true, sensitivity: 'base', }) }