import type { PrismaClient } from '@prisma/client'; import { DataScope } from './enums.js'; /** 数据权限档位(从大到小)的优先级,用于多角色取最高权限。 */ const RANK: Record = { all: 5, dept_and_child: 4, dept: 3, custom: 2, self: 1, }; /** 从多个角色的 data_scope 中取最高权限档。 */ export function resolveDataScope(scopes: DataScope[]): DataScope { if (scopes.length === 0) return 'self'; return scopes.reduce((a, b) => (RANK[a] >= RANK[b] ? a : b)); } /** * 计算数据权限可见的部门 code 集合。 * 返回空数组表示「全部可见」(不受数据权限限制)。 */ export async function resolveVisibleOrgs(opts: { prisma: PrismaClient; tenantCode: string; dataScope: DataScope; orgCode: string | null; roleCodes: string[]; }): Promise { const { prisma, tenantCode, dataScope, orgCode, roleCodes } = opts; switch (dataScope) { case 'all': return []; case 'self': // 仅本人:不走组织过滤,由调用方按 userId 过滤(返回哨兵避免误放大为全量) return ['__none__']; case 'dept': return orgCode ? [orgCode] : ['__none__']; case 'dept_and_child': return orgCode ? collectDescendants(prisma, tenantCode, orgCode) : ['__none__']; case 'custom': { const rows = await prisma.roleOrg.findMany({ where: { tenantCode, roleCode: { in: roleCodes } }, select: { orgCode: true }, }); const codes: string[] = [...new Set(rows.map((r) => r.orgCode))]; return codes.length ? codes : ['__none__']; } } } /** 收集某部门及其全部后代部门的 code(含自身),带 visited 防环。 */ async function collectDescendants(prisma: PrismaClient, tenantCode: string, rootCode: string): Promise { const result: string[] = []; const visited = new Set(); let frontier = [rootCode]; while (frontier.length > 0) { const next: string[] = []; for (const code of frontier) { if (visited.has(code)) continue; visited.add(code); result.push(code); next.push(code); } if (next.length === 0) break; const children = await prisma.org.findMany({ where: { tenantCode, parentCode: { in: next }, deletedAt: null }, select: { code: true }, }); frontier = children.map((c) => c.code); } return result; }