diff --git a/public/index.html b/public/index.html index c044181..517cfa3 100644 --- a/public/index.html +++ b/public/index.html @@ -46,7 +46,7 @@ diff --git a/public/js/app.js b/public/js/app.js index b597fdc..becf556 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -17,6 +17,14 @@ const App = { try { const s = await API.get('/install/status'); if (!s.installed) { location.hash = '#/install'; return; } } catch { location.hash = '#/install'; return; } this._footerLoaded = false; window.addEventListener('hashchange', () => this.route()); + document.getElementById('modal-close').onclick = () => this.closeModal(); + document.addEventListener('click', (e) => { + const action = e.target.closest('[data-action]'); + if (!action) return; + const [obj, method, ...args] = action.dataset.action.split(':'); + const target = window[obj]; + if (target && target[method]) target[method](...args); + }); this.route(); }, diff --git a/public/js/pages/dashboard.js b/public/js/pages/dashboard.js index cd8b27c..b513387 100644 --- a/public/js/pages/dashboard.js +++ b/public/js/pages/dashboard.js @@ -3,7 +3,7 @@ const Dashboard = { async mount() { const ct = document.getElementById('page-content'); - document.getElementById('page-title').textContent = '控制台'; + document.getElementById('page-title').textContent = '控制?; document.getElementById('page-actions').innerHTML = ` @@ -25,24 +25,24 @@ const Dashboard = { ct.innerHTML = `
${stats.total}
工单总数
-
${byStatus.pending || 0}
待处理
-
${byStatus.processing || 0}
处理中
-
${byStatus.resolved || 0}
已解决
+
${byStatus.pending || 0}
待处?/div>
+
${byStatus.processing || 0}
处理?/div>
+
${byStatus.resolved || 0}
已解?/div>
${Auth.isAdmin() && exports ? `
类型分布
- ${(exports.byType||[]).map(r => `
${U.TYPE[r.type]||r.type}${r.c} 条
`).join('')} + ${(exports.byType||[]).map(r => `
${U.TYPE[r.type]||r.type}${r.c} ?/span>
`).join('')}
-
状态分布
- ${(exports.byStatus||[]).map(r => `
${U.STATUS[r.status]||r.status}${r.c} 条
`).join('')} +
状态分?/div>
+ ${(exports.byStatus||[]).map(r => `
${U.STATUS[r.status]||r.status}${r.c} ?/span>
`).join('')}
${exports.monthly?.length ? `
月度趋势
${exports.monthly.map(m=>``).join('')}
月份数量
${m.m}${m.c}
` : ''} ` : ''} -

提示: 可在"工单列表"中查看和管理所有工单

+

提示: 可在"工单列表"中查看和管理所有工?/p> `; } }; diff --git a/public/js/pages/export-page.js b/public/js/pages/export-page.js index 177bf01..52431d2 100644 --- a/public/js/pages/export-page.js +++ b/public/js/pages/export-page.js @@ -11,8 +11,8 @@ const ExportPage = {

导出工单
-
-
+
+
@@ -28,14 +28,14 @@ const ExportPage = {
导出操作日志
-
+
统计报表
-

查看系统整体统计和趋势数据

+

查看系统整体统计和趋势数?/p>

@@ -77,11 +77,11 @@ const ExportPage = {

概览

工单总数${d.total}
今日新增${d.today}
-
用户数${d.usersTotal}
+
用户?/span>${d.usersTotal}
-

状态分布

${(d.byStatus||[]).map(r=>`
${U.STATUS[r.status]||r.status}${r.c}
`).join('')}
+

状态分?/h4>${(d.byStatus||[]).map(r=>`
${U.STATUS[r.status]||r.status}${r.c}
`).join('')}

类型分布

${(d.byType||[]).map(r=>`
${U.TYPE[r.type]||r.type}${r.c}
`).join('')}
- ${d.monthly?.length?`

月度趋势

${d.monthly.map(m=>`
${m.m}${m.c} 条
`).join('')}
`:''} + ${d.monthly?.length?`

月度趋势

${d.monthly.map(m=>`
${m.m}${m.c} ?/span>
`).join('')}
`:''} `, '600px'); } catch (e) { alert(e.message); } } diff --git a/public/js/pages/features.js b/public/js/pages/features.js index 0c9280c..4bd7ab0 100644 --- a/public/js/pages/features.js +++ b/public/js/pages/features.js @@ -20,7 +20,7 @@ const FeaturesPage = { ct.innerHTML = `
- + @@ -74,7 +74,7 @@ const FeaturesPage = { renderItem(i) { const sc = i.status==='done'?'var(--s)':i.status==='planned'?'var(--p)':'var(--g5)'; - const statusLabel = i.status==='done'?'已完成':i.status==='planned'?'计划中':'待定'; + const statusLabel = i.status==='done'?'已完?:i.status==='planned'?'计划?:'待定'; return `
${i.status==='done'?'\u2713':i.status==='planned'?'\u25C9':'\u25CB'} ${U.esc(i.title)} @@ -153,9 +153,9 @@ const FeaturesPage = { U.modal('添加', `
-
+
- + `); document.getElementById('feat-form').onsubmit = async e => { e.preventDefault(); @@ -171,10 +171,10 @@ const FeaturesPage = { U.modal('编辑', `
-
-
+
+
- +
`); document.getElementById('fe-edit').onsubmit = async e => { e.preventDefault(); @@ -184,5 +184,5 @@ const FeaturesPage = { }; }, - async del(id) { if (!await U.confirm('确认删除?')) return; try { await API.req('DELETE', '/features/'+id); App.closeModal(); this.load(); } catch(ex){alert(ex.message);} } + async del(id) { if (!await U.confirm('确认删除?)) return; try { await API.req('DELETE', '/features/'+id); App.closeModal(); this.load(); } catch(ex){alert(ex.message);} } }; diff --git a/public/js/pages/home.js b/public/js/pages/home.js index ddb62fc..4132030 100644 --- a/public/js/pages/home.js +++ b/public/js/pages/home.js @@ -39,19 +39,19 @@ const HomePage = { this.searchTracking = async () => { const token = document.getElementById('track-token').value.trim(); - if (!token) return alert('请输入追踪标识'); + if (!token) return alert('请输入追踪标?); const ct = document.getElementById('track-result'); ct.innerHTML = '
'; try { const tickets = await API.get(`/tickets/tracking?token=${token}`); ct.innerHTML = tickets.length ? `
- + ${tickets.map(tick => ` - `).join('')}
#类型标题状态时间操作#类型标题状?/th>时间操作
${tick.id}${U.badge(tick.type,'type')}${U.esc(tick.title)} ${U.badge(tick.status,'status')}${U.date(tick.created_at)}
` : '

未找到工单

'; + `).join('')}
` : '

未找到工?/p>

'; } catch (ex) { ct.innerHTML = `
${ex.message}
`; } }; }, @@ -62,20 +62,20 @@ const HomePage = { U.loading(ct); API.get(`/tickets/tracking?token=${token}`).then(tickets => { const t = tickets.find(x => x.id === id); - if (!t) { ct.innerHTML = '

未找到

'; return; } + if (!t) { ct.innerHTML = '

未找?/p>'; return; } ct.innerHTML = `

基本信息

标题${U.esc(t.title)}
类型${U.badge(t.type,'type')}
-
状态${U.badge(t.status,'status')}
-
提交者${U.esc(t.reporter_game_name)} (UID: ${U.esc(t.reporter_game_uid)})
+
状?/span>${U.badge(t.status,'status')}
+
提交?/span>${U.esc(t.reporter_game_name)} (UID: ${U.esc(t.reporter_game_uid)})
${t.type==='report'?`
被举报人${U.esc(t.target_game_name||'?')} (UID: ${U.esc(t.target_game_uid||'?')})
原因${U.esc(t.reason)}
`:''} ${t.description?`
详情${U.esc(t.description)}
`:''}
时间${U.date(t.created_at)}
-

如需回复,请注册账号后关联此工单。

`; +

如需回复,请注册账号后关联此工单?/p>`; }).catch(e => { ct.innerHTML = `

${e.message}
`; }); } }; diff --git a/public/js/pages/install.js b/public/js/pages/install.js index e6a6a0d..bb94447 100644 --- a/public/js/pages/install.js +++ b/public/js/pages/install.js @@ -20,15 +20,15 @@ const InstallPage = { renderDBStep(ct) { ct.innerHTML = ` -
第1步:数据库配置
+
?步:数据库配?/div>
-
+
-
如不存在将自动创建
+
如不存在将自动创?/span>
- +
`; @@ -36,7 +36,7 @@ const InstallPage = { e.preventDefault(); const btn = e.target.querySelector('button'); btn.disabled = true; - btn.innerHTML = ' 测试中...'; + btn.innerHTML = ' 测试?..'; try { await API.post('/install/check-db', { host: document.getElementById('db-host').value, @@ -57,24 +57,24 @@ const InstallPage = { document.getElementById('db-err').textContent = ex.message; document.getElementById('db-err').classList.remove('hidden'); btn.disabled = false; - btn.innerHTML = ' 测试连接并继续'; + btn.innerHTML = ' 测试连接并继?; } }; }, renderAdminStep(ct) { ct.innerHTML = ` -
第2步:创建服主账号
+
?步:创建服主账号
-
+
-
注意:安装完成后需要重启服务器才能加载业务路由。请记好账号密码。
+
注意?/strong>安装完成后需要重启服务器才能加载业务路由。请记好账号密码?/div>
@@ -83,7 +83,7 @@ const InstallPage = { e.preventDefault(); const btn = e.target.querySelector('button'); btn.disabled = true; - btn.innerHTML = ' 安装中...'; + btn.innerHTML = ' 安装?..'; try { await API.post('/install/complete', { ...this.dbConfig, @@ -97,7 +97,7 @@ const InstallPage = { admin_game_name: document.getElementById('ia-game').value, admin_game_uid: document.getElementById('ia-uid').value, }); - document.getElementById('install-admin').innerHTML = '

安装成功!

配置已保存。请重启服务器后刷新页面。

'; + document.getElementById('install-admin').innerHTML = '

安装成功?/h3>

配置已保存。请重启服务器后刷新页面?/p>

'; } catch (ex) { document.getElementById('ia-err').textContent = ex.message; document.getElementById('ia-err').classList.remove('hidden'); diff --git a/public/js/pages/login.js b/public/js/pages/login.js index 565a8e1..6fb9051 100644 --- a/public/js/pages/login.js +++ b/public/js/pages/login.js @@ -4,7 +4,7 @@ const LoginPage = {
-
+
@@ -22,7 +22,7 @@ const LoginPage = { e.preventDefault(); const btn = e.target.querySelector('button'); btn.disabled = true; - btn.innerHTML = ' 登录中...'; + btn.innerHTML = ' 登录?..'; try { await Auth.login(document.getElementById('lu').value.trim(), document.getElementById('lp').value.trim()); App.afterLogin(); diff --git a/public/js/pages/notifications.js b/public/js/pages/notifications.js index 720adb6..fe92e90 100644 --- a/public/js/pages/notifications.js +++ b/public/js/pages/notifications.js @@ -28,14 +28,14 @@ const NotificationsPage = { showCreate() { U.modal('添加Webhook', ` -
+
${EventOptions('all')}
-
+ `); bindEventToggles(); document.getElementById('nc-form').onsubmit = async e => { e.preventDefault(); @@ -51,8 +51,8 @@ const NotificationsPage = {
${EventOptions(events)}
-
- +
+ `); bindEventToggles(); document.getElementById('ne-form').onsubmit = async e => { e.preventDefault(); @@ -61,7 +61,7 @@ const NotificationsPage = { }, async test(id) { try { alert((await API.post(`/notifications/${id}/test`)).message); } catch(ex){alert(ex.message);} }, - async del(id) { if(await U.confirm('确认删除此通知配置?')){ try { await API.req('DELETE',`/notifications/${id}`); this.load(); } catch(ex){alert(ex.message);} } } + async del(id) { if(await U.confirm('确认删除此通知配置?)){ try { await API.req('DELETE',`/notifications/${id}`); this.load(); } catch(ex){alert(ex.message);} } } }; function EventOptions(current) { return ['all','ticket_created','ticket_claimed','ticket_transferred','ticket_updated'].map(e=>``).join(''); } diff --git a/public/js/pages/polls.js b/public/js/pages/polls.js index b7422e7..26334d8 100644 --- a/public/js/pages/polls.js +++ b/public/js/pages/polls.js @@ -32,16 +32,16 @@ const PollsPage = { const opts = p.options || []; const timed = p.start_time || p.end_time; return `
-
${U.esc(p.server_name)} — ${U.esc(p.title)} +
${U.esc(p.server_name)} ?${U.esc(p.title)} - ${timed ? `${p.start_time?'起: '+U.date(p.start_time):''} ${p.end_time?'至: '+U.date(p.end_time):''}`:''} - ${p.total||0} 票 + ${timed ? `${p.start_time?'? '+U.date(p.start_time):''} ${p.end_time?'? '+U.date(p.end_time):''}`:''} + ${p.total||0} ?/span> ${Auth.isOwner() ? `` : ''}
${p.description?`

${U.esc(p.description)}

`:''} - ${p.voted ? `
已投票
` : ''} + ${p.voted ? `
已投?/div>` : ''}
${opts.map((o,i) => { const v = p.voted ? 0 : (p.votes?.[i] || 0); @@ -51,7 +51,7 @@ const PollsPage = { ${!p.voted ? `
` : ''}
${my?' ':''}${U.esc(o)} - ${!p.voted ? `${v}票 ${pct}%` : ''} + ${!p.voted ? `${v}?${pct}%` : ''}
`; }).join('')} @@ -79,17 +79,17 @@ const PollsPage = {
-
-
-
- +
+
+
+ `); document.getElementById('poll-form').onsubmit = async e => { e.preventDefault(); const [group_name, server_name] = document.getElementById('pl-gs').value.split('::'); const opts = document.getElementById('pl-opts').value.split('\n').map(s=>s.trim()).filter(s=>s); - if (opts.length < 2) return alert('至少需要2个选项'); + if (opts.length < 2) return alert('至少需?个选项'); try { await API.post('/polls', { title: document.getElementById('pl-title').value, description: document.getElementById('pl-desc').value, options: opts, group_name, server_name, start_time: document.getElementById('pl-start').value||null, end_time: document.getElementById('pl-end').value||null }); App.closeModal(); this.load(); @@ -107,7 +107,7 @@ const PollsPage = {
`).join(''); U.modal('管理分组', ` -
+
${list||'

暂无

'}
`); @@ -124,10 +124,10 @@ const PollsPage = { document.getElementById('modal-title').textContent = '编辑投票'; document.getElementById('modal-body').innerHTML = `
-
+
-
- +
+
`; document.getElementById('modal-overlay').classList.remove('hidden'); @@ -138,5 +138,5 @@ const PollsPage = { }; }, - async deletePoll(id) { if (!await U.confirm('确认删除?')) return; try { await API.req('DELETE', '/polls/'+id); App.closeModal(); this.load(); } catch(ex){alert(ex.message);} } + async deletePoll(id) { if (!await U.confirm('确认删除?)) return; try { await API.req('DELETE', '/polls/'+id); App.closeModal(); this.load(); } catch(ex){alert(ex.message);} } }; diff --git a/public/js/pages/register.js b/public/js/pages/register.js index ac0e958..035276c 100644 --- a/public/js/pages/register.js +++ b/public/js/pages/register.js @@ -8,29 +8,29 @@ const RegisterPage = {
-
+
-
+
+
SMTP 邮件设置
-
+
-
+
-
+
@@ -38,9 +38,9 @@ const SettingsPage = { site_name: {value: document.getElementById('s-name').value, label:'站点名称'}, site_url: {value: document.getElementById('s-url').value, label:'站点地址'}, copyright: {value: document.getElementById('s-copyright').value, label:'页尾版权'}, - icp: {value: document.getElementById('s-icp').value, label:'ICP备案号'}, + icp: {value: document.getElementById('s-icp').value, label:'ICP备案?}, }); - alert('已保存'); + alert('已保?); } catch (ex) { alert(ex.message); } }; @@ -48,14 +48,14 @@ const SettingsPage = { e.preventDefault(); try { await API.put('/settings/settings', { - smtp_host: {value: document.getElementById('s-host').value, label:'SMTP服务器'}, + smtp_host: {value: document.getElementById('s-host').value, label:'SMTP服务?}, smtp_port: {value: document.getElementById('s-port').value, label:'SMTP端口'}, smtp_secure: {value: document.getElementById('s-secure').value, label:'SSL'}, - smtp_user: {value: document.getElementById('s-user').value, label:'SMTP用户名'}, + smtp_user: {value: document.getElementById('s-user').value, label:'SMTP用户?}, smtp_pass: {value: document.getElementById('s-pass').value, label:'SMTP密码'}, smtp_from: {value: document.getElementById('s-from').value, label:'发件地址'}, }); - alert('已保存'); + alert('已保?); } catch (ex) { alert(ex.message); } }; } catch (e) { diff --git a/public/js/pages/templates.js b/public/js/pages/templates.js index b81f449..7f59b50 100644 --- a/public/js/pages/templates.js +++ b/public/js/pages/templates.js @@ -29,7 +29,7 @@ const TemplatesPage = {
可用变量: ${t.description?.match(/\{\{[^}]+\}\}/g)?.join(', ') || '{{site_name}}'}
- + `, '800px'); document.getElementById('et-form').onsubmit = async e => { diff --git a/public/js/pages/ticket-create.js b/public/js/pages/ticket-create.js index c1c300d..4765b41 100644 --- a/public/js/pages/ticket-create.js +++ b/public/js/pages/ticket-create.js @@ -34,38 +34,38 @@ const TicketCreate = { ${isReport ? `
-
-
+
+
- +
-
+
` : isAppeal ? ` -
-
+
` : ` -
+
`}
-
上传文件 (图片/视频,每个最大20MB)
+
上传文件 (图片/视频,每个最?0MB)

点击选择文件或拖拽到此处

-

支持: JPG/PNG/GIF/WebP/MP4/WebM   每个最大50MB

+

支持: JPG/PNG/GIF/WebP/MP4/WebM   每个最?0MB

@@ -104,7 +104,7 @@ const TicketCreate = { for (const f of fileList) { if (!allowed.includes(f.type)) { alert(`不支持的文件类型: ${f.name}`); continue; } if (f.size > 50 * 1024 * 1024) { alert(`文件过大: ${f.name}`); continue; } - if (this.files.length >= 5) { alert('最多5个文件'); break; } + if (this.files.length >= 5) { alert('最?个文?); break; } this.files.push(f); } this.refreshFileList(listEl); @@ -137,13 +137,13 @@ const TicketCreate = { const btn = form.querySelector('[type="submit"]'); btn.disabled = true; - btn.innerHTML = ' 提交中...'; + btn.innerHTML = ' 提交?..'; try { const res = await API.req('POST', '/tickets', fd); if (res.tracking_token) { document.cookie = `tracking_token=${res.tracking_token};path=/;max-age=${365*24*3600};SameSite=Lax`; } - alert('提交成功!工单编号: #' + res.id); + alert('提交成功!工单编? #' + res.id); if (Auth.logged()) App.navigate('tickets'); else App.navigate('home'); } catch (ex) { diff --git a/public/js/pages/ticket-detail.js b/public/js/pages/ticket-detail.js index 3f1866f..41f4136 100644 --- a/public/js/pages/ticket-detail.js +++ b/public/js/pages/ticket-detail.js @@ -6,7 +6,7 @@ const TicketDetail = { async mount() { const id = this.id; document.getElementById('page-title').textContent = `工单 #${id}`; - document.getElementById('page-actions').innerHTML = ``; + document.getElementById('page-actions').innerHTML = ``; try { this.renderDetail(document.getElementById('page-content'), await API.get(`/tickets/${id}`)); } catch (e) { document.getElementById('page-content').innerHTML = `
${e.message}
`; } }, @@ -23,7 +23,7 @@ const TicketDetail = {
基本信息
${U.badge(t.status,'status')} ${U.badge(t.type,'type')} ${U.badge(t.priority,'priority')}
标题${U.esc(t.title)}
-
提交者${U.esc(t.reporter_game_name)} (UID: ${U.esc(t.reporter_game_uid)})
+
提交?/span>${U.esc(t.reporter_game_name)} (UID: ${U.esc(t.reporter_game_uid)})
${isRep?`
被举报人${U.esc(t.target_game_name||'?')} (UID: ${U.esc(t.target_game_uid||'?')})
原因${U.esc(t.reason)}
`:''} ${isAppeal?`
申诉理由${U.esc(t.reason)}
`:''} @@ -35,42 +35,42 @@ const TicketDetail = { ${t.claim_note?`
处理备注
${U.esc(t.claim_note)}
`:''} ${t.parent_ticket?`
关联工单
-
原工单#${t.parent_ticket.id} ${U.esc(t.parent_ticket.title)} — ${U.badge(t.parent_ticket.status,'status')}
+
原工?/span>#${t.parent_ticket.id} ${U.esc(t.parent_ticket.title)} ?${U.badge(t.parent_ticket.status,'status')}
`:''} ${t.attachments?.length?`
附件 (${t.attachments.length})
${t.attachments.map(a=>a.mime_type.startsWith('image')?``:` ${U.esc(a.original_name)}`).join('')}
`:''} -
沟通记录
+
沟通记?/div>
${t.responses?.length?`
${t.responses.map(r=>`
${U.esc(r.username||'系统')}${r.role?`${U.ROLE[r.role]}`:''}${U.date(r.created_at)}
${U.esc(r.content)}
`).join('')}
`:'

暂无记录

'}
${isStaff?'回复 (公开)':'补充信息'}
-
+
处理信息
提交账号${t.submitter?`${U.esc(t.submitter)} (${U.esc(t.user_game_name||'')})`:'匿名'}
-
负责人${t.assignee_name?`${U.esc(t.assignee_name)}`:'待认领'}
+
负责?/span>${t.assignee_name?`${U.esc(t.assignee_name)}`:'待认?/span>'}
${t.claimed_at?`
认领时间${U.date(t.claimed_at)}
`:''}
${isStaff?`
管理操作
- ${canClaim?``:''} - ${isMyTicket?``:''} - ${canTransfer?``:''} - ${isOwner||isMyTicket?``:''} + ${canClaim?``:''} + ${isMyTicket?``:''} + ${canTransfer?``:''} + ${isOwner||isMyTicket?`
`:''} ${!isStaff && t.user_id === Auth.user().id && ['resolved','rejected'].includes(t.status) && t.type !== 'result_appeal' ? `
结果申诉
-

对处理结果有异议?可以提交一次申诉,由服主复核。

- +

对处理结果有异议?可以提交一次申诉,由服主复核?/p> +

`:''} ${t.transfers?.length?` @@ -86,7 +86,7 @@ const TicketDetail = { }, async claimTicket(id) { - U.modal('接单认领', `
`); + U.modal('接单认领', `
`); document.getElementById('claim-form').onsubmit = async e => { e.preventDefault(); try { await API.post(`/tickets/${id}/claim`, {claim_note: document.getElementById('claim-note').value, initial_reply: document.getElementById('claim-reply').value}); App.closeModal(); this.mount(); } catch(ex){alert(ex.message);} }; @@ -94,7 +94,7 @@ const TicketDetail = { async editNote(id) { const t = await API.get(`/tickets/${id}`); - U.modal('更新处理备注', `
`); + U.modal('更新处理备注', `
`); document.getElementById('note-form').onsubmit = async e => { e.preventDefault(); try { await API.put(`/tickets/${id}`, {claim_note: document.getElementById('upd-note').value}); App.closeModal(); this.mount(); } catch(ex){alert(ex.message);} }; @@ -103,14 +103,14 @@ const TicketDetail = { async transferTicket(id) { const users = await API.get('/users'); const staff = users.filter(u => (u.role==='owner'||u.role==='admin') && u.id !== Auth.user().id); - U.modal('转单', `
`); + U.modal('转单', `
`); document.getElementById('tf-form').onsubmit = async e => { e.preventDefault(); try { await API.post(`/tickets/${id}/transfer`, {to_user_id: parseInt(document.getElementById('tf-to').value), reason: document.getElementById('tf-reason').value}); App.closeModal(); this.mount(); } catch(ex){alert(ex.message);} }; }, async changeStatus(id) { - U.modal('变更状态', `
`); + U.modal('变更状?, `
`); document.getElementById('cs-form').onsubmit = async e => { e.preventDefault(); try { await API.put(`/tickets/${id}`, {status:document.getElementById('cs-status').value}); App.closeModal(); this.mount(); } catch(ex){alert(ex.message);} }; @@ -118,10 +118,10 @@ const TicketDetail = { appealResult(parentId) { U.modal('结果申诉', `
-
-
+
申诉后将生成新工单,仅服主可见及处理
- +
`); document.getElementById('ar-form').onsubmit = async e => { e.preventDefault(); try { @@ -133,7 +133,7 @@ const TicketDetail = { parent_ticket_id: parentId, }); App.closeModal(); - alert('申诉已提交,请等待服主处理'); + alert('申诉已提交,请等待服主处?); this.mount(); } catch(ex) { alert(ex.message); } }; diff --git a/public/js/pages/tickets.js b/public/js/pages/tickets.js index 7c99693..4092c13 100644 --- a/public/js/pages/tickets.js +++ b/public/js/pages/tickets.js @@ -20,14 +20,14 @@ const TicketsPage = { ct.innerHTML = `
- - + ' : ''}
- - + + @@ -74,7 +74,7 @@ const TicketsPage = { ct.innerHTML = tickets.length === 0 ? `

暂无工单

` : `
- + ${tickets.map(t => ` @@ -84,7 +84,7 @@ const TicketsPage = { - + `).join('')}
#类型标题提交者对象状态优先级负责人时间操作#类型标题提交?/th>对象状?/th>优先?/th>负责?/th>时间操作
${t.id}${t.target_game_name?`${U.esc(t.target_game_name)}${t.target_game_uid?`
UID:${U.esc(t.target_game_uid)}`:''}`:'-'}
${U.badge(t.status,'status')} ${U.badge(t.priority,'priority')}${t.assignee_name?`${U.esc(t.assignee_name)}`:`待认领`}${t.assignee_name?`${U.esc(t.assignee_name)}`:`待认?/span>`} ${U.date(t.updated_at)}
`; diff --git a/public/js/pages/tracking.js b/public/js/pages/tracking.js index 42d2e10..5b1888a 100644 --- a/public/js/pages/tracking.js +++ b/public/js/pages/tracking.js @@ -19,20 +19,20 @@ const TrackingPage = { async search() { const token = document.getElementById('track-token').value.trim(); - if (!token) return alert('请输入追踪标识'); + if (!token) return alert('请输入追踪标?); const ct = document.getElementById('track-result'); U.loading(ct); try { const tickets = await API.get(`/tickets/tracking?token=${token}`); ct.innerHTML = tickets.length ? ` -
${tickets.map(t => ` +
#类型标题状态时间
${tickets.map(t => ` `).join('')}
#类型标题状?/th>时间
${t.id}${U.badge(t.type,'type')} ${U.esc(t.title)} ${U.badge(t.status,'status')}${U.date(t.created_at)}

如需获取更详细的跟踪和回复通知,请注册账号

- ` : '

未找到工单

'; + ` : '

未找到工?/p>

'; } catch (e) { ct.innerHTML = `
${e.message}
`; } } }; diff --git a/public/js/pages/unclaimed.js b/public/js/pages/unclaimed.js index ef43d54..5af95c3 100644 --- a/public/js/pages/unclaimed.js +++ b/public/js/pages/unclaimed.js @@ -4,7 +4,7 @@ const UnclaimedPage = { async render() { return '
'; }, async mount() { - document.getElementById('page-title').textContent = '待处理工单'; + document.getElementById('page-title').textContent = '待处理工?; document.getElementById('page-actions').innerHTML = ''; const ct = document.getElementById('page-content'); @@ -35,7 +35,7 @@ const UnclaimedPage = { ct.innerHTML = tickets.length === 0 ? `

所有工单已处理完毕

` : `
${tickets.length} 个待处理工单按状态优先级排序
- + ${tickets.map(t => ` @@ -55,7 +55,7 @@ const UnclaimedPage = { }, async quickClaim(id) { - U.modal('接单认领', `
`); + U.modal('接单认领', `
`); document.getElementById('qc-form').onsubmit = async e => { e.preventDefault(); try { await API.post(`/tickets/${id}/claim`, {claim_note: document.getElementById('qc-note').value, initial_reply: document.getElementById('qc-reply').value}); App.closeModal(); this.load(); } catch(ex){alert(ex.message);} }; diff --git a/public/js/pages/users.js b/public/js/pages/users.js index a7f8da0..2c50eb1 100644 --- a/public/js/pages/users.js +++ b/public/js/pages/users.js @@ -13,7 +13,7 @@ const UsersPage = { const users = await API.get('/users'); ct.innerHTML = `
#类型标题提交者对象/详情状态优先级时间操作#类型标题提交?/th>对象/详情状?/th>优先?/th>时间操作
${t.id}${U.badge(t.type,'type')}
- + ${users.map(u => ` @@ -30,10 +30,10 @@ const UsersPage = { createUser() { U.modal('添加用户', ` -
-
-
- +
+
+
+ `); document.getElementById('cu-form').onsubmit = async e => { @@ -56,11 +56,11 @@ const UsersPage = { editUser(id, username, email, gameName, gameUid, role, active) { U.modal('编辑用户', ` -
+
-
-
- +
+
+ `); document.getElementById('eu-form').onsubmit = async e => { diff --git a/public/js/utils.js b/public/js/utils.js index 0aa95c6..d6a3aa3 100644 --- a/public/js/utils.js +++ b/public/js/utils.js @@ -60,5 +60,11 @@ const U = { document.querySelector('.btn-confirm-cancel').onclick = () => { App.closeModal(); resolve(false); }; document.querySelector('.btn-confirm-ok').onclick = () => { App.closeModal(); resolve(true); }; }); + }, + + bindClicks(container, handlers) { + for (const [selector, fn] of Object.entries(handlers)) { + container.querySelectorAll(selector).forEach(el => el.addEventListener('click', fn)); + } } };
#用户名邮箱游戏名游戏UID角色状态时间操作#用户?/th>邮箱游戏?/th>游戏UID角色状?/th>时间操作
${u.id}${U.esc(u.username)}${U.esc(u.email)}