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

104 lines
3.0 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.

// 切换用户激活状态API
import { NextRequest, NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import { prisma } from '@/lib/prisma';
import { isSystemAdmin } from '@/lib/department-permission';
// POST - 切换用户激活状态(仅管理员)
export async function POST(request: NextRequest) {
try {
const session = await getServerSession(authOptions);
if (!session || !isSystemAdmin(session.user.role)) {
return NextResponse.json(
{ error: '无权限' },
{ status: 403 }
);
}
const { userId, isActive, status } = await request.json();
// 支持新旧两种参数格式
let targetStatus: string;
let targetIsActive: boolean;
if (status !== undefined) {
// 新格式:使用 status 参数
if (!['pending', 'active', 'suspended', 'archived'].includes(status)) {
return NextResponse.json(
{ error: '无效的状态值' },
{ status: 400 }
);
}
targetStatus = status;
targetIsActive = status === 'active';
} else if (isActive !== undefined) {
// 旧格式:使用 isActive 参数(向后兼容)
if (typeof isActive !== 'boolean') {
return NextResponse.json(
{ error: '参数错误' },
{ status: 400 }
);
}
targetIsActive = isActive;
targetStatus = isActive ? 'active' : 'pending';
} else {
return NextResponse.json(
{ error: '缺少参数:需要 isActive 或 status' },
{ status: 400 }
);
}
if (!userId) {
return NextResponse.json(
{ error: '缺少用户ID' },
{ status: 400 }
);
}
// 不能禁用自己
if (userId === session.user.id) {
return NextResponse.json(
{ error: '不能禁用自己' },
{ status: 400 }
);
}
// 双写:同时更新 status 和 isActive
const updateData: any = {
isActive: targetIsActive, // 旧字段(向后兼容)
status: targetStatus, // 新字段(阶段一新增)
};
// 如果状态为 archived,设置 archivedAt
if (targetStatus === 'archived') {
updateData.archivedAt = new Date();
} else if (targetStatus !== 'archived') {
// 如果从 archived 状态恢复,清除 archivedAt
updateData.archivedAt = null;
}
await prisma.user.update({
where: { id: userId },
data: updateData,
});
const statusMessages: Record<string, string> = {
'pending': '用户已设置为待激活',
'active': '用户已激活',
'suspended': '用户已暂停',
'archived': '用户已归档',
};
return NextResponse.json({
message: statusMessages[targetStatus] || (targetIsActive ? '用户已激活' : '用户已禁用'),
});
} catch (error) {
console.error('Toggle active error:', error);
return NextResponse.json(
{ error: '操作失败' },
{ status: 500 }
);
}
}