From e654339611021dfa24319a057a01d854b2045cbf Mon Sep 17 00:00:00 2001 From: canglan Date: Sun, 12 Jul 2026 01:23:35 +0800 Subject: [PATCH] chore: remove stale files from v2 --- backend/captcha.js | 40 ---- backend/routes/complaints.js | 208 ------------------ opencode.txt | 1 - public/js/pages/complaint-detail.js | 322 ---------------------------- public/js/pages/complaints.js | 188 ---------------- public/js/pages/implementations.js | 62 ------ public/js/pages/plans.js | 62 ------ public/js/pages/reviews.js | 62 ------ 8 files changed, 945 deletions(-) delete mode 100644 backend/captcha.js delete mode 100644 backend/routes/complaints.js delete mode 100644 opencode.txt delete mode 100644 public/js/pages/complaint-detail.js delete mode 100644 public/js/pages/complaints.js delete mode 100644 public/js/pages/implementations.js delete mode 100644 public/js/pages/plans.js delete mode 100644 public/js/pages/reviews.js diff --git a/backend/captcha.js b/backend/captcha.js deleted file mode 100644 index 98a65a1..0000000 --- a/backend/captcha.js +++ /dev/null @@ -1,40 +0,0 @@ -const crypto = require('crypto'); -const { getDb } = require('./db'); - -function generate() { - const db = getDb(); - db.prepare("DELETE FROM captchas WHERE datetime(created_at) < datetime('now','localtime','-5 minutes')").run(); - - const id = crypto.randomUUID(); - const ops = ['+', '-', '\u00d7']; - const op = ops[Math.floor(Math.random() * ops.length)]; - let a, b, answer; - - if (op === '\u00d7') { - a = Math.floor(Math.random() * 9) + 1; - b = Math.floor(Math.random() * 9) + 1; - } else { - a = Math.floor(Math.random() * 20) + 1; - b = Math.floor(Math.random() * 10) + 1; - if (op === '-' && a < b) [a, b] = [b, a]; - } - - if (op === '+') answer = a + b; - else if (op === '-') answer = a - b; - else answer = a * b; - - const question = `${a} ${op} ${b} = ?`; - db.prepare('INSERT INTO captchas(id, question, answer) VALUES (?,?,?)').run(id, question, String(answer)); - - return { id, question }; -} - -function verify(id, answer) { - const db = getDb(); - const row = db.prepare("SELECT * FROM captchas WHERE id = ? AND datetime(created_at) > datetime('now','localtime','-5 minutes')").get(id); - if (!row) return false; - db.prepare('DELETE FROM captchas WHERE id = ?').run(id); - return String(answer).trim() === row.answer; -} - -module.exports = { generate, verify }; diff --git a/backend/routes/complaints.js b/backend/routes/complaints.js deleted file mode 100644 index 4fc3350..0000000 --- a/backend/routes/complaints.js +++ /dev/null @@ -1,208 +0,0 @@ -const express = require('express'); -const { getDb } = require('../db'); -const { authenticate, requireRole, optionalAuth } = require('../middleware/auth'); - -const router = express.Router(); - -router.get('/', optionalAuth, (req, res) => { - const db = getDb(); - let query = `SELECT c.*, - p.display_name as planner_name, i.display_name as implementer_name, r.display_name as reviewer_name - FROM complaints c - LEFT JOIN users p ON c.assigned_planner_id = p.id - LEFT JOIN users i ON c.assigned_implementer_id = i.id - LEFT JOIN users r ON c.assigned_reviewer_id = r.id`; - let conditions = []; - let params = []; - - const { status, priority, category, search } = req.query; - - if (!req.user) { - conditions.push("c.status != 'pending'"); - } - - if (status) { - conditions.push('c.status = ?'); - params.push(status); - } - if (priority) { - conditions.push('c.priority = ?'); - params.push(priority); - } - if (category) { - conditions.push('c.category = ?'); - params.push(category); - } - if (search) { - conditions.push("(c.title LIKE ? OR c.description LIKE ? OR c.player_name LIKE ?)"); - const s = `%${search}%`; - params.push(s, s, s); - } - - if (req.user && req.user.role === 'planner') { - conditions.push('(c.assigned_planner_id = ? OR c.assigned_planner_id IS NULL)'); - params.push(req.user.id); - } - if (req.user && req.user.role === 'implementer') { - conditions.push('c.assigned_implementer_id = ?'); - params.push(req.user.id); - } - if (req.user && req.user.role === 'reviewer') { - conditions.push('c.assigned_reviewer_id = ?'); - params.push(req.user.id); - } - - if (conditions.length > 0) { - query += ' WHERE ' + conditions.join(' AND '); - } - query += ' ORDER BY c.updated_at DESC'; - - const complaints = db.prepare(query).all(...params); - res.json(complaints); -}); - -router.get('/stats', authenticate, (req, res) => { - const db = getDb(); - const total = db.prepare('SELECT COUNT(*) as count FROM complaints').get(); - const byStatus = db.prepare('SELECT status, COUNT(*) as count FROM complaints GROUP BY status').all(); - const byPriority = db.prepare('SELECT priority, COUNT(*) as count FROM complaints GROUP BY priority').all(); - const today = db.prepare("SELECT COUNT(*) as count FROM complaints WHERE date(created_at) = date('now','localtime')").get(); - - let myStats = {}; - if (['planner', 'implementer', 'reviewer'].includes(req.user.role)) { - const roleMap = { planner: 'assigned_planner_id', implementer: 'assigned_implementer_id', reviewer: 'assigned_reviewer_id' }; - const col = roleMap[req.user.role]; - myStats.total = db.prepare(`SELECT COUNT(*) as count FROM complaints WHERE ${col} = ?`).get(req.user.id).count; - myStats.pending = db.prepare(`SELECT COUNT(*) as count FROM complaints WHERE ${col} = ? AND status NOT IN ('resolved','closed','rejected')`).get(req.user.id).count; - myStats.completed = db.prepare(`SELECT COUNT(*) as count FROM complaints WHERE ${col} = ? AND status IN ('resolved','closed')`).get(req.user.id).count; - } - - res.json({ total: total.count, byStatus, byPriority, today: today.count, myStats }); -}); - -router.get('/:id', optionalAuth, (req, res) => { - const db = getDb(); - const complaint = db.prepare(`SELECT c.*, - p.display_name as planner_name, i.display_name as implementer_name, r.display_name as reviewer_name - FROM complaints c - LEFT JOIN users p ON c.assigned_planner_id = p.id - LEFT JOIN users i ON c.assigned_implementer_id = i.id - LEFT JOIN users r ON c.assigned_reviewer_id = r.id - WHERE c.id = ?`).get(req.params.id); - if (!complaint) return res.status(404).json({ error: '投诉不存在' }); - - const responses = db.prepare(`SELECT r.*, u.display_name as user_name, u.role as user_role - FROM responses r LEFT JOIN users u ON r.user_id = u.id - WHERE r.complaint_id = ? ORDER BY r.created_at ASC`).all(req.params.id); - complaint.responses = responses; - - if (complaint.plan_id) { - const plan = db.prepare(`SELECT p.*, u.display_name as planner_name FROM plans p - LEFT JOIN users u ON p.planner_id = u.id WHERE p.id = ?`).get(complaint.plan_id); - complaint.plan = plan; - } - if (complaint.implementation_id) { - const impl = db.prepare(`SELECT i.*, u.display_name as implementer_name FROM implementations i - LEFT JOIN users u ON i.implementer_id = u.id WHERE i.id = ?`).get(complaint.implementation_id); - complaint.implementation = impl; - } - if (complaint.review_id) { - const review = db.prepare(`SELECT r.*, u.display_name as reviewer_name FROM reviews r - LEFT JOIN users u ON r.reviewer_id = u.id WHERE r.id = ?`).get(complaint.review_id); - complaint.review = review; - } - - res.json(complaint); -}); - -router.post('/', optionalAuth, (req, res) => { - const { title, description, category, priority, player_name, player_email, player_contact } = req.body; - if (!title || !description || !player_name) { - return res.status(400).json({ error: '标题、描述和玩家名称为必填项' }); - } - const db = getDb(); - const result = db.prepare(`INSERT INTO complaints(title, description, category, priority, player_name, player_email, player_contact, status) - VALUES (?,?,?,?,?,?,?,'pending')`).run( - title, description, category || 'other', priority || 'medium', player_name, player_email || '', player_contact || '' - ); - const complaintId = result.lastInsertRowid; - - db.prepare(`INSERT INTO responses(complaint_id, user_id, response_type, content) VALUES (?,?,?,?)`).run( - complaintId, req.user?.id || null, 'system', '投诉已提交,等待处理' - ); - db.prepare(`INSERT INTO audit_logs(user_id, username, action, entity_type, entity_id, details) VALUES (?,?,?,?,?,?)`).run( - req.user?.id || null, req.user?.username || player_name, 'create', 'complaint', complaintId, - `投诉已创建: ${title}` - ); - res.status(201).json({ id: complaintId, message: '投诉提交成功' }); -}); - -router.put('/:id', authenticate, (req, res) => { - const db = getDb(); - const complaint = db.prepare('SELECT * FROM complaints WHERE id = ?').get(req.params.id); - if (!complaint) return res.status(404).json({ error: '投诉不存在' }); - - const allowedFields = {}; - if (req.body.title) allowedFields.title = req.body.title; - if (req.body.description) allowedFields.description = req.body.description; - if (req.body.category) allowedFields.category = req.body.category; - if (req.body.priority) allowedFields.priority = req.body.priority; - if (req.body.status) allowedFields.status = req.body.status; - - if (Object.keys(allowedFields).length === 0) { - return res.status(400).json({ error: '没有可更新的字段' }); - } - - const assignments = {}; - if (req.body.assigned_planner_id !== undefined) assignments.assigned_planner_id = req.body.assigned_planner_id; - if (req.body.assigned_implementer_id !== undefined) assignments.assigned_implementer_id = req.body.assigned_implementer_id; - if (req.body.assigned_reviewer_id !== undefined) assignments.assigned_reviewer_id = req.body.assigned_reviewer_id; - - const allFields = { ...allowedFields, ...assignments }; - const setClauses = Object.keys(allFields).map(k => `${k} = ?`).join(', '); - const values = Object.values(allFields); - - db.prepare(`UPDATE complaints SET ${setClauses}, updated_at = datetime('now','localtime') WHERE id = ?`).run(...values, req.params.id); - - if (req.body.status && req.body.status !== complaint.status) { - db.prepare(`INSERT INTO responses(complaint_id, user_id, response_type, content) VALUES (?,?,?,?)`).run( - req.params.id, req.user.id, 'system', `状态变更为: ${getStatusLabel(req.body.status)}` - ); - db.prepare(`INSERT INTO audit_logs(user_id, username, action, entity_type, entity_id, details) VALUES (?,?,?,?,?,?)`).run( - req.user.id, req.user.username, 'update_status', 'complaint', req.params.id, - `状态从 ${complaint.status} 变更为 ${req.body.status}` - ); - } - - db.prepare(`INSERT INTO audit_logs(user_id, username, action, entity_type, entity_id, details) VALUES (?,?,?,?,?,?)`).run( - req.user.id, req.user.username, 'update', 'complaint', req.params.id, '更新投诉信息' - ); - - res.json({ message: '更新成功' }); -}); - -router.post('/:id/response', authenticate, (req, res) => { - const { content, response_type } = req.body; - if (!content) return res.status(400).json({ error: '内容不能为空' }); - const db = getDb(); - const complaint = db.prepare('SELECT * FROM complaints WHERE id = ?').get(req.params.id); - if (!complaint) return res.status(404).json({ error: '投诉不存在' }); - - db.prepare(`INSERT INTO responses(complaint_id, user_id, response_type, content) VALUES (?,?,?,?)`).run( - req.params.id, req.user.id, response_type || 'comment', content - ); - db.prepare(`UPDATE complaints SET updated_at = datetime('now','localtime') WHERE id = ?`).run(req.params.id); - - res.status(201).json({ message: '回复添加成功' }); -}); - -function getStatusLabel(status) { - const labels = { - pending: '待处理', under_review: '审查中', planned: '已计划', - in_progress: '实施中', in_review: '审核中', resolved: '已解决', - rejected: '已驳回', closed: '已关闭' - }; - return labels[status] || status; -} - -module.exports = router; diff --git a/opencode.txt b/opencode.txt deleted file mode 100644 index 221f280..0000000 --- a/opencode.txt +++ /dev/null @@ -1 +0,0 @@ -ses_0b2c2409dffegYwIl1HBMSlSLL \ No newline at end of file diff --git a/public/js/pages/complaint-detail.js b/public/js/pages/complaint-detail.js deleted file mode 100644 index f5ac690..0000000 --- a/public/js/pages/complaint-detail.js +++ /dev/null @@ -1,322 +0,0 @@ -const ComplaintDetailPage = { - complaintId: null, - - async render(id) { - this.complaintId = id; - return '

加载中...

'; - }, - - async mount() { - const container = document.getElementById('page-content'); - const backBtn = ''; - document.getElementById('page-title').textContent = `投诉 #${this.complaintId}`; - document.getElementById('page-actions').innerHTML = backBtn; - - try { - const complaint = await API.get(`/complaints/${this.complaintId}`); - this.renderDetail(container, complaint); - } catch (err) { - container.innerHTML = `
加载失败: ${err.message}
`; - } - }, - - renderDetail(container, c) { - const user = Auth.getUser(); - - container.innerHTML = ` -
-
-
-
- 基本信息 -
${Utils.statusBadge(c.status)} ${Utils.priorityBadge(c.priority)}
-
-
-
标题${Utils.escapeHtml(c.title)}
-
描述${Utils.escapeHtml(c.description)}
-
分类${Utils.categoryBadge(c.category)}
-
玩家${Utils.escapeHtml(c.player_name)}
- ${c.player_email ? `
邮箱${Utils.escapeHtml(c.player_email)}
` : ''} - ${c.player_contact ? `
联系方式${Utils.escapeHtml(c.player_contact)}
` : ''} -
创建时间${Utils.formatDate(c.created_at)}
-
更新时间${Utils.formatDate(c.updated_at)}
-
-
- - ${c.plan ? this.renderPlanSection(c) : ''} - ${c.implementation ? this.renderImplementationSection(c) : ''} - ${c.review ? this.renderReviewSection(c) : ''} - -
-
沟通记录
-
- ${c.responses && c.responses.length > 0 ? ` -
- ${c.responses.map(r => ` -
-
- ${Utils.escapeHtml(r.user_name) || '系统'} - ${r.user_role ? `${Utils.roleLabels[r.user_role]}` : ''} - ${Utils.formatDate(r.created_at)} -
-
${Utils.escapeHtml(r.content)}
-
- `).join('')} -
- ` : '

暂无记录

'} -
-
- -
-
添加回复
-
-
-
- -
- -
-
-
-
- -
-
-
人员分配
-
-
规划者${c.planner_name || '未分配'}
-
实施者${c.implementer_name || '未分配'}
-
审查者${c.reviewer_name || '未分配'}
-
-
- -
-
操作
-
- ${user && (user.role === 'planner' || user.role === 'admin') && !c.plan ? ` - - ` : ''} - ${user && (user.role === 'planner' || user.role === 'admin') && c.plan && c.plan.status === 'draft' ? ` - - ` : ''} - ${user && (user.role === 'implementer' || user.role === 'admin') && c.plan && c.implementer_name === user.display_name && !c.implementation ? ` - - ` : ''} - ${user && (user.role === 'reviewer' || user.role === 'admin') && c.implementation && c.implementation.status === 'completed' && !c.review ? ` - - ` : ''} - ${user && (user.role === 'admin') ? ` - - ` : ''} -
-
-
-
- `; - - document.getElementById('add-response-form')?.addEventListener('submit', async (e) => { - e.preventDefault(); - const content = document.getElementById('response-content').value.trim(); - if (!content) return; - try { - await API.post(`/complaints/${c.id}/response`, { content }); - document.getElementById('response-content').value = ''; - this.mount(); - } catch (err) { - alert(err.message); - } - }); - }, - - renderPlanSection(c) { - const p = c.plan; - return ` -
-
- 处理计划 - ${Utils.statusBadge(p.status)} -
-
-
标题${Utils.escapeHtml(p.title)}
-
描述${Utils.escapeHtml(p.description)}
- ${p.technical_approach ? `
技术方案${Utils.escapeHtml(p.technical_approach)}
` : ''} - ${p.expected_effort ? `
预计工时${p.expected_effort}
` : ''} - ${p.reject_reason ? `
驳回原因${Utils.escapeHtml(p.reject_reason)}
` : ''} -
规划者${p.planner_name || '-'}
-
-
- `; - }, - - renderImplementationSection(c) { - const i = c.implementation; - return ` -
-
- 实施情况 - ${Utils.statusBadge(i.status)} -
-
- ${i.code_reference ? `
代码参考${Utils.escapeHtml(i.code_reference)}
` : ''} - ${i.implementation_notes ? `
实施说明${Utils.escapeHtml(i.implementation_notes)}
` : ''} - ${i.reject_reason ? `
驳回原因${Utils.escapeHtml(i.reject_reason)}
` : ''} -
实施者${i.implementer_name || '-'}
- ${i.status === 'in_progress' ? ` -
-
-
- - -
-
- - -
- -
-
- ` : ''} -
-
- `; - }, - - renderReviewSection(c) { - const r = c.review; - return ` -
-
- 审查结果 - ${Utils.statusBadge(r.status)} -
-
- ${r.review_notes ? `
审查意见${Utils.escapeHtml(r.review_notes)}
` : ''} - ${r.issues_found ? `
发现的问题${Utils.escapeHtml(r.issues_found)}
` : ''} - ${r.reject_reason ? `
驳回原因${Utils.escapeHtml(r.reject_reason)}
` : ''} -
审查者${r.reviewer_name || '-'}
-
-
- `; - }, - - async refresh() { - await this.mount(); - }, - - async createPlan(complaintId) { - Utils.openModal('创建处理计划', ` -
-
- - -
-
- - -
-
- - -
-
- - -
- -
- `); - document.getElementById('create-plan-form').addEventListener('submit', async (e) => { - e.preventDefault(); - try { - await API.post('/plans', { - complaint_id: complaintId, - title: document.getElementById('plan-title').value, - description: document.getElementById('plan-description').value, - technical_approach: document.getElementById('plan-tech').value, - expected_effort: document.getElementById('plan-effort').value, - }); - App.closeModal(); - this.refresh(); - } catch (err) { alert(err.message); } - }); - }, - - async assignImplementer(complaintId, planId) { - const users = await API.get('/users/implementers'); - if (!users.length) { alert('暂无可用实施者'); return; } - Utils.openModal('分配实施者', ` -
-
- - -
- -
- `); - document.getElementById('assign-impl-form').addEventListener('submit', async (e) => { - e.preventDefault(); - try { - await API.post(`/plans/${planId}/assign`, { implementer_id: parseInt(document.getElementById('assign-impl-user').value) }); - App.closeModal(); - this.refresh(); - } catch (err) { alert(err.message); } - }); - }, - - async startImplementation(complaintId, planId) { - try { - await API.post('/implementations', { plan_id: planId }); - this.refresh(); - } catch (err) { alert(err.message); } - }, - - async startReview(complaintId, implementationId) { - try { - await API.post('/reviews', { implementation_id: implementationId }); - this.refresh(); - } catch (err) { alert(err.message); } - }, - - showUpdateStatusModal(complaintId) { - Utils.openModal('修改状态', ` -
-
- - -
- -
- `); - document.getElementById('update-status-form').addEventListener('submit', async (e) => { - e.preventDefault(); - try { - await API.put(`/complaints/${complaintId}`, { status: document.getElementById('new-status').value }); - App.closeModal(); - this.refresh(); - } catch (err) { alert(err.message); } - }); - } -}; diff --git a/public/js/pages/complaints.js b/public/js/pages/complaints.js deleted file mode 100644 index be53728..0000000 --- a/public/js/pages/complaints.js +++ /dev/null @@ -1,188 +0,0 @@ -const ComplaintsPage = { - async render() { - return '

加载中...

'; - }, - - async mount() { - const container = document.getElementById('page-content'); - document.getElementById('page-title').textContent = '投诉列表'; - document.getElementById('page-actions').innerHTML = ''; - - await this.loadList(container); - }, - - async loadList(container, filters = {}) { - const params = new URLSearchParams(); - if (filters.status) params.set('status', filters.status); - if (filters.priority) params.set('priority', filters.priority); - if (filters.category) params.set('category', filters.category); - if (filters.search) params.set('search', filters.search); - const qs = params.toString(); - - container.innerHTML = '

加载中...

'; - - try { - const complaints = await API.get('/complaints' + (qs ? '?' + qs : '')); - this.renderList(container, complaints, filters); - } catch (err) { - container.innerHTML = `
加载失败: ${err.message}
`; - } - }, - - renderList(container, complaints, filters = {}) { - container.innerHTML = ` -
- - - - - - -
- - ${complaints.length === 0 ? ` -
- -

暂无投诉记录

-
- ` : ` -
-
- - - - - - - - - - - - - - - - - - ${complaints.map(c => ` - - - - - - - - - - - - - - `).join('')} - -
#标题玩家分类优先级状态规划者实施者审查者更新时间操作
${c.id}${Utils.escapeHtml(c.title)}${Utils.escapeHtml(c.player_name)}${Utils.categoryBadge(c.category)}${Utils.priorityBadge(c.priority)}${Utils.statusBadge(c.status)}${c.planner_name || '-'}${c.implementer_name || '-'}${c.reviewer_name || '-'}${Utils.formatDate(c.updated_at)}
-
-
- `} - `; - }, - - applyFilters() { - const filters = { - status: document.getElementById('filter-status').value, - priority: document.getElementById('filter-priority').value, - category: document.getElementById('filter-category').value, - search: document.getElementById('filter-search').value, - }; - const container = document.getElementById('page-content'); - this.loadList(container, filters); - }, - - resetFilters() { - const container = document.getElementById('page-content'); - this.loadList(container, {}); - }, - - showCreateModal() { - Utils.openModal('提交投诉', ` -
-
- - -
-
- - -
-
-
- - -
-
- - -
-
-
- - -
-
-
- - -
-
- - -
-
- -
- `); - document.getElementById('create-complaint-form').addEventListener('submit', async (e) => { - e.preventDefault(); - const btn = e.target.querySelector('button[type="submit"]'); - btn.disabled = true; - btn.innerHTML = ' 提交中...'; - try { - await API.post('/complaints', { - title: document.getElementById('c-title').value, - description: document.getElementById('c-description').value, - category: document.getElementById('c-category').value, - priority: document.getElementById('c-priority').value, - player_name: document.getElementById('c-player_name').value, - player_email: document.getElementById('c-player_email').value, - player_contact: document.getElementById('c-player_contact').value, - }); - App.closeModal(); - this.mount(); - } catch (err) { - alert(err.message); - btn.disabled = false; - btn.innerHTML = ' 提交'; - } - }); - } -}; diff --git a/public/js/pages/implementations.js b/public/js/pages/implementations.js deleted file mode 100644 index c4802f1..0000000 --- a/public/js/pages/implementations.js +++ /dev/null @@ -1,62 +0,0 @@ -const ImplementationsPage = { - async render() { - return '

加载中...

'; - }, - - async mount() { - const container = document.getElementById('page-content'); - document.getElementById('page-title').textContent = '实施管理'; - document.getElementById('page-actions').innerHTML = ''; - - try { - const impls = await API.get('/implementations'); - this.renderList(container, impls); - } catch (err) { - container.innerHTML = `
加载失败: ${err.message}
`; - } - }, - - renderList(container, impls) { - container.innerHTML = ` - ${impls.length === 0 ? ` -
- -

暂无实施记录

-
- ` : ` -
-
- - - - - - - - - - - - - - ${impls.map(i => ` - - - - - - - - - - `).join('')} - -
#关联投诉关联计划状态实施者创建时间操作
${i.id}#${i.complaint_id} ${Utils.escapeHtml(i.complaint_title)}${Utils.escapeHtml(i.plan_title)}${Utils.statusBadge(i.status)}${i.implementer_name || '-'}${Utils.formatDate(i.created_at)} - -
-
-
- `} - `; - } -}; diff --git a/public/js/pages/plans.js b/public/js/pages/plans.js deleted file mode 100644 index b4d1801..0000000 --- a/public/js/pages/plans.js +++ /dev/null @@ -1,62 +0,0 @@ -const PlansPage = { - async render() { - return '

加载中...

'; - }, - - async mount() { - const container = document.getElementById('page-content'); - document.getElementById('page-title').textContent = '计划管理'; - document.getElementById('page-actions').innerHTML = ''; - - try { - const plans = await API.get('/plans'); - this.renderList(container, plans); - } catch (err) { - container.innerHTML = `
加载失败: ${err.message}
`; - } - }, - - renderList(container, plans) { - container.innerHTML = ` - ${plans.length === 0 ? ` -
- -

暂无计划

-
- ` : ` -
-
- - - - - - - - - - - - - - ${plans.map(p => ` - - - - - - - - - - `).join('')} - -
#计划标题关联投诉状态规划者创建时间操作
${p.id}${Utils.escapeHtml(p.title)}#${p.complaint_id} ${Utils.escapeHtml(p.complaint_title)}${Utils.statusBadge(p.status)}${p.planner_name || '-'}${Utils.formatDate(p.created_at)} - -
-
-
- `} - `; - } -}; diff --git a/public/js/pages/reviews.js b/public/js/pages/reviews.js deleted file mode 100644 index 843bec3..0000000 --- a/public/js/pages/reviews.js +++ /dev/null @@ -1,62 +0,0 @@ -const ReviewsPage = { - async render() { - return '

加载中...

'; - }, - - async mount() { - const container = document.getElementById('page-content'); - document.getElementById('page-title').textContent = '审查管理'; - document.getElementById('page-actions').innerHTML = ''; - - try { - const reviews = await API.get('/reviews'); - this.renderList(container, reviews); - } catch (err) { - container.innerHTML = `
加载失败: ${err.message}
`; - } - }, - - renderList(container, reviews) { - container.innerHTML = ` - ${reviews.length === 0 ? ` -
- -

暂无审查记录

-
- ` : ` -
-
- - - - - - - - - - - - - - ${reviews.map(r => ` - - - - - - - - - - `).join('')} - -
#关联投诉状态审查者审查意见创建时间操作
${r.id}#${r.complaint_id} ${Utils.escapeHtml(r.complaint_title)}${Utils.statusBadge(r.status)}${r.reviewer_name || '-'}${r.review_notes ? Utils.escapeHtml(r.review_notes.slice(0, 50)) : '-'}${Utils.formatDate(r.created_at)} - -
-
-
- `} - `; - } -};