import { Router } from 'express' import pool from '../db/connection' import { authMiddleware } from '../middleware/auth' import { requireAdmin } from '../middleware/requireAdmin' const router = Router() /** 当前用户的反馈列表 */ router.get('/mine', authMiddleware, async (req, res) => { try { const userId = (req as any).userId const page = Math.max(1, parseInt(req.query.page as string) || 1) const pageSize = Math.min(100, Math.max(1, parseInt(req.query.pageSize as string) || 20)) const offset = (page - 1) * pageSize const [countResult] = await pool.execute( 'SELECT COUNT(*) as total FROM feedbacks WHERE user_id = ?', [userId] ) const total = (countResult as any[])[0].total const [rows] = await pool.execute( `SELECT id, type, content, contact, status, admin_reply, created_at FROM feedbacks WHERE user_id = ? ORDER BY created_at DESC LIMIT ? OFFSET ?`, [userId, pageSize, offset] ) res.json({ code: 0, data: { list: rows, total, page, pageSize } }) } catch (error) { console.error('Get my feedback error:', error) res.status(500).json({ code: 50000, message: '获取失败' }) } }) /** 用户提交反馈 */ router.post('/', authMiddleware, async (req, res) => { try { const userId = (req as any).userId const { type, content, contact } = req.body if (!content || !content.trim()) { return res.status(400).json({ code: 40001, message: '请填写反馈内容' }) } const validTypes = ['bug', 'feature', 'ux', 'other'] const feedbackType = validTypes.includes(type) ? type : 'other' await pool.execute( 'INSERT INTO feedbacks (user_id, type, content, contact) VALUES (?, ?, ?, ?)', [userId, feedbackType, content.trim(), contact || ''] ) res.json({ code: 0 }) } catch (error) { console.error('Submit feedback error:', error) res.status(500).json({ code: 50000, message: '提交失败' }) } }) /** 管理员获取反馈列表 */ router.get('/', requireAdmin, async (req, res) => { try { const page = Math.max(1, parseInt(req.query.page as string) || 1) const pageSize = Math.min(100, Math.max(1, parseInt(req.query.pageSize as string) || 20)) const status = req.query.status as string const offset = (page - 1) * pageSize let where = '1=1' const params: any[] = [] if (status && ['pending', 'processed', 'ignored'].includes(status)) { where += ' AND f.status = ?' params.push(status) } const [countResult] = await pool.execute( `SELECT COUNT(*) as total FROM feedbacks f WHERE ${where}`, params ) const total = (countResult as any[])[0].total // LIMIT/OFFSET 使用参数化查询 const [rows] = await pool.execute( `SELECT f.*, u.nickname, u.avatar_url FROM feedbacks f LEFT JOIN users u ON f.user_id = u.id AND u.deleted_at IS NULL WHERE ${where} ORDER BY f.created_at DESC LIMIT ? OFFSET ?`, [...params, pageSize, offset] ) res.json({ code: 0, data: { list: rows, total, page, pageSize } }) } catch (error) { console.error('Get feedback list error:', error) res.status(500).json({ code: 50000, message: '获取失败' }) } }) /** 管理员更新反馈状态 */ router.put('/:id/status', requireAdmin, async (req, res) => { try { const { id } = req.params const { status, admin_reply } = req.body const validStatuses = ['pending', 'processed', 'ignored'] if (!validStatuses.includes(status)) { return res.status(400).json({ code: 40001, message: '无效的状态' }) } // 查询反馈信息(用于发送通知) const [feedbackRows] = await pool.execute( 'SELECT user_id, content FROM feedbacks WHERE id = ?', [id] ) const feedback = (feedbackRows as any[])[0] if (!feedback) { return res.status(404).json({ code: 40400, message: '反馈不存在' }) } await pool.execute( 'UPDATE feedbacks SET status = ?, admin_reply = ? WHERE id = ?', [status, admin_reply || '', id] ) // 如果有管理员回复,发送通知给反馈提交者 if (feedback && admin_reply && admin_reply.trim()) { const statusText: Record = { processed: '已处理', ignored: '已忽略', pending: '待处理' } const replyPreview = admin_reply.trim().length > 50 ? admin_reply.trim().slice(0, 50) + '...' : admin_reply.trim() await pool.execute( `INSERT INTO notifications (user_id, type, title, content) VALUES (?, 'personal', ?, ?)`, [ feedback.user_id, `您的反馈已${statusText[status] || '更新'}`, `反馈内容:${feedback.content.slice(0, 30)}...\n\n管理员回复:${replyPreview}` ] ) } res.json({ code: 0 }) } catch (error) { console.error('Update feedback status error:', error) res.status(500).json({ code: 50000, message: '更新失败' }) } }) export default router