import { Injectable } from '@nestjs/common'; import { db, RoleMapMethodSchema, ObjectType, Prisma, RowModelRequest, UserProfile, } from '@nice/common'; import { DepartmentService } from '@server/models/department/department.service'; import { TRPCError } from '@trpc/server'; import { RowModelService } from '../base/row-model.service'; import { isFieldCondition } from '../base/sql-builder'; import { z } from 'zod'; @Injectable() export class RoleMapService extends RowModelService { createJoinSql(request?: RowModelRequest): string[] { return [ `LEFT JOIN staff ON staff.id = ${this.tableName}.object_id`, `LEFT JOIN department ON department.id = staff.dept_id`, ]; } createUnGroupingRowSelect(): string[] { return [ `${this.tableName}.id AS id`, `${this.tableName}.object_id AS object_id`, `${this.tableName}.role_id AS role_id`, `${this.tableName}.domain_id AS domain_id`, `${this.tableName}.object_type AS object_type`, `staff.officer_id AS staff_officer_id`, `staff.username AS staff_username`, `department.name AS department_name`, `staff.showname AS staff_`, ]; } constructor(private readonly departmentService: DepartmentService) { super('rolemap'); } protected createGetRowsFilters( request: z.infer, staff: UserProfile, ) { const { roleId, domainId } = request; // Base conditions let condition = super.createGetRowsFilters(request, staff); if (isFieldCondition(condition)) return; // Adding conditions based on parameters existence if (roleId) { condition.AND.push({ field: `${this.tableName}.role_id`, value: roleId, op: 'equals', }); } if (domainId) { condition.AND.push({ field: `${this.tableName}.domain_id`, value: domainId, op: 'equals', }); } return condition; } protected async getRowDto(row: any, staff?: UserProfile): Promise { if (!row.id) return row; return row; } /** * 删除某对象的所有角色 * @param data 包含对象ID的数据 * @returns 删除结果 */ async deleteAllRolesForObject( data: z.infer, ) { const { objectId } = data; return await db.roleMap.deleteMany({ where: { objectId, }, }); } /** * 为某对象设置一个角色 * @param data 角色映射数据 * @returns 创建的角色映射 */ async setRoleForObject(data: z.infer) { return await db.roleMap.create({ data, }); } /** * 批量为多个对象创建角色映射 * @param data 角色映射数据 * @returns 创建的角色映射列表 */ async setRoleForObjects( data: z.infer, ) { const { domainId, roleId, objectIds, objectType } = data; const roleMaps = objectIds.map((id) => ({ domainId, objectId: id, roleId, objectType, })); // 开启事务 const result = await db.$transaction(async (prisma) => { // 首先,删除现有的角色映射 await prisma.roleMap.deleteMany({ where: { domainId, roleId, objectType, }, }); // 然后,创建新的角色映射 return await prisma.roleMap.createManyAndReturn({ data: roleMaps, }); }); const wrapResult = Promise.all( result.map(async (item) => { const staff = await db.staff.findMany({ include: { department: true }, where: { id: item.objectId, }, }); return { ...item, staff }; }), ); return wrapResult; } async addRoleForObjects( data: z.infer, ) { const { domainId, roleId, objectIds, objectType } = data; const objects = await db.roleMap.findMany({ where: { domainId, roleId, objectType }, }); data.objectIds = Array.from( new Set([...objectIds, ...objects.map((obj) => obj.objectId)]), ); const result = this.setRoleForObjects(data); return result; } /** * 为某对象设置多个角色 * @param data 角色映射数据 * @returns 创建的角色映射列表 */ async setRolesForObject( data: z.infer, ) { const { domainId, objectId, roleIds, objectType } = data; const roleMaps = roleIds.map((id) => ({ domainId, objectId, roleId: id, objectType, })); return await db.roleMap.createMany({ data: roleMaps }); } /** * 获取某对象的权限 * @param data 包含域ID、部门ID和对象ID的数据 * @returns 用户角色的权限列表 */ async getPermsForObject( data: z.infer, ) { const { domainId, deptId, staffId } = data; // Get all ancestor department IDs if deptId is provided. const ancestorDeptIds = deptId ? await this.departmentService.getAncestorIds(deptId) : []; // Define a common filter for querying roles. const objectFilters: Prisma.RoleMapWhereInput[] = [ { objectId: staffId, objectType: ObjectType.STAFF }, ...(deptId || ancestorDeptIds.length > 0 ? [ { objectId: { in: [deptId, ...ancestorDeptIds].filter(Boolean) }, objectType: ObjectType.DEPARTMENT, }, ] : []), ]; // Helper function to fetch roles based on domain ID. const fetchRoles = async (domainId: string) => { return db.roleMap.findMany({ where: { AND: { domainId, OR: objectFilters, }, }, include: { role: true }, }); }; // Fetch roles with and without specific domain IDs. const [nullDomainRoles, userRoles] = await Promise.all([ fetchRoles(null), fetchRoles(domainId), ]); // Extract permissions from roles and return them. return [...userRoles, ...nullDomainRoles].flatMap( ({ role }) => role.permissions, ); } /** * 批量删除角色映射 * @param data 包含要删除的角色映射ID列表的数据 * @returns 删除结果 * @throws 如果未提供ID,将抛出错误 */ async deleteMany(data: z.infer) { const { ids } = data; if (!ids || ids.length === 0) { throw new TRPCError({ code: 'BAD_REQUEST', message: 'No IDs provided for deletion.', }); } const rowData = await this.getRowByIds({ ids, extraCondition: {} }); await db.roleMap.deleteMany({ where: { id: { in: ids } }, }); return rowData; } /** * 分页获取角色映射 * @param data 包含分页信息的数据 * @returns 分页结果,包含角色映射列表和总数 */ async paginate(data: z.infer) { const { page, pageSize, domainId, roleId } = data; const [items, totalCount] = await Promise.all([ db.roleMap.findMany({ skip: (page - 1) * pageSize, take: pageSize, where: { domainId, roleId }, }), db.roleMap.count({ where: { domainId, roleId }, }), ]); // const processedItems = await Promise.all(items.map(item => this.genRoleMapDto(item))); return { items, totalCount }; } async getStaffsNotMap( data: z.infer, ) { const { domainId, roleId } = data; let staffs = await db.staff.findMany({ where: { domainId, }, }); const roleMaps = await db.roleMap.findMany({ where: { domainId, roleId, objectType: ObjectType.STAFF, }, }); staffs = staffs.filter( (staff) => roleMaps.findIndex((roleMap) => roleMap.objectId === staff.id) === -1, ); return staffs; } /** * 更新角色映射 * @param data 包含更新信息的数据 * @returns 更新后的角色映射 */ async update(data: z.infer) { const { id, ...others } = data; const updatedRoleMap = await db.roleMap.update({ where: { id }, data: { ...others }, }); return updatedRoleMap; } /** * 获取角色映射详情 * @param data 包含角色ID和域ID的数据 * @returns 角色映射详情,包含部门ID和员工ID列表 */ async getRoleMapDetail( data: z.infer, ) { const { roleId, domainId } = data; const res = await db.roleMap.findMany({ where: { roleId, domainId } }); const deptIds = res .filter((item) => item.objectType === ObjectType.DEPARTMENT) .map((item) => item.objectId); const staffIds = res .filter((item) => item.objectType === ObjectType.STAFF) .map((item) => item.objectId); return { deptIds, staffIds }; } }