WuYongJie d1c6efc79d
Some checks failed
CI Check / check (push) Has been cancelled
feat: NAS 部署与 Harbor 推送流程
2025-12-03 14:39:06 +08:00

161 lines
4.6 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server'
import { getServerSession } from 'next-auth'
import { authOptions } from '@/lib/auth'
import { prisma } from '@/lib/prisma'
import { createMaterialLog } from '@/lib/material-log'
import { buildDepartmentDescendants, isDepartmentWithinScope } from '@/lib/departments'
export const dynamic = 'force-dynamic'
export async function POST(req: NextRequest) {
try {
const session = await getServerSession(authOptions)
if (!session || (session.user as any).role !== 'ADMIN') {
return NextResponse.json({ error: '无操作权限' }, { status: 403 })
}
const { materialId, isPremium } = await req.json()
if (!materialId || typeof isPremium !== 'boolean') {
return NextResponse.json({ error: '参数错误' }, { status: 400 })
}
const operatorId = (session.user as any).id as string
const operator = await prisma.user.findUnique({
where: { id: operatorId },
select: {
id: true,
role: true,
isSuperAdmin: true,
department: true,
managedDepartment: true,
},
})
if (!operator) {
return NextResponse.json({ error: '未找到当前用户信息' }, { status: 403 })
}
const targetMaterial = await prisma.material.findUnique({
where: { id: materialId },
select: {
id: true,
isPremium: true,
user: {
select: {
id: true,
department: true,
},
},
},
})
if (!targetMaterial) {
return NextResponse.json({ error: '素材不存在' }, { status: 404 })
}
if (!operator.isSuperAdmin) {
const operatorScope = (operator.managedDepartment || operator.department || '').trim()
if (!operatorScope) {
return NextResponse.json(
{ error: '尚未配置所属组织,无法设置精品' },
{ status: 403 }
)
}
const targetDepartment = (targetMaterial.user?.department || '').trim()
if (!targetDepartment) {
return NextResponse.json(
{ error: '目标素材未设置所属组织,暂不支持跨组织加精' },
{ status: 403 }
)
}
let hasAccess =
targetDepartment === operatorScope ||
targetDepartment.startsWith(`${operatorScope}-`)
if (!hasAccess) {
const departments = await prisma.department.findMany({ select: { name: true } })
const descendantMap = buildDepartmentDescendants(departments)
hasAccess = isDepartmentWithinScope(operatorScope, targetDepartment, descendantMap)
}
if (!hasAccess) {
return NextResponse.json(
{ error: '只能为所属组织及下级组织的素材设置精品' },
{ status: 403 }
)
}
}
if (targetMaterial.isPremium === isPremium) {
return NextResponse.json({ success: true, material: targetMaterial })
}
if (isPremium) {
const settings = await prisma.systemSettings.findFirst({
select: { premiumRatio: true },
})
const ratio = settings?.premiumRatio ?? 10
if (ratio <= 0) {
return NextResponse.json(
{ error: '当前已禁用精品作品,请先在系统设置中开启' },
{ status: 400 }
)
}
const [totalMaterials, currentPremiumCount] = await Promise.all([
prisma.material.count(),
prisma.material.count({ where: { isPremium: true } }),
])
if (totalMaterials === 0) {
return NextResponse.json(
{ error: '暂无素材,无法设置精品作品' },
{ status: 400 }
)
}
const allowedCount = Math.max(1, Math.floor((totalMaterials * ratio) / 100))
if (currentPremiumCount >= allowedCount) {
return NextResponse.json(
{
error: `精品作品已达上限(${allowedCount} 条),请调整比例或取消其他素材的精品状态`,
},
{ status: 400 }
)
}
}
const updated = await prisma.material.update({
where: { id: materialId },
data: { isPremium },
select: {
id: true,
isPremium: true,
},
})
// 记录切换精品状态日志
await createMaterialLog({
materialId,
userId: operatorId,
action: 'TOGGLE_PREMIUM',
changes: {
isPremium: {
oldValue: targetMaterial.isPremium,
newValue: isPremium,
},
},
})
return NextResponse.json({ success: true, material: updated })
} catch (error) {
console.error('[MaterialPremium] POST error:', error)
return NextResponse.json({ error: '更新精品状态失败' }, { status: 500 })
}
}