208 lines
6.0 KiB
TypeScript
208 lines
6.0 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server'
|
||
import { getServerSession } from 'next-auth'
|
||
import { authOptions } from '@/lib/auth'
|
||
import { prisma } from '@/lib/prisma'
|
||
|
||
// Get all materials with search and filter support
|
||
export async function GET(req: NextRequest) {
|
||
try {
|
||
const session = await getServerSession(authOptions)
|
||
const { searchParams } = new URL(req.url)
|
||
const search = searchParams.get('search') || ''
|
||
const categoryName = searchParams.get('category') || ''
|
||
const sceneName = searchParams.get('scene') || ''
|
||
const materialType = searchParams.get('materialType') || ''
|
||
const platformName = searchParams.get('platform') || ''
|
||
const month = searchParams.get('month') || ''
|
||
const sortBy = searchParams.get('sortBy') || 'createdAt' // createdAt | downloadCount
|
||
const page = parseInt(searchParams.get('page') || '1')
|
||
const pageSize = parseInt(searchParams.get('pageSize') || '20')
|
||
|
||
// Build where clause
|
||
const where: any = {}
|
||
|
||
// Add search condition (search in SPU, shop, scene category, author)
|
||
if (search) {
|
||
where.OR = [
|
||
{ productModel: { contains: search, mode: 'insensitive' } }, // SPU
|
||
{ brandName: { contains: search, mode: 'insensitive' } }, // 品牌
|
||
{ seriesName: { contains: search, mode: 'insensitive' } }, // 系列
|
||
{ skuCode: { contains: search, mode: 'insensitive' } }, // SKU
|
||
{ materialTexture: { contains: search, mode: 'insensitive' } }, // 材质
|
||
{ categoryName: { contains: search, mode: 'insensitive' } }, // 使用店铺
|
||
{ sceneName: { contains: search, mode: 'insensitive' } }, // 场景类别
|
||
{ authorName: { contains: search, mode: 'insensitive' } }, // 作者
|
||
]
|
||
}
|
||
|
||
// Add shop filter (使用店铺)
|
||
if (categoryName) {
|
||
where.categoryName = categoryName
|
||
}
|
||
|
||
// Add scene category filter (场景类别)
|
||
if (sceneName) {
|
||
where.sceneName = sceneName
|
||
}
|
||
|
||
// Add material type filter (素材类型)
|
||
if (materialType) {
|
||
where.materialType = materialType
|
||
}
|
||
|
||
// Add platform filter (平台分类)
|
||
if (platformName) {
|
||
where.platformName = platformName
|
||
}
|
||
|
||
// Add month filter (上传月份)
|
||
if (month) {
|
||
const [year, monthNum] = month.split('-')
|
||
const startDate = new Date(parseInt(year), parseInt(monthNum) - 1, 1)
|
||
const endDate = new Date(parseInt(year), parseInt(monthNum), 1)
|
||
where.createdAt = {
|
||
gte: startDate,
|
||
lt: endDate
|
||
}
|
||
}
|
||
|
||
// 构建排序规则
|
||
let orderBy: any = { createdAt: 'desc' }
|
||
if (sortBy === 'downloadCount') {
|
||
orderBy = { downloadCount: 'desc' }
|
||
}
|
||
|
||
// 计算总数和分页数据(并行查询,优化性能)
|
||
const maxPageSize = Math.min(pageSize, 100) // 限制最大分页大小为 100
|
||
const [totalCount, materials] = 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,
|
||
renderer: true,
|
||
renderTime: true,
|
||
imageResolution: true,
|
||
colorMode: true,
|
||
authorName: true,
|
||
previewUrl: true,
|
||
zipFileName: true,
|
||
zipFileSize: true,
|
||
downloadCount: true,
|
||
likeCount: true,
|
||
displayImages: true,
|
||
createdAt: true,
|
||
userId: true,
|
||
user: {
|
||
select: {
|
||
username: true,
|
||
},
|
||
},
|
||
},
|
||
orderBy,
|
||
skip: (page - 1) * maxPageSize,
|
||
take: maxPageSize,
|
||
})
|
||
])
|
||
const totalPages = Math.ceil(totalCount / maxPageSize)
|
||
|
||
// 如果用户已登录,查询点赞状态(优化:只在有数据时查询)
|
||
let userLikes: Set<string> = new Set()
|
||
if (session && materials.length > 0) {
|
||
const userId = (session.user as any).id
|
||
const materialIds = materials.map(m => m.id)
|
||
const likes = await prisma.materialLike.findMany({
|
||
where: {
|
||
userId,
|
||
materialId: { in: materialIds }
|
||
},
|
||
select: {
|
||
materialId: true
|
||
}
|
||
})
|
||
userLikes = new Set(likes.map(l => l.materialId))
|
||
}
|
||
|
||
// 添加点赞状态到每个素材,并转换BigInt为字符串
|
||
const materialsWithLikeStatus = materials.map(material => ({
|
||
...material,
|
||
zipFileSize: material.zipFileSize.toString(),
|
||
isLiked: userLikes.has(material.id)
|
||
}))
|
||
|
||
return NextResponse.json({
|
||
materials: materialsWithLikeStatus,
|
||
totalPages,
|
||
totalCount,
|
||
currentPage: page,
|
||
})
|
||
} catch (error) {
|
||
console.error('[Materials] GET error:', error)
|
||
return NextResponse.json(
|
||
{ error: '获取素材列表失败' },
|
||
{ status: 500 }
|
||
)
|
||
}
|
||
}
|
||
|
||
// Delete material (admin only)
|
||
export async function DELETE(req: NextRequest) {
|
||
try {
|
||
const session = await getServerSession(authOptions)
|
||
|
||
if (!session || (session.user as any).role !== 'ADMIN') {
|
||
return NextResponse.json(
|
||
{ error: '无权限' },
|
||
{ status: 403 }
|
||
)
|
||
}
|
||
|
||
const { searchParams } = new URL(req.url)
|
||
const id = searchParams.get('id')
|
||
|
||
if (!id) {
|
||
return NextResponse.json(
|
||
{ error: '缺少素材ID' },
|
||
{ status: 400 }
|
||
)
|
||
}
|
||
|
||
// Get material to delete files
|
||
const material = await prisma.material.findUnique({
|
||
where: { id },
|
||
})
|
||
|
||
if (!material) {
|
||
return NextResponse.json(
|
||
{ error: '素材不存在' },
|
||
{ status: 404 }
|
||
)
|
||
}
|
||
|
||
// Delete from database
|
||
await prisma.material.delete({
|
||
where: { id },
|
||
})
|
||
|
||
// TODO: Delete files from S3 and local storage
|
||
|
||
return NextResponse.json({ message: '删除成功' })
|
||
} catch (error) {
|
||
console.error('[Materials] DELETE error:', error)
|
||
return NextResponse.json(
|
||
{ error: '删除失败' },
|
||
{ status: 500 }
|
||
)
|
||
}
|
||
}
|
||
|