feat: appealing status, auto-close parent on appeal resolved, closed=final
This commit is contained in:
@@ -3,7 +3,7 @@ const { query } = require('../db');
|
||||
const { authenticate, requireRole } = require('../middleware/auth');
|
||||
|
||||
const router = express.Router();
|
||||
const SL = { pending:'待处理', processing:'处理中', awaiting_info:'待补充', resolved:'已解决', rejected:'已驳回', closed:'已关闭' };
|
||||
const SL = { pending:'待处理', processing:'处理中', awaiting_info:'待补充', appealing:'申诉中', resolved:'已解决', rejected:'已驳回', closed:'已关闭' };
|
||||
const TL = { report:'举报', suggestion:'建议', appeal:'申诉', result_appeal:'结果申诉' };
|
||||
|
||||
function toCSV(headers, rows, filename) {
|
||||
|
||||
@@ -9,10 +9,10 @@ const { validateLengths } = require('../middleware/security');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
const SL = { pending:'待处理', processing:'处理中', awaiting_info:'待补充', resolved:'已解决', rejected:'已驳回', closed:'已关闭' };
|
||||
const SL = { pending:'待处理', processing:'处理中', awaiting_info:'待补充', appealing:'申诉中', resolved:'已解决', rejected:'已驳回', closed:'已关闭' };
|
||||
const TL = { report:'举报', suggestion:'建议', appeal:'申诉', result_appeal:'结果申诉' };
|
||||
const SC = { pending:'#f59e0b', processing:'#7c3aed', awaiting_info:'#d97706', resolved:'#059669', rejected:'#dc2626', closed:'#6b7280' };
|
||||
const SO = { processing:1, awaiting_info:2, pending:3, resolved:4, rejected:5, closed:6 };
|
||||
const SC = { pending:'#f59e0b', processing:'#7c3aed', awaiting_info:'#d97706', appealing:'#f97316', resolved:'#059669', rejected:'#dc2626', closed:'#6b7280' };
|
||||
const SO = { processing:1, awaiting_info:2, appealing:3, pending:4, resolved:5, rejected:6, closed:7 };
|
||||
|
||||
async function siteUrl() { const r = await getRow("SELECT v FROM settings WHERE k='site_url'"); return r?.v || 'http://localhost:3100'; }
|
||||
|
||||
@@ -108,7 +108,8 @@ router.post('/', optionalAuth, upload.array('files', 5), finalizeUpload, validat
|
||||
if (!parent_ticket_id) return res.status(400).json({ error: '缺少原工单信息' });
|
||||
const orig = await getRow("SELECT * FROM tickets WHERE id = ? AND user_id = ? AND status IN ('resolved','rejected','closed')", [parent_ticket_id, req.user?.id||0]);
|
||||
if (!orig) return res.status(400).json({ error: '原工单不存在或状态不允许申诉' });
|
||||
const existing = await getRow("SELECT id FROM tickets WHERE type = 'result_appeal' AND parent_ticket_id = ?", [parent_ticket_id]);
|
||||
if (orig.status === 'closed') return res.status(400).json({ error: '已关闭的工单无法申诉' });
|
||||
const existing = await getRow("SELECT id FROM tickets WHERE type = 'result_appeal' AND parent_ticket_id = ? AND status != 'closed'", [parent_ticket_id]);
|
||||
if (existing) return res.status(400).json({ error: '该工单已有结果申诉在处理中' });
|
||||
if (!reason) return res.status(400).json({ error: '请填写申诉理由' });
|
||||
if (!description) return res.status(400).json({ error: '请填写详细申诉内容' });
|
||||
@@ -140,6 +141,11 @@ router.post('/', optionalAuth, upload.array('files', 5), finalizeUpload, validat
|
||||
}
|
||||
}
|
||||
|
||||
if (type === 'result_appeal' && parent_ticket_id) {
|
||||
await conn.execute("UPDATE tickets SET status = 'appealing' WHERE id = ?", [parent_ticket_id]);
|
||||
await conn.execute("INSERT INTO responses(ticket_id, user_id, content, is_staff) VALUES (?,?,?,0)", [parent_ticket_id, req.user?.id||null, '【系统】玩家已对处理结果提出申诉,工单状态变更为申诉中']);
|
||||
}
|
||||
|
||||
const respContent = type === 'report'
|
||||
? `举报已提交\n举报人: ${rgn} (UID: ${rgu})\n被举报人: ${target_game_name||'无'} (UID: ${target_game_uid||'无'})\n原因: ${reason}${description?'\n详情: '+description:''}`
|
||||
: type === 'appeal'
|
||||
@@ -166,6 +172,7 @@ router.post('/', optionalAuth, upload.array('files', 5), finalizeUpload, validat
|
||||
router.put('/:id', authenticate, requireRole('owner','admin'), async (req, res) => {
|
||||
const t = await getRow('SELECT * FROM tickets WHERE id = ?', [req.params.id]);
|
||||
if (!t) return res.status(404).json({ error: '工单不存在' });
|
||||
if (t.status === 'closed') return res.status(400).json({ error: '已关闭的工单不可再修改' });
|
||||
const fields = {};
|
||||
if (req.body.status) fields.status = req.body.status;
|
||||
if (req.body.priority) fields.priority = req.body.priority;
|
||||
@@ -176,6 +183,12 @@ router.put('/:id', authenticate, requireRole('owner','admin'), async (req, res)
|
||||
|
||||
if (req.body.status && req.body.status !== t.status) {
|
||||
await query("INSERT INTO responses(ticket_id, user_id, content, is_staff) VALUES (?,?,?,1)", [req.params.id, req.user.id, `状态变更为: ${SL[req.body.status]||req.body.status}`]);
|
||||
|
||||
if (t.type === 'result_appeal' && (req.body.status === 'resolved' || req.body.status === 'rejected')) {
|
||||
await query(`UPDATE tickets SET status = 'closed' WHERE id = ?`, [t.parent_ticket_id]);
|
||||
await query("INSERT INTO responses(ticket_id, user_id, content, is_staff) VALUES (?,?,?,1)", [t.parent_ticket_id, req.user.id, `【系统】申诉已处理,原工单已关闭`]);
|
||||
}
|
||||
|
||||
await notifyStatusChange(t, req.body.status);
|
||||
}
|
||||
await query("INSERT INTO audit_logs(user_id, username, action, entity_type, entity_id, details) VALUES (?,?,?,?,?,?)", [req.user.id, req.user.username, 'update_ticket', 'ticket', req.params.id, '更新工单']);
|
||||
@@ -186,6 +199,7 @@ router.post('/:id/claim', authenticate, requireRole('owner','admin'), async (req
|
||||
const t = await getRow('SELECT * FROM tickets WHERE id = ?', [req.params.id]);
|
||||
if (!t) return res.status(404).json({ error: '工单不存在' });
|
||||
if (t.assigned_to && t.assigned_to !== req.user.id && t.status !== 'pending') return res.status(400).json({ error: '该工单已被他人认领' });
|
||||
if (t.status === 'closed') return res.status(400).json({ error: '已关闭的工单不可认领' });
|
||||
if (t.type === 'suggestion' && req.user.role !== 'owner') return res.status(403).json({ error: '建议工单仅服主可处理' });
|
||||
if ((t.type === 'result_appeal' || t.is_admin_complaint) && req.user.role !== 'owner') return res.status(403).json({ error: '该工单仅服主可处理' });
|
||||
|
||||
@@ -206,6 +220,7 @@ router.post('/:id/claim', authenticate, requireRole('owner','admin'), async (req
|
||||
router.post('/:id/transfer', authenticate, requireRole('owner','admin'), async (req, res) => {
|
||||
const t = await getRow('SELECT * FROM tickets WHERE id = ?', [req.params.id]);
|
||||
if (!t) return res.status(404).json({ error: '工单不存在' });
|
||||
if (t.status === 'closed') return res.status(400).json({ error: '已关闭的工单不可转交' });
|
||||
if (t.assigned_to !== req.user.id && req.user.role !== 'owner') return res.status(403).json({ error: '只能转交自己负责的工单' });
|
||||
const { to_user_id, reason } = req.body;
|
||||
if (!to_user_id) return res.status(400).json({ error: '请选择转交目标' });
|
||||
|
||||
Reference in New Issue
Block a user