feat: batch ticket operations (close/delete/change status)

This commit is contained in:
2026-07-17 21:55:15 +08:00
parent ed6fe9dcf1
commit 5497de9aac
2 changed files with 61 additions and 1 deletions

View File

@@ -62,12 +62,24 @@ const TicketsPage = {
},
renderList(ct, tickets) {
const isStaff = Auth.isAdmin();
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>
: `${isStaff ? `<div class="filter-bar">
<button class="btn btn-o btn-sm" onclick="TicketsPage.selectAll()">全选</button>
<button class="btn btn-w btn-sm" onclick="TicketsPage.batchAction('close')">批量关闭</button>
<button class="btn btn-d btn-sm" onclick="TicketsPage.batchAction('delete')">批量删除</button>
<select id="batch-status" class="btn-o btn-sm" style="padding:5px 10px;font-size:12px;border:1px solid var(--g300);border-radius:var(--r)">
<option value="resolved">已解决</option><option value="rejected">已驳回</option><option value="processing">处理中</option><option value="pending">待处理</option>
</select>
<button class="btn btn-o btn-sm" onclick="TicketsPage.batchAction('status')">批量改状态</button>
</div>` : ''}
<div class="card table-wrap"><table><thead><tr>
${isStaff ? '<th><input type="checkbox" id="select-all" onchange="TicketsPage.toggleAll()"></th>' : ''}
<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>
${isStaff ? `<td><input type="checkbox" class="ticket-cb" value="${t.id}"></td>` : ''}
<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>
@@ -94,5 +106,27 @@ const TicketsPage = {
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);
},
toggleAll() {
const checked = document.getElementById('select-all').checked;
document.querySelectorAll('.ticket-cb').forEach(cb => cb.checked = checked);
},
selectAll() {
document.querySelectorAll('.ticket-cb').forEach(cb => cb.checked = true);
document.getElementById('select-all').checked = true;
},
selectedIds() {
return Array.from(document.querySelectorAll('.ticket-cb:checked')).map(cb => parseInt(cb.value));
},
async batchAction(action) {
const ids = this.selectedIds();
if (!ids.length) return alert('请先选择工单');
const status = document.getElementById('batch-status')?.value;
if (!confirm(`确认${action==='delete'?'删除':'操作'} ${ids.length} 个工单?`)) return;
try { await API.post('/tickets/batch', { ids, action, status }); this.loadTab(this.tab); } catch(ex){alert(ex.message);}
}
};