import { Router, Request, Response } from 'express'; import { z } from 'zod'; import { authMiddleware } from '../middleware/auth'; import { prisma } from '../utils/prisma'; const router = Router(); router.use(authMiddleware); // source → targetType 映射 function sourceToType(source?: string): string { if (source === '全面战场' || source === 'schemes_aob') return 'SCHEME_AOB'; return 'SCHEME'; // 烽火地带 / schemes } // 格式化方案卡片(对齐顶层 API) function formatScheme(s: any) { return { id: s.id, user_id: s.userId, description: s.description || '', scheme_content: s.schemeContent || '', category: s.category || '', weapon_name: s.weaponName || '', price: s.price ? `${s.price}W` : null, tags: [], uses: s.downloadsCount || 0, status: 'normal', comments: null, shares: null, created_at: s.createdAt?.toISOString?.() || s.createdAt, updated_at: s.updatedAt?.toISOString?.() || s.updatedAt, source: null, total_historical_uses: s.downloadsCount || 0, username: s.user?.username || '', avatar: s.user?.avatar || '', partner_type: null, partner_level: null, partner_badge: null, partner_logo: null, social_link: null, likes: null, }; } // ============================================ // 获取收藏列表 (对齐 GET /api/favorites) // ============================================ router.get('/', async (req: Request, res: Response) => { try { const { page = '1', limit = '12', sort = 'hot', weaponCategory, weaponName, search } = req.query; const pageNum = Math.max(1, parseInt(String(page)) || 1); const limitNum = Math.min(100, Math.max(1, parseInt(String(limit)) || 12)); // 先查用户的收藏记录 const total = await prisma.favorite.count({ where: { userId: req.user!.userId } }); const favorites = await prisma.favorite.findMany({ where: { userId: req.user!.userId }, orderBy: { createdAt: 'desc' }, skip: (pageNum - 1) * limitNum, take: limitNum, }); // 加载关联的方案数据 const data: any[] = []; for (const fav of favorites) { let scheme: any = null; if (fav.targetType === 'SCHEME') { scheme = await prisma.scheme.findUnique({ where: { id: fav.targetId }, include: { user: { select: { username: true, avatar: true } } }, }); } else if (fav.targetType === 'SCHEME_AOB') { scheme = await prisma.schemeAob.findUnique({ where: { id: fav.targetId }, include: { user: { select: { username: true, avatar: true } } }, }); } if (scheme && scheme.status === 'PUBLISHED') { data.push(formatScheme(scheme)); } } res.json({ success: true, data, pagination: { page: pageNum, limit: limitNum, hasMore: pageNum * limitNum < total }, }); } catch (error) { console.error('Get favorites error:', error); res.status(500).json({ success: false, message: '获取失败' }); } }); // ============================================ // 添加收藏 (对齐 POST /api/favorites) // body: { schemeId, source: "烽火地带" } // ============================================ const addFavoriteSchema = z.object({ schemeId: z.string().or(z.number()), source: z.string().optional(), }); router.post('/', async (req: Request, res: Response) => { try { const body = addFavoriteSchema.parse(req.body); const targetType = sourceToType(body.source); const targetId = String(body.schemeId); const existing = await prisma.favorite.findFirst({ where: { userId: req.user!.userId, targetType, targetId }, }); if (existing) { return res.json({ success: true, alreadyFavorited: true }); } // 验证目标存在 let targetExists = false; if (targetType === 'SCHEME') { targetExists = !!(await prisma.scheme.findFirst({ where: { id: targetId, status: 'PUBLISHED' } })); } else { targetExists = !!(await prisma.schemeAob.findFirst({ where: { id: targetId, status: 'PUBLISHED' } })); } if (!targetExists) { return res.status(404).json({ success: false, message: '方案不存在' }); } await prisma.favorite.create({ data: { userId: req.user!.userId, targetType, targetId }, }); res.json({ success: true, alreadyFavorited: false }); } catch (error) { console.error('Add favorite error:', error); res.status(500).json({ success: false, message: '收藏失败' }); } }); // ============================================ // 取消收藏 (对齐 DELETE /api/favorites/:schemeId?source=xxx) // ============================================ router.delete('/:schemeId', async (req: Request, res: Response) => { try { const { schemeId } = req.params; const source = req.query.source as string | undefined; const targetType = sourceToType(source); const favorite = await prisma.favorite.findFirst({ where: { userId: req.user!.userId, targetType, targetId: schemeId }, }); if (!favorite) { return res.status(404).json({ success: false, message: '收藏不存在' }); } await prisma.favorite.delete({ where: { id: favorite.id } }); res.json({ success: true }); } catch (error) { console.error('Remove favorite error:', error); res.status(500).json({ success: false, message: '取消收藏失败' }); } }); // ============================================ // 检查收藏状态 (对齐 GET /api/favorites/check?schemeId=xx&source=xx) // ============================================ router.get('/check', async (req: Request, res: Response) => { try { const { schemeId, source } = req.query; if (!schemeId) { return res.status(400).json({ success: false, message: '参数缺失' }); } const targetType = sourceToType(source as string | undefined); const favorite = await prisma.favorite.findFirst({ where: { userId: req.user!.userId, targetType, targetId: String(schemeId) }, }); res.json({ isFavorited: !!favorite }); } catch (error) { console.error('Check favorite error:', error); res.status(500).json({ success: false, message: '检查失败' }); } }); export default router;