Files
MC_Report/public/js/pages/tickets.js

109 lines
5.3 KiB
JavaScript

const TicketsPage = {
tab: 'all',
filters: {},
async render() { return '<div class="loading"><i class="fas fa-spinner"></i></div>'; },
async mount() {
document.getElementById('page-title').textContent = '工单列表';
document.getElementById('page-actions').innerHTML = `
<button class="btn btn-p btn-sm" onclick="App.navigate('tickets','create?type=report')"><i class="fas fa-flag"></i> 举报</button>
<button class="btn btn-s btn-sm" onclick="App.navigate('tickets','create?type=suggestion')"><i class="fas fa-lightbulb"></i> 建议</button>
`;
this.renderLayout();
await this.loadTab(this.tab);
},
renderLayout() {
const ct = document.getElementById('page-content');
const isStaff = Auth.isAdmin();
ct.innerHTML = `
<div class="tab-nav" id="ticket-tabs">
<button data-tab="all" class="active">全部</button>
<button data-tab="pending">待认领</button>
<button data-tab="claimed">已接单</button>
${Auth.user().role === 'player' ? '<button data-tab="mine">我的工单</button>' : ''}
</div>
<div class="filter-bar">
<select id="ft-type" onchange="TicketsPage.applyFilters()"><option value="">全部类型</option>${Object.entries(U.TYPE).map(([k,v])=>`<option value="${k}">${v}</option>`).join('')}</select>
<select id="ft-status" onchange="TicketsPage.applyFilters()"><option value="">全部状态</option>${Object.entries(U.STATUS).map(([k,v])=>`<option value="${k}">${v}</option>`).join('')}</select>
<select id="ft-priority" onchange="TicketsPage.applyFilters()"><option value="">全部优先级</option>${Object.entries(U.PRIORITY).map(([k,v])=>`<option value="${k}">${v}</option>`).join('')}</select>
<input id="ft-search" placeholder="搜索..." onkeyup="if(event.key==='Enter')TicketsPage.applyFilters()">
<button class="btn btn-o btn-sm" onclick="TicketsPage.applyFilters()"><i class="fas fa-search"></i></button>
<button class="btn btn-o btn-sm" onclick="TicketsPage.resetFilters()"><i class="fas fa-undo"></i></button>
</div>
<div id="ticket-list"></div>
`;
document.querySelectorAll('#ticket-tabs button').forEach(btn => {
btn.onclick = () => {
document.querySelectorAll('#ticket-tabs button').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
this.tab = btn.dataset.tab;
this.loadTab(this.tab);
};
});
},
async loadTab(tab) {
const list = document.getElementById('ticket-list');
U.loading(list);
try {
const params = new URLSearchParams();
if (this.filters.type) params.set('type', this.filters.type);
if (this.filters.status) params.set('status', this.filters.status);
if (this.filters.priority) params.set('priority', this.filters.priority);
if (this.filters.search) params.set('search', this.filters.search);
if (tab === 'pending') params.set('claimed', '0');
else if (tab === 'claimed') params.set('claimed', '1');
else if (tab === 'mine') params.set('status', '');
const qs = params.toString();
const tickets = await API.get('/tickets' + (qs ? '?' + qs : ''));
if (tab === 'mine') {
this.renderList(list, tickets);
return;
}
this.renderList(list, tickets);
} catch (e) { list.innerHTML = `<div class="alert alert-e">${e.message}</div>`; }
},
renderList(ct, tickets) {
ct.innerHTML = tickets.length === 0
? `<div class="empty"><i class="fas fa-inbox"></i><p>暂无工单</p></div>`
: `<div class="card table-wrap"><table><thead><tr>
<th>#</th><th>类型</th><th>标题</th><th>提交者</th><th>对象</th><th>状态</th><th>优先级</th><th>负责人</th><th>时间</th><th>操作</th>
</tr></thead><tbody>${tickets.map(t => `
<tr>
<td>${t.id}</td>
<td>${U.badge(t.type,'type')}</td>
<td><a href="#" onclick="App.navigate('ticket',${t.id});return false" style="color:var(--p);text-decoration:none;font-weight:600">${U.esc(t.title)}</a></td>
<td>${U.esc(t.reporter_game_name)}<br><span class="tm ts">UID:${U.esc(t.reporter_game_uid)}</span></td>
<td>${t.target_game_name?`${U.esc(t.target_game_name)}${t.target_game_uid?`<br><span class="tm ts">UID:${U.esc(t.target_game_uid)}</span>`:''}`:'-'}</td>
<td>${U.badge(t.status,'status')}</td>
<td>${U.badge(t.priority,'priority')}</td>
<td>${t.assignee_name?`<span class="badge bg-admin">${U.esc(t.assignee_name)}</span>`:`<span class="tm">待认领</span>`}</td>
<td class="ts">${U.date(t.updated_at)}</td>
<td><button class="btn btn-o btn-sm" onclick="App.navigate('ticket',${t.id})"><i class="fas fa-eye"></i></button></td>
</tr>`).join('')}</tbody></table></div>`;
},
applyFilters() {
this.filters = {
type: document.getElementById('ft-type').value,
status: document.getElementById('ft-status').value,
priority: document.getElementById('ft-priority').value,
search: document.getElementById('ft-search').value,
};
this.loadTab(this.tab);
},
resetFilters() {
this.filters = {};
document.querySelectorAll('.filter-bar select, .filter-bar input').forEach(el => { if (el.tagName === 'SELECT' || el.tagName === 'INPUT') el.value = ''; });
this.loadTab(this.tab);
}
};