feat: 隐私政策 + 意见反馈系统

- 新增隐私政策页面,满足小程序审核要求
- 新增意见反馈功能(用户提交 + 管理员查看)
- 后端新增 feedbacks 表和反馈 API
- 管理后台新增反馈管理入口
- 我的页面添加意见反馈、隐私政策入口
This commit is contained in:
2026-06-08 10:16:28 +08:00
parent 8cf240f76b
commit 29614fdb70
10 changed files with 1026 additions and 0 deletions

View File

@@ -0,0 +1,110 @@
import { Router } from 'express'
import { pool } from '../db/connection'
import { authMiddleware } from '../middleware/auth'
const router = Router()
/** 用户提交反馈 */
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({ error: '请填写反馈内容' })
}
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({ success: true })
} catch (error) {
console.error('Submit feedback error:', error)
res.status(500).json({ error: '提交失败' })
}
})
/** 管理员获取反馈列表 */
router.get('/', authMiddleware, async (req, res) => {
try {
const userId = (req as any).userId
const [users] = await pool.execute('SELECT role FROM users WHERE id = ?', [userId])
const user = (users as any[])[0]
if (!user || user.role !== 'admin') {
return res.status(403).json({ error: '无权限' })
}
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
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
WHERE ${where}
ORDER BY f.created_at DESC
LIMIT ? OFFSET ?`,
[...params, pageSize, offset]
)
res.json({ list: rows, total, page, pageSize })
} catch (error) {
console.error('Get feedback list error:', error)
res.status(500).json({ error: '获取失败' })
}
})
/** 管理员更新反馈状态 */
router.put('/:id/status', authMiddleware, async (req, res) => {
try {
const userId = (req as any).userId
const [users] = await pool.execute('SELECT role FROM users WHERE id = ?', [userId])
const user = (users as any[])[0]
if (!user || user.role !== 'admin') {
return res.status(403).json({ error: '无权限' })
}
const { id } = req.params
const { status, admin_reply } = req.body
const validStatuses = ['pending', 'processed', 'ignored']
if (!validStatuses.includes(status)) {
return res.status(400).json({ error: '无效的状态' })
}
await pool.execute(
'UPDATE feedbacks SET status = ?, admin_reply = ? WHERE id = ?',
[status, admin_reply || '', id]
)
res.json({ success: true })
} catch (error) {
console.error('Update feedback status error:', error)
res.status(500).json({ error: '更新失败' })
}
})
export default router