import { Router, Request, Response } from 'express'; import { z } from 'zod'; import { authMiddleware } from '../middleware/auth'; import { prisma } from '../utils/prisma'; const router = Router(); // ============================================ // 获取用户统计 (公开) // ============================================ router.get('/stats/:userId', async (req: Request, res: Response) => { try { const { userId } = req.params; const user = await prisma.user.findUnique({ where: { id: userId }, select: { schemesCount: true, favoritesCount: true, isVip: true, vipExpireAt: true, createdAt: true, }, }); if (!user) { return res.status(404).json({ success: false, message: '用户不存在', }); } res.json({ success: true, data: { schemesCount: user.schemesCount, favoritesCount: user.favoritesCount, isVip: user.isVip, vipExpireAt: user.vipExpireAt, memberSince: user.createdAt, }, }); } catch (error) { console.error('Get user stats error:', error); res.status(500).json({ success: false, message: '获取失败' }); } }); // ============================================ // 获取用户方案列表 (公开) // ============================================ router.get('/schemes/:userId', async (req: Request, res: Response) => { try { const { userId } = req.params; const { type = 'schemes', page = 1, limit = 20 } = req.query; const pageNum = Math.max(1, parseInt(String(page)) || 1); const limitNum = Math.min(100, Math.max(1, parseInt(String(limit)) || 20)); const skip = (pageNum - 1) * limitNum; let schemes; if (type === 'aob') { schemes = await prisma.schemeAob.findMany({ where: { userId, status: 'PUBLISHED' }, orderBy: { createdAt: 'desc' }, skip, take: Number(limit), select: { id: true, title: true, weaponName: true, category: true, viewsCount: true, downloadsCount: true, likesCount: true, createdAt: true, }, }); } else { schemes = await prisma.scheme.findMany({ where: { userId, status: 'PUBLISHED' }, orderBy: { createdAt: 'desc' }, skip, take: Number(limit), select: { id: true, title: true, weaponName: true, category: true, viewsCount: true, downloadsCount: true, likesCount: true, createdAt: true, }, }); } res.json({ success: true, data: schemes, }); } catch (error) { console.error('Get user schemes error:', error); res.status(500).json({ success: false, message: '获取失败' }); } }); // ============================================ // 获取用户被收藏次数 (公开) // ============================================ router.get('/favorited-count/:userId', async (req: Request, res: Response) => { try { const { userId } = req.params; const user = await prisma.user.findUnique({ where: { id: userId }, select: { favoritesCount: true }, }); if (!user) { return res.status(404).json({ success: false, message: '用户不存在', }); } res.json({ success: true, favoritedCount: user.favoritesCount, }); } catch (error) { console.error('Get favorited count error:', error); res.status(500).json({ success: false, message: '获取失败' }); } }); // ============================================ // 获取用户功能限制信息 (公开) // ============================================ router.get('/limits/:userId', async (req: Request, res: Response) => { try { const { userId } = req.params; const user = await prisma.user.findUnique({ where: { id: userId }, select: { id: true, isVip: true, vipExpireAt: true }, }); if (!user) { return res.status(404).json({ success: false, message: '用户不存在' }); } const now = new Date(); const isVipActive = user.isVip && user.vipExpireAt && user.vipExpireAt > now; const limits = isVipActive ? { maxDailyUses: 500, dailyUsesLeft: 500, maxFavorites: 1000, maxSchemes: 200, canUploadIcc: true, } : { maxDailyUses: 50, dailyUsesLeft: 50, maxFavorites: 100, maxSchemes: 50, canUploadIcc: false, }; res.json({ success: true, ...limits }); } catch (error) { console.error('Get user limits error:', error); res.status(500).json({ success: false, message: '获取失败' }); } }); // ============================================ // 以下路由需要认证 // ============================================ router.use(authMiddleware); const updateUsernameSchema = z.object({ userId: z.string().uuid(), username: z.string().min(3).max(50), }); router.put('/username', async (req: Request, res: Response) => { try { const body = updateUsernameSchema.parse(req.body); // 验证用户 ID if (body.userId !== req.user!.userId) { return res.status(403).json({ success: false, message: '无权修改其他用户信息', }); } // 检查用户名是否已存在 const existing = await prisma.user.findUnique({ where: { username: body.username }, }); if (existing) { return res.status(400).json({ success: false, message: '用户名已被使用', }); } // 检查修改次数限制 const limit = await prisma.userLog.count({ where: { userId: req.user!.userId, action: 'UPDATE_USERNAME', }, }); if (limit >= 4) { return res.status(400).json({ success: false, message: '用户名修改次数已达上限', }); } // 更新用户名 await prisma.user.update({ where: { id: body.userId }, data: { username: body.username }, }); // 记录日志 await prisma.userLog.create({ data: { userId: req.user!.userId, action: 'UPDATE_USERNAME', ipAddress: req.ip, }, }); res.json({ success: true, message: '用户名更新成功', username: body.username, }); } catch (error) { if (error instanceof z.ZodError) { return res.status(400).json({ success: false, message: '参数验证失败', errors: error.errors }); } console.error('Update username error:', error); res.status(500).json({ success: false, message: '更新失败' }); } }); // ============================================ // 更新邮箱 // ============================================ const updateEmailSchema = z.object({ userId: z.string().uuid(), email: z.string().email(), }); router.put('/email', async (req: Request, res: Response) => { try { const body = updateEmailSchema.parse(req.body); if (body.userId !== req.user!.userId) { return res.status(403).json({ success: false, message: '无权修改其他用户信息', }); } // 检查邮箱是否已存在 const existing = await prisma.user.findUnique({ where: { email: body.email }, }); if (existing) { return res.status(400).json({ success: false, message: '邮箱已被使用', }); } await prisma.user.update({ where: { id: body.userId }, data: { email: body.email }, }); res.json({ success: true, message: '邮箱更新成功', email: body.email, }); } catch (error) { if (error instanceof z.ZodError) { return res.status(400).json({ success: false, message: '参数验证失败', errors: error.errors }); } console.error('Update email error:', error); res.status(500).json({ success: false, message: '更新失败' }); } }); // ============================================ // 更新头像 // ============================================ const updateAvatarSchema = z.object({ userId: z.string().uuid(), avatar: z.string().url(), }); router.put('/avatar', async (req: Request, res: Response) => { try { const body = updateAvatarSchema.parse(req.body); if (body.userId !== req.user!.userId) { return res.status(403).json({ success: false, message: '无权修改其他用户信息', }); } await prisma.user.update({ where: { id: body.userId }, data: { avatar: body.avatar }, }); res.json({ success: true, message: '头像更新成功', avatar: body.avatar, }); } catch (error) { if (error instanceof z.ZodError) { return res.status(400).json({ success: false, message: '参数验证失败', errors: error.errors }); } console.error('Update avatar error:', error); res.status(500).json({ success: false, message: '更新失败' }); } }); export default router;