feat: 隐私政策 + 意见反馈系统
- 新增隐私政策页面,满足小程序审核要求 - 新增意见反馈功能(用户提交 + 管理员查看) - 后端新增 feedbacks 表和反馈 API - 管理后台新增反馈管理入口 - 我的页面添加意见反馈、隐私政策入口
This commit is contained in:
110
server/src/routes/feedback.ts
Normal file
110
server/src/routes/feedback.ts
Normal 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
|
||||
Reference in New Issue
Block a user