2026-06-01 11:24:54 +08:00

124 lines
3.9 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server'
import { getServerSession } from 'next-auth'
import { Prisma } from '@prisma/client'
import { authOptions } from '@/lib/auth'
import { prisma } from '@/lib/prisma'
import { buildMaterialManagementScopeWhere, getMaterialPermissionActor } from '@/lib/material-permissions'
export const dynamic = 'force-dynamic'
const DEFAULT_EXPORT_LIMIT = 10000
const MAX_EXPORT_LIMIT = 10000
function parseExportLimit(value: string | null) {
const parsed = Number.parseInt(value || '', 10)
if (!Number.isFinite(parsed) || parsed <= 0) {
return DEFAULT_EXPORT_LIMIT
}
return Math.min(parsed, MAX_EXPORT_LIMIT)
}
export async function GET(req: NextRequest) {
try {
const session = await getServerSession(authOptions)
if (!session?.user) {
return NextResponse.json({ error: '未登录' }, { status: 401 })
}
const actor = await getMaterialPermissionActor(session)
if (!actor || (actor.role !== 'ADMIN' && !actor.isSuperAdmin)) {
return NextResponse.json({ error: '需要管理员权限' }, { status: 403 })
}
const { searchParams } = new URL(req.url)
const limit = parseExportLimit(searchParams.get('limit'))
const scopeWhere = await buildMaterialManagementScopeWhere(actor)
const filters: Prisma.MaterialWhereInput[] = [{ deletedAt: null }]
if (Object.keys(scopeWhere).length > 0) {
filters.push(scopeWhere)
}
const where: Prisma.MaterialWhereInput = filters.length === 1 ? filters[0] : { AND: filters }
const [totalCount, rawMaterials] = await Promise.all([
prisma.material.count({ where }),
prisma.material.findMany({
where,
select: {
id: true,
productModel: true,
brandName: true,
seriesName: true,
skuCode: true,
materialTexture: true,
categoryName: true,
sceneName: true,
platformName: true,
materialType: true,
materialKind: true,
renderer: true,
renderTime: true,
imageResolution: true,
colorMode: true,
authorName: true,
metadata: true,
templateId: true,
zipFileName: true,
zipFileSize: true,
downloadCount: true,
likeCount: true,
isPremium: true,
createdAt: true,
updatedAt: true,
user: {
select: {
username: true,
},
},
},
orderBy: { createdAt: 'desc' },
take: limit,
}),
])
const materials = rawMaterials.map((material) => {
let parsedMetadata: Record<string, unknown> | null = null
if (material.metadata) {
try {
const parsed = JSON.parse(material.metadata)
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
parsedMetadata = parsed as Record<string, unknown>
}
} catch {
parsedMetadata = null
}
}
const templateFields =
parsedMetadata?.templateFields && typeof parsedMetadata.templateFields === 'object' && !Array.isArray(parsedMetadata.templateFields)
? parsedMetadata.templateFields
: {}
return {
...material,
metadata: material.metadata,
templateId: material.templateId ?? (typeof parsedMetadata?.templateId === 'string' ? parsedMetadata.templateId : null),
templateFields,
zipFileSize: material.zipFileSize.toString(),
createdAt: material.createdAt.toISOString(),
updatedAt: material.updatedAt.toISOString(),
}
})
return NextResponse.json({
materials,
totalCount,
exportedCount: materials.length,
limit,
})
} catch (error) {
console.error('[AdminMaterialsExport] GET error:', error)
return NextResponse.json({ error: '导出素材数据失败' }, { status: 500 })
}
}