fix: data-action buttons, sources enabled, email notify, ticket detail single-page

- app.js: mount page objects via inline script (CSP blocks eval → data-action buttons dead)
- app.js: add tickets list entry to sidebar nav (admin could not find claimed tickets)
- sources: GET /sources?manage=1 returns enabled field for admin view
- mailer: sendNotifyEmail consumes email-type notification_configs (webhook_url = recipients)
- tickets: trigger notify on created/claimed/transferred/updated/status-change
- notifications: email type shows recipient field, validates email list
- ticket-detail: single-page chat flow (player/staff bubbles) + processing log timeline
- css: chat bubble styles
This commit is contained in:
2026-08-22 20:00:12 +08:00
parent e5a1d693f1
commit c5ceba7cf0
9 changed files with 120 additions and 37 deletions

View File

@@ -20,6 +20,7 @@
const App = {
navItems: [
{ id: 'dashboard', label: '控制台', icon: 'fa-chart-simple', roles: ['owner','admin','player'] },
{ id: 'tickets', label: '工单列表', icon: 'fa-list', roles: ['owner','admin'] },
{ id: 'tickets-create', label: '提交工单', icon: 'fa-plus-circle', roles: ['player'] },
{ id: 'bans', label: '封禁列表', icon: 'fa-ban', roles: ['owner','admin','player'] },
{ id: 'unclaimed', label: '待处理工单', icon: 'fa-inbox', roles: ['owner','admin'] },
@@ -163,11 +164,13 @@ const App = {
const s = document.createElement('script');
s.src = src;
s.onload = () => {
// 页面脚本顶层 const 在全局词法环境, 用间接 eval 挂到 window,
// 供 inline onclick / data-action 的 window[obj] 查找
// 页面脚本顶层 const 在全局词法环境, 用内联 script 挂到 window
// (不能用 eval: CSP scriptSrc 无 'unsafe-eval', (0,eval) 会被拦截导致 data-action 按钮失效)
const objs = this.PAGE_OBJS[src.split('/').pop()] || [];
for (const o of objs) {
try { if (typeof window[o] === 'undefined') window[o] = (0, eval)(o); } catch {}
if (objs.length) {
const inline = document.createElement('script');
inline.textContent = objs.map(o => `window.${o} = ${o};`).join('\n');
document.head.appendChild(inline);
}
resolve();
};