WuYongJie f646b71813
Some checks failed
CI Check / check (push) Has been cancelled
chore: 初始化本地仓库并同步最近改动
2025-11-18 17:50:16 +08:00

208 lines
6.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 }
)
}
}