159 lines
6.3 KiB
TypeScript
159 lines
6.3 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server'
|
|
import { getServerSession } from 'next-auth'
|
|
import { authOptions } from '@/lib/auth'
|
|
import { prisma } from '@/lib/prisma'
|
|
import { isSuperAdmin } from '@/lib/department-permission'
|
|
import { BINDING_STATUS, PERMISSION_PATH_PROFILE_SELECT } from '@/lib/employee-directory'
|
|
import { findNearestGroupMemberships, resolveEmployeeOrganizationPaths, lastOrganizationPathSegment } from '@/lib/organization-material-permissions'
|
|
import { loadPermissionGroupDepartments } from '@/lib/permission-groups'
|
|
|
|
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(request: NextRequest) {
|
|
try {
|
|
if (!(await requireSuperAdmin())) {
|
|
return NextResponse.json({ error: '需要超级管理员权限' }, { status: 403 })
|
|
}
|
|
|
|
const keyword = String(new URL(request.url).searchParams.get('q') || '').trim()
|
|
if (keyword.length < 1) {
|
|
return NextResponse.json({ people: [], groups: [] })
|
|
}
|
|
|
|
const [bindings, packs, departmentRows, units] = await Promise.all([
|
|
prisma.userEmployeeBinding.findMany({
|
|
where: {
|
|
status: BINDING_STATUS.ACTIVE,
|
|
user: { isActive: true, dingtalkUserId: { not: null } },
|
|
OR: [
|
|
{ user: { username: { contains: keyword, mode: 'insensitive' } } },
|
|
{ user: { realName: { contains: keyword, mode: 'insensitive' } } },
|
|
{ employeeProfile: { displayName: { contains: keyword, mode: 'insensitive' } } },
|
|
{ employeeProfile: { jobNumber: { contains: keyword, mode: 'insensitive' } } },
|
|
],
|
|
},
|
|
take: 20,
|
|
select: {
|
|
userId: true,
|
|
user: {
|
|
select: {
|
|
username: true,
|
|
realName: true,
|
|
permissionInherits: {
|
|
select: { pack: { select: { slug: true, name: true } } },
|
|
},
|
|
},
|
|
},
|
|
employeeProfile: {
|
|
select: { ...PERMISSION_PATH_PROFILE_SELECT, displayName: true, departmentName: true, jobNumber: true },
|
|
},
|
|
},
|
|
}),
|
|
prisma.materialPermissionPack.findMany({
|
|
orderBy: { name: 'asc' },
|
|
select: { id: true, slug: true, name: true },
|
|
}),
|
|
loadPermissionGroupDepartments(),
|
|
prisma.organizationUnit.findMany({
|
|
where: { isActive: true }, select: { sourceDeptId: true, path: true },
|
|
}),
|
|
])
|
|
const pathBySourceDeptId = new Map(units.map((unit) => [String(unit.sourceDeptId), unit.path]))
|
|
const memberships = departmentRows.flatMap((row) => {
|
|
const pack = packs.find((item) => item.id === row.packId)
|
|
if (!pack || !row.organizationUnit?.isActive) return []
|
|
return [{ departmentPath: row.organizationUnit.path, slug: pack.slug, name: pack.name }]
|
|
})
|
|
|
|
return NextResponse.json({
|
|
groups: packs.map((pack) => ({ slug: pack.slug, name: pack.name })),
|
|
people: bindings.map((binding) => {
|
|
const paths = resolveEmployeeOrganizationPaths(binding.employeeProfile, pathBySourceDeptId)
|
|
const path = paths[0] || null
|
|
const departmentGroups = Array.from(new Map(paths.flatMap((currentPath) => {
|
|
const nearest = findNearestGroupMemberships(currentPath, memberships)
|
|
return nearest ? nearest.items.map((item) => {
|
|
const group = { slug: item.slug, name: item.name, attachedPath: nearest.attachedPath,
|
|
source: nearest.attachedPath === currentPath ? 'own' : 'inherit' }
|
|
return [`${item.slug}:${nearest.attachedPath}`, group] as const
|
|
}) : []
|
|
})).values())
|
|
const personalGroups = binding.user.permissionInherits.map((row) => ({
|
|
slug: row.pack.slug,
|
|
name: row.pack.name,
|
|
}))
|
|
return {
|
|
userId: binding.userId,
|
|
username: binding.user.username,
|
|
displayName: binding.employeeProfile.displayName || binding.user.realName || binding.user.username,
|
|
jobNumber: binding.employeeProfile.jobNumber,
|
|
departmentPath: path,
|
|
departmentName: path ? lastOrganizationPathSegment(path) : null,
|
|
departmentGroups,
|
|
personalGroups,
|
|
}
|
|
}),
|
|
})
|
|
} catch (error) {
|
|
console.error('[user-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 action = String(body?.action || '').trim()
|
|
const userId = String(body?.userId || '').trim()
|
|
const slug = String(body?.slug || '').trim()
|
|
if (!userId) return NextResponse.json({ error: '请选择人员' }, { status: 400 })
|
|
if (!slug) return NextResponse.json({ error: '缺少权限组' }, { status: 400 })
|
|
|
|
const [user, pack] = await Promise.all([
|
|
prisma.user.findUnique({
|
|
where: { id: userId },
|
|
select: { id: true, dingtalkUserId: true },
|
|
}),
|
|
prisma.materialPermissionPack.findUnique({
|
|
where: { slug },
|
|
select: { id: true },
|
|
}),
|
|
])
|
|
if (!user) return NextResponse.json({ error: '没有这个账号' }, { status: 400 })
|
|
if (!user.dingtalkUserId) {
|
|
return NextResponse.json({ error: '这个账号没有钉钉绑定,不能进权限组' }, { status: 400 })
|
|
}
|
|
if (!pack) return NextResponse.json({ error: '没有这个权限组' }, { status: 400 })
|
|
|
|
if (action === 'remove-member') {
|
|
await prisma.userPermissionInherit.deleteMany({
|
|
where: { userId, packId: pack.id },
|
|
})
|
|
return NextResponse.json({ ok: true })
|
|
}
|
|
|
|
if (action === 'add-member') {
|
|
await prisma.userPermissionInherit.upsert({
|
|
where: { userId_packId: { userId, packId: pack.id } },
|
|
update: {},
|
|
create: { userId, packId: pack.id },
|
|
})
|
|
return NextResponse.json({ ok: true })
|
|
}
|
|
|
|
return NextResponse.json({ error: '不认识这个操作' }, { status: 400 })
|
|
} catch (error) {
|
|
console.error('[user-permissions] PUT failed', error)
|
|
return NextResponse.json({ error: '保存人员权限失败' }, { status: 500 })
|
|
}
|
|
}
|