chenpei d17f6df2c7 feat: 部门管理和文件上传优化
新功能:
1. 部门管理功能
   - 管理员可在系统设置中添加/删除部门
   - 用户注册时从下拉框选择部门
   - 新增Department数据库表和API

2. 文件上传优化
   - 支持直接上传源文件(.max/.psd/.ai/.cad/.dwg/.c4d)
   - 自动识别文件类型并设置素材类型
   - 压缩包需手动选择类型
   - 优化拖拽上传体验

数据库变更:
- 新增departments表
- User表新增department字段
2025-10-26 14:06:19 +08:00

169 lines
4.6 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 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
{ 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 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
}
}
// 计算总数和总页数
const totalCount = await prisma.material.count({ where })
const totalPages = Math.ceil(totalCount / pageSize)
// 构建排序规则
let orderBy: any = { createdAt: 'desc' }
if (sortBy === 'downloadCount') {
orderBy = { downloadCount: 'desc' }
}
// 获取分页数据
const materials = await prisma.material.findMany({
where,
include: {
user: {
select: {
username: true,
},
},
},
orderBy,
skip: (page - 1) * pageSize,
take: pageSize,
})
// 如果用户已登录,查询点赞状态
let userLikes: Set<string> = new Set()
if (session) {
const userId = (session.user as any).id
const likes = await prisma.materialLike.findMany({
where: {
userId,
materialId: {
in: materials.map(m => m.id)
}
},
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('Error fetching materials:', 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('Error deleting material:', error)
return NextResponse.json(
{ error: '删除失败' },
{ status: 500 }
)
}
}