124 lines
3.9 KiB
TypeScript
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 })
|
|
}
|
|
}
|