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' import { createMaterialLog } from '@/lib/material-log' // UUID 格式校验正则 const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i /** * 批量删除素材(软删除或永久删除) * * 改进点: * 1. 使用 isSystemAdmin() 统一权限校验 * 2. 永久删除时会物理删除 S3/本地文件 * 3. 永久删除时会删除关联记录(MaterialAsset, MaterialSku) * 4. 增加 ID 格式校验 */ export async function POST(request: NextRequest) { try { const session = await getServerSession(authOptions) // 使用统一的权限检查函数(与单条删除保持一致) if (!session || !isSystemAdmin((session.user as any)?.role)) { return NextResponse.json({ error: '无权限,需要系统管理员权限' }, { status: 403 }) } const { ids, permanent } = await request.json() const operatorId = (session.user as any).id if (!operatorId) { return NextResponse.json({ error: '缺少操作人信息' }, { status: 401 }) } // 校验 ids 是数组且非空 if (!Array.isArray(ids) || ids.length === 0) { return NextResponse.json({ error: '请提供要删除的素材ID列表' }, { status: 400 }) } // 校验每个 ID 的格式(防止注入) const invalidIds = ids.filter(id => typeof id !== 'string' || !UUID_REGEX.test(id)) if (invalidIds.length > 0) { return NextResponse.json({ error: `存在无效的素材ID格式: ${invalidIds.slice(0, 3).join(', ')}${invalidIds.length > 3 ? '...' : ''}` }, { status: 400 }) } if (permanent) { return NextResponse.json({ error: '批量永久删除已暂停:请使用可恢复删除;待持久化清理任务上线后再开放物理删除', code: 'PERMANENT_DELETE_DISABLED', }, { status: 409 }) } else { // ========== 软删除:仅标记 deletedAt ========== // 查询素材(需要处理任务号) const materials = await prisma.material.findMany({ where: { id: { in: ids } }, select: { id: true, taskNo: true, productModel: true, materialType: true } }) if (materials.length === 0) { return NextResponse.json({ error: '未找到要删除的素材' }, { status: 404 }) } const deletedAt = new Date() await prisma.$transaction([ prisma.material.updateMany({ where: { id: { in: materials.map((m) => m.id) } }, data: { deletedAt, }, }), prisma.materialSku.updateMany({ where: { materialId: { in: materials.map((m) => m.id) }, deletedAt: null, }, data: { deletedAt, }, }), ]) await Promise.all( materials.map((material) => createMaterialLog({ materialId: material.id, userId: operatorId, action: 'DELETE', changes: { materialSnapshot: { oldValue: null, newValue: { id: material.id, productModel: material.productModel, materialType: material.materialType, }, }, deletedAt: { oldValue: null, newValue: deletedAt.toISOString(), }, deleteMode: { oldValue: 'active', newValue: 'soft', }, }, }) ) ) console.log(`[BatchDelete] 软删除完成: ${materials.length} 条素材`) return NextResponse.json({ success: true, message: '批量删除成功(已移入回收站)', details: { deletedRecords: materials.length, } }) } } catch (error) { console.error('[BatchDelete] Error:', error) return NextResponse.json({ error: '批量删除失败' }, { status: 500 }) } }