chenpei ea9076df45 feat: 实现统一的下载错误处理系统并修复产品全案数据库Schema
- 创建统一的下载错误处理模块 (lib/download-errors.ts)
- 实现13种错误类型分类和中文错误消息
- 后端统一使用 createDownloadError 创建标准化错误响应
- 前端统一使用 parseDownloadError 解析错误并显示
- 修复正式系统数据库Schema,添加产品全案相关字段和表
- 执行数据库迁移:添加 task_no, task_status, task_fetched_at 字段
- 创建 material_assets, api_keys, api_call_logs 表
2026-01-05 17:52:42 +08:00

251 lines
7.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 });
}
}