import { Injectable } from '@nestjs/common'; import { db, DepartmentMethodSchema, DeptAncestry, getUniqueItems, ObjectType, Prisma, } from '@nice/common'; import { BaseTreeService } from '../base/base.tree.service'; import { z } from 'zod'; import { mapToDeptSimpleTree, getStaffsByDeptIds } from './utils'; import EventBus, { CrudOperation } from '@server/utils/event-bus'; @Injectable() export class DepartmentService extends BaseTreeService { constructor() { super(db, ObjectType.DEPARTMENT, 'deptAncestry', true); } async getDescendantIdsInDomain( ancestorId: string, includeAncestor = true, ): Promise { // 如果没有提供部门ID,返回空数组 if (!ancestorId) return []; // 获取祖先部门信息 const ancestorDepartment = await db.department.findUnique({ where: { id: ancestorId }, }); // 如果未找到部门,返回空数组 if (!ancestorDepartment) return []; // 查询同域下以指定部门为祖先的部门血缘关系 const departmentAncestries = await db.deptAncestry.findMany({ where: { ancestorId: ancestorId, descendant: { domainId: ancestorDepartment.domainId, }, }, }); // 提取子部门ID列表 const descendantDepartmentIds = departmentAncestries.map( (ancestry) => ancestry.descendantId, ); // 根据参数决定是否包含祖先部门ID if (includeAncestor && ancestorId) { descendantDepartmentIds.push(ancestorId); } return descendantDepartmentIds; } async getDescendantDomainIds( ancestorDomainId: string, includeAncestorDomain = true, ): Promise { if (!ancestorDomainId) return []; // 查询所有以指定域ID为祖先的域的血缘关系 const domainAncestries = await db.deptAncestry.findMany({ where: { ancestorId: ancestorDomainId, descendant: { isDomain: true, }, }, }); // 提取子域的ID列表 const descendantDomainIds = domainAncestries.map( (ancestry) => ancestry.descendantId, ); // 根据参数决定是否包含祖先域ID if (includeAncestorDomain && ancestorDomainId) { descendantDomainIds.push(ancestorDomainId); } return descendantDomainIds; } /** * 获取指定DOM下的对应name的单位 * @param domainId * @param name * @returns */ async findInDomain(domainId: string, name: string) { const subDepts = await db.deptAncestry.findMany({ where: { ancestorId: domainId, }, include: { descendant: true, }, }); const dept = subDepts.find((item) => item.descendant.name === name); return dept.descendant; } private async setDomainId(parentId: string) { const parent = await this.findUnique({ where: { id: parentId } }); return parent.isDomain ? parentId : parent.domainId; } async create(args: Prisma.DepartmentCreateArgs) { if (args.data.parentId) { args.data.domainId = await this.setDomainId(args.data.parentId); } const result = await super.create(args); EventBus.emit('dataChanged', { type: this.objectType, operation: CrudOperation.CREATED, data: result, }); return result; } async update(args: Prisma.DepartmentUpdateArgs) { if (args.data.parentId) { args.data.domainId = await this.setDomainId(args.data.parentId as string); } const result = await super.update(args); EventBus.emit('dataChanged', { type: this.objectType, operation: CrudOperation.UPDATED, data: result, }); return result; } /** * 删除现有单位并清理DeptAncestry关系。 * @param data - 用于删除现有单位的数据。 * @returns 删除的单位对象。 */ async softDeleteByIds(ids: string[]) { const descendantIds = await this.getDescendantIds(ids, true); const result = await super.softDeleteByIds(descendantIds); EventBus.emit('dataChanged', { type: this.objectType, operation: CrudOperation.DELETED, data: result, }); return result; } /** * 获取指定部门及其所有子部门的员工。 * @param deptIds - 要获取员工ID的部门ID数组。 * @returns 包含所有员工ID的数组。 */ async getStaffsInDepts(deptIds: string[]) { const allDeptIds = await this.getDescendantIds(deptIds, true); return await getStaffsByDeptIds(Array.from(allDeptIds)); } async getStaffIdsInDepts(deptIds: string[]) { const result = await this.getStaffsInDepts(deptIds); return result.map((s) => s.id); } /** * 根据部门名称列表和域ID获取多个部门的ID。 * * @param {string[]} names - 部门名称列表 * @param {string} domainId - 域ID * @returns {Promise>} - 返回一个对象,键为部门名称,值为部门ID或null */ async getDeptIdsByNames( names: string[], domainId: string, ): Promise> { // 使用 Prisma 的 findMany 方法批量查询部门信息,优化性能 const depts = await db.department.findMany({ where: { // 查询条件:部门名称在给定的名称列表中 name: { in: names }, // 查询条件:部门在指定的域下(通过ancestors关系查询) ancestors: { some: { ancestorId: domainId, }, }, }, // 选择查询的字段:只查询部门的id和name字段 select: { id: true, name: true, }, }); // 创建一个Map对象,将部门名称映射到部门ID const deptMap = new Map(depts.map((dept) => [dept.name, dept.id])); // 初始化结果对象,用于存储最终的结果 const result: Record = {}; // 遍历传入的部门名称列表 for (const name of names) { // 从Map中获取部门ID,如果不存在则返回null result[name] = deptMap.get(name) || null; } // 返回最终的结果对象 return result; } async getChildSimpleTree( data: z.infer, ) { const { domain, deptIds, rootId } = data; // 提取非空 deptIds const validDeptIds = deptIds?.filter((id) => id !== null) ?? []; const hasNullDeptId = deptIds?.includes(null) ?? false; const [childrenData, selfData] = await Promise.all([ db.deptAncestry.findMany({ where: { ...(deptIds && { OR: [ ...(validDeptIds.length ? [{ ancestorId: { in: validDeptIds } }] : []), ...(hasNullDeptId ? [{ ancestorId: null }] : []), ], }), ancestorId: rootId, relDepth: 1, descendant: { isDomain: domain }, }, include: { descendant: { include: { children: true, deptStaffs: true } }, }, orderBy: { descendant: { order: 'asc' } }, }), deptIds ? db.department.findMany({ where: { ...(deptIds && { OR: [ ...(validDeptIds.length ? [{ id: { in: validDeptIds } }] : []), ], }), isDomain: domain, }, include: { children: true }, orderBy: { order: 'asc' }, }) : [], ]); const children = childrenData .map(({ descendant }) => descendant) .filter(Boolean) .map(mapToDeptSimpleTree); const selfItems = selfData.map(mapToDeptSimpleTree); return getUniqueItems([...children, ...selfItems], 'id'); } /** * 获取父级部门简单树结构的异步方法 * * @param data - 包含部门ID、域和根ID的输入参数 * @returns 返回唯一的部门简单树结构数组 * * 方法整体设计思路: * 1. 并行查询父级部门ancestry和自身部门数据 * 2. 查询根节点的直接子节点 * 3. 通过自定义过滤函数筛选超出根节点层级的祖先节点 * 4. 将查询结果映射为简单树结构 * 5. 去重并返回最终结果 */ async getParentSimpleTree( data: z.infer, ) { // 解构输入参数 const { deptIds, domain, rootId } = data; // 并行查询父级部门ancestry和自身部门数据 // 使用Promise.all提高查询效率,减少等待时间 const [parentData, selfData] = await Promise.all([ // 查询指定部门的所有祖先节点,包含子节点和父节点信息 db.deptAncestry.findMany({ where: { descendantId: { in: deptIds }, // 查询条件:descendant在给定的部门ID列表中 ancestor: { isDomain: domain }, // 限定域 }, include: { ancestor: { include: { children: true, // 包含子节点信息 parent: true, // 包含父节点信息 }, }, }, orderBy: { ancestor: { order: 'asc' } }, // 按祖先节点顺序升序排序 }), // 查询自身部门数据 db.department.findMany({ where: { id: { in: deptIds }, isDomain: domain }, include: { children: true }, // 包含子节点信息 orderBy: { order: 'asc' }, // 按顺序升序排序 }), ]); // 查询根节点的直接子节点 const rootChildren = await db.deptAncestry.findMany({ where: { ancestorId: rootId, // 祖先ID为根ID descendant: { isDomain: domain }, // 限定域 }, }); /** * 判断祖先节点是否超出根节点层级的函数 * * @param ancestor - 祖先节点 * @returns 是否超出根节点层级 */ const isDirectDescendantOfRoot = (ancestor: DeptAncestry): boolean => { return ( rootChildren.findIndex( (child) => child.descendantId === ancestor.ancestorId, ) !== -1 ); }; // 处理父级节点:过滤并映射为简单树结构 const parents = parentData .map(({ ancestor }) => ancestor) // 提取祖先节点 .filter( (ancestor) => ancestor && isDirectDescendantOfRoot(ancestor as any), ) // 过滤有效且超出根节点层级的节点 .map(mapToDeptSimpleTree); // 映射为简单树结构 // 处理自身节点:映射为简单树结构 const selfItems = selfData.map(mapToDeptSimpleTree); // 合并并去重父级和自身节点,返回唯一项 return getUniqueItems([...parents, ...selfItems], 'id'); } }