- 创建统一的下载错误处理模块 (lib/download-errors.ts) - 实现13种错误类型分类和中文错误消息 - 后端统一使用 createDownloadError 创建标准化错误响应 - 前端统一使用 parseDownloadError 解析错误并显示 - 修复正式系统数据库Schema,添加产品全案相关字段和表 - 执行数据库迁移:添加 task_no, task_status, task_fetched_at 字段 - 创建 material_assets, api_keys, api_call_logs 表
251 lines
7.4 KiB
TypeScript
251 lines
7.4 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server';
|
||
import { getServerSession } from 'next-auth';
|
||
import { authOptions } from '@/lib/auth';
|
||
import { prisma } from '@/lib/prisma';
|
||
import { createDefaultPermissionsForDepartment, isSystemAdmin } from '@/lib/department-permission';
|
||
|
||
// GET /api/departments - 获取部门列表
|
||
export async function GET(request: NextRequest) {
|
||
try {
|
||
const { searchParams } = new URL(request.url);
|
||
const includeHierarchy = searchParams.get('includeHierarchy') === 'true';
|
||
const status = searchParams.get('status'); // 可选:active/disabled/archived
|
||
|
||
// 构建查询条件
|
||
const where: any = {};
|
||
if (status) {
|
||
// 如果指定了status参数,使用它
|
||
where.status = status;
|
||
}
|
||
// 注意:如果不指定status,返回所有部门(包括向后兼容的情况)
|
||
|
||
if (includeHierarchy) {
|
||
// 新方式:支持层级查询
|
||
const departments = await prisma.department.findMany({
|
||
where,
|
||
include: {
|
||
parent: {
|
||
select: {
|
||
id: true,
|
||
name: true,
|
||
code: true,
|
||
level: true,
|
||
},
|
||
},
|
||
children: {
|
||
select: {
|
||
id: true,
|
||
name: true,
|
||
code: true,
|
||
level: true,
|
||
status: true,
|
||
},
|
||
orderBy: [
|
||
{ sortOrder: 'asc' },
|
||
{ name: 'asc' },
|
||
],
|
||
},
|
||
manager: {
|
||
select: {
|
||
id: true,
|
||
email: true,
|
||
username: true,
|
||
realName: true,
|
||
},
|
||
},
|
||
},
|
||
orderBy: [
|
||
{ level: 'asc' },
|
||
{ sortOrder: 'asc' },
|
||
{ name: 'asc' },
|
||
],
|
||
});
|
||
|
||
return NextResponse.json(departments);
|
||
} else {
|
||
// 旧方式:扁平列表(向后兼容)
|
||
const departments = await prisma.department.findMany({
|
||
where,
|
||
orderBy: [
|
||
{ sortOrder: 'asc' },
|
||
{ name: 'asc' },
|
||
],
|
||
});
|
||
|
||
return NextResponse.json(departments);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error fetching departments:', error);
|
||
return NextResponse.json({ error: '获取部门列表失败' }, { status: 500 });
|
||
}
|
||
}
|
||
|
||
// POST /api/departments - 创建部门
|
||
export async function POST(request: NextRequest) {
|
||
try {
|
||
const session = await getServerSession(authOptions);
|
||
// 使用兼容性检查:ADMIN 和 SYSTEM_ADMIN 都可以管理部门
|
||
if (!session || !session.user || !isSystemAdmin((session.user as any).role)) {
|
||
return NextResponse.json({ error: '无权限' }, { status: 403 });
|
||
}
|
||
|
||
const body = await request.json();
|
||
const {
|
||
name,
|
||
parentId,
|
||
code,
|
||
level,
|
||
managerId,
|
||
status,
|
||
description,
|
||
sortOrder
|
||
} = body;
|
||
|
||
if (!name || name.trim() === '') {
|
||
return NextResponse.json({ error: '部门名称不能为空' }, { status: 400 });
|
||
}
|
||
|
||
// 检查部门是否已存在
|
||
const existing = await prisma.department.findUnique({
|
||
where: { name },
|
||
});
|
||
|
||
if (existing) {
|
||
return NextResponse.json({ error: '部门已存在' }, { status: 400 });
|
||
}
|
||
|
||
// 如果指定了parentId,验证父部门是否存在
|
||
let calculatedLevel = level ?? 1;
|
||
if (parentId) {
|
||
const parent = await prisma.department.findUnique({
|
||
where: { id: parentId },
|
||
select: { level: true, status: true },
|
||
});
|
||
|
||
if (!parent) {
|
||
return NextResponse.json({ error: '父部门不存在' }, { status: 400 });
|
||
}
|
||
|
||
if (parent.status !== 'active') {
|
||
return NextResponse.json({ error: '父部门未启用,无法创建子部门' }, { status: 400 });
|
||
}
|
||
|
||
// 计算层级(父部门层级 + 1)
|
||
calculatedLevel = (parent.level ?? 1) + 1;
|
||
|
||
if (calculatedLevel > 3) {
|
||
return NextResponse.json({ error: '部门层级不能超过3级' }, { status: 400 });
|
||
}
|
||
}
|
||
|
||
// 构建创建数据
|
||
const createData: any = {
|
||
name,
|
||
level: calculatedLevel,
|
||
status: status ?? 'active',
|
||
sortOrder: sortOrder ?? 0,
|
||
};
|
||
|
||
// 可选字段
|
||
if (parentId) createData.parentId = parentId;
|
||
if (code) createData.code = code;
|
||
if (managerId) {
|
||
createData.managerId = managerId;
|
||
// 设置部门管理员时,自动将用户角色设置为DEPT_ADMIN
|
||
await prisma.user.update({
|
||
where: { id: managerId },
|
||
data: { role: 'DEPT_ADMIN' },
|
||
});
|
||
}
|
||
if (description) createData.description = description;
|
||
|
||
const department = await prisma.department.create({
|
||
data: createData,
|
||
});
|
||
|
||
// 自动创建默认权限配置
|
||
try {
|
||
await createDefaultPermissionsForDepartment(name);
|
||
} catch (error) {
|
||
console.error('Error creating default permissions for department:', error);
|
||
// 不阻止部门创建,只记录错误
|
||
}
|
||
|
||
return NextResponse.json(department, { status: 201 });
|
||
} catch (error: any) {
|
||
console.error('Error creating department:', error);
|
||
|
||
// 处理唯一约束错误
|
||
if (error.code === 'P2002') {
|
||
if (error.meta?.target?.includes('code')) {
|
||
return NextResponse.json({ error: '部门编码已存在' }, { status: 400 });
|
||
}
|
||
if (error.meta?.target?.includes('name')) {
|
||
return NextResponse.json({ error: '部门名称已存在' }, { status: 400 });
|
||
}
|
||
}
|
||
|
||
return NextResponse.json({ error: '创建部门失败' }, { status: 500 });
|
||
}
|
||
}
|
||
|
||
// DELETE /api/departments - 删除部门(保留向后兼容,建议使用 DELETE /api/departments/[id])
|
||
export async function DELETE(request: NextRequest) {
|
||
try {
|
||
const session = await getServerSession(authOptions);
|
||
// 使用兼容性检查:ADMIN 和 SYSTEM_ADMIN 都可以管理部门
|
||
if (!session || !session.user || !isSystemAdmin((session.user as any).role)) {
|
||
return NextResponse.json({ error: '无权限' }, { status: 403 });
|
||
}
|
||
|
||
const { searchParams } = new URL(request.url);
|
||
const id = searchParams.get('id');
|
||
|
||
if (!id) {
|
||
return NextResponse.json({ error: '缺少部门ID' }, { status: 400 });
|
||
}
|
||
|
||
// 检查部门是否存在
|
||
const department = await prisma.department.findUnique({
|
||
where: { id },
|
||
include: {
|
||
children: {
|
||
select: { id: true, name: true },
|
||
},
|
||
users: {
|
||
select: { id: true },
|
||
},
|
||
},
|
||
});
|
||
|
||
if (!department) {
|
||
return NextResponse.json({ error: '部门不存在' }, { status: 404 });
|
||
}
|
||
|
||
// 检查是否有子部门
|
||
if (department.children && department.children.length > 0) {
|
||
return NextResponse.json(
|
||
{ error: '该部门有子部门,不能删除。请先删除或移动所有子部门' },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
// 检查是否有用户
|
||
if (department.users && department.users.length > 0) {
|
||
return NextResponse.json(
|
||
{ error: '该部门有用户,不能删除。请先将用户移动到其他部门' },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
await prisma.department.delete({
|
||
where: { id },
|
||
});
|
||
|
||
return NextResponse.json({ message: '删除成功' });
|
||
} catch (error) {
|
||
console.error('Error deleting department:', error);
|
||
return NextResponse.json({ error: '删除失败' }, { status: 500 });
|
||
}
|
||
}
|