import { NextRequest, NextResponse } from 'next/server' import { getServerSession } from 'next-auth' import { authOptions } from '@/lib/auth' import { prisma } from '@/lib/prisma' import { getAllMaterialTypes, isSuperAdmin } from '@/lib/department-permission' import { filterSelectableMaterialTypes } from '@/lib/material-type-options' import { collectOccupiedOrganizationPaths, pruneOrganizationTree, resolveOrganizationPermissionKey, type MaterialPermissionFlags, } from '@/lib/organization-material-permissions' type OrgNode = { id: string name: string path: string level: number parentId: string | null children: OrgNode[] } const emptyFlags = (): MaterialPermissionFlags => ({ canView: false, canDownload: false, canDownloadSource: false, canShare: true, canEditAssets: false, }) async function requireSuperAdmin() { const session = await getServerSession(authOptions) const userId = (session?.user as { id?: string } | undefined)?.id if (!session || !(await isSuperAdmin(userId))) { return null } return session } export async function GET() { try { if (!(await requireSuperAdmin())) { return NextResponse.json({ error: '需要超级管理员权限' }, { status: 403 }) } const [units, rows, materialTypes, bindings] = await Promise.all([ prisma.organizationUnit.findMany({ where: { isActive: true }, select: { id: true, name: true, path: true, level: true, parentId: true }, orderBy: [{ level: 'asc' }, { name: 'asc' }], }), prisma.departmentMaterialPermission.findMany({ select: { department: true, materialType: true, canView: true, canDownload: true, canDownloadSource: true, canShare: true, }, }), getAllMaterialTypes().then(filterSelectableMaterialTypes), prisma.userEmployeeBinding.findMany({ where: { status: 'ACTIVE', user: { isActive: true } }, select: { employeeProfile: { select: { departmentPath: true } } }, }), ]) const stored = new Map>() for (const row of rows) { const current = stored.get(row.department) || {} current[row.materialType] = { canView: row.canView, canDownload: row.canDownload, canDownloadSource: row.canDownloadSource, canShare: row.canShare, canEditAssets: false, } stored.set(row.department, current) } const storedKeys = new Set(stored.keys()) const nodeMap = new Map() for (const unit of units) { nodeMap.set(unit.id, { ...unit, children: [] }) } const roots: OrgNode[] = [] for (const node of Array.from(nodeMap.values())) { if (node.parentId && nodeMap.has(node.parentId)) { nodeMap.get(node.parentId)!.children.push(node) } else { roots.push(node) } } const occupiedPaths = collectOccupiedOrganizationPaths( bindings.map((binding) => binding.employeeProfile?.departmentPath), ) const tree = pruneOrganizationTree(roots, occupiedPaths) const permissions: Record> = {} const sources: Record = {} for (const unit of units) { const resolved = resolveOrganizationPermissionKey(unit.path, storedKeys) const flags: Record = {} const storedFlags = resolved && resolved.source !== 'none' ? stored.get(resolved.key) || {} : {} for (const materialType of materialTypes) { flags[materialType] = storedFlags[materialType] ? { ...storedFlags[materialType] } : emptyFlags() } permissions[unit.path] = flags sources[unit.path] = { source: resolved?.source || 'none', storageKey: resolved && resolved.source !== 'none' ? resolved.key : null, inheritFrom: resolved?.inheritFrom || null, } } return NextResponse.json({ tree, materialTypes, permissions, sources, }) } catch (error) { console.error('[organization material-permissions] GET failed', error) return NextResponse.json({ error: '获取部门权限配置失败' }, { status: 500 }) } } export async function PUT(request: NextRequest) { try { if (!(await requireSuperAdmin())) { return NextResponse.json({ error: '需要超级管理员权限' }, { status: 403 }) } const body = await request.json() const path = String(body?.path || '').trim() const action = String(body?.action || 'save') const incoming: Array<{ materialType: string canView?: boolean canDownload?: boolean canDownloadSource?: boolean canShare?: boolean }> = Array.isArray(body?.permissions) ? body.permissions : [] const unit = await prisma.organizationUnit.findFirst({ where: { isActive: true, path }, select: { path: true, name: true }, }) if (!unit) { return NextResponse.json({ error: '花名册里没有这个部门' }, { status: 400 }) } if (action === 'inherit') { await prisma.departmentMaterialPermission.deleteMany({ where: { department: unit.path }, }) return NextResponse.json({ ok: true }) } if (incoming.length === 0) { return NextResponse.json({ error: '素材类型列表不能为空' }, { status: 400 }) } await prisma.$transaction( incoming .filter((item) => item.materialType) .map((item) => prisma.departmentMaterialPermission.upsert({ where: { department_materialType: { department: unit.path, materialType: item.materialType, }, }, update: { canView: item.canView ?? false, canDownload: item.canDownload ?? false, canDownloadSource: item.canDownloadSource ?? false, canShare: item.canShare ?? true, linkedToDepartment: null, }, create: { department: unit.path, materialType: item.materialType, canView: item.canView ?? false, canDownload: item.canDownload ?? false, canDownloadSource: item.canDownloadSource ?? false, canShare: item.canShare ?? true, linkedToDepartment: null, }, }), ), ) return NextResponse.json({ ok: true }) } catch (error) { console.error('[organization material-permissions] PUT failed', error) return NextResponse.json({ error: '保存部门权限配置失败' }, { status: 500 }) } }