feat: anonymous ticket tracking as standalone public page
- tracking: promoted to public route (before auth gate) with full single-ticket view - backend: GET /tickets/tracking/:id validates cookie tracking_token, returns responses/attachments/transfers - tracking.js: rewrite - token list + chat-flow detail (player/staff bubbles) + processing log + anon reply - ticket-create: anon submit now lands on #/tracking instead of home - home: tracking tab navigates to standalone page
This commit is contained in:
@@ -109,6 +109,20 @@ router.get('/tracking', async (req, res) => {
|
||||
res.json(rows);
|
||||
});
|
||||
|
||||
// ---- 匿名追踪: 单工单完整详情(cookie 追踪标识校验, 含对话/附件/处理日志) ----
|
||||
router.get('/tracking/:id', async (req, res) => {
|
||||
const cookieToken = req.headers.cookie?.split('; ').find(c => c.startsWith('tracking_token='))?.split('=')[1];
|
||||
if (!cookieToken) return res.status(403).json({ error: '无权操作,请先提交工单获取追踪标识' });
|
||||
const t = await getRow(`SELECT t.*, u.game_name as user_game_name, u.username as submitter, a.game_name as assignee_name, a.username as assignee_username
|
||||
FROM tickets t LEFT JOIN users u ON t.user_id = u.id LEFT JOIN users a ON t.assigned_to = a.id WHERE t.id = ? AND t.tracking_token = ?`, [req.params.id, cookieToken]);
|
||||
if (!t) return res.status(404).json({ error: '工单不存在或无权查看' });
|
||||
t.responses = await query(`SELECT r.*, u.username, u.role FROM responses r LEFT JOIN users u ON r.user_id = u.id WHERE r.ticket_id = ? ORDER BY r.created_at ASC`, [req.params.id]);
|
||||
t.attachments = await query('SELECT * FROM attachments WHERE ticket_id = ?', [req.params.id]);
|
||||
t.transfers = await query(`SELECT tf.*, fu.username as from_username, fu.game_name as from_game_name, tu.username as to_username, tu.game_name as to_game_name
|
||||
FROM ticket_transfers tf LEFT JOIN users fu ON tf.from_user_id = fu.id LEFT JOIN users tu ON tf.to_user_id = tu.id WHERE tf.ticket_id = ? ORDER BY tf.created_at ASC`, [req.params.id]);
|
||||
res.json(t);
|
||||
});
|
||||
|
||||
router.get('/:id', authenticate, async (req, res) => {
|
||||
await autoCloseExpired();
|
||||
const t = await getRow(`SELECT t.*, u.game_name as user_game_name, u.username as submitter, a.game_name as assignee_name, a.username as assignee_username
|
||||
|
||||
Reference in New Issue
Block a user