This commit is contained in:
2026-07-21 16:43:57 +08:00 Unverified
parent 722bb6f016
commit 48bef02904
7 changed files with 168 additions and 5 deletions
+51
View File
@@ -158,6 +158,21 @@ function updateQualificationSelection(container) {
if (count) count.textContent = `已选 ${selected.length}`;
}
function updatePlacementSelection() {
const table = document.getElementById('placementReviewTable');
if (!table) return;
const selectable = [...table.querySelectorAll('[data-placement-select]:not(:disabled)')];
const visible = selectable.filter(input => !input.closest('tr').hidden);
const selected = selectable.filter(input => input.checked);
const selectAll = document.querySelector('[data-placement-select-all][data-target="placementReviewTable"]');
if (selectAll) {
selectAll.checked = visible.length > 0 && visible.every(input => input.checked);
selectAll.indeterminate = visible.some(input => input.checked) && !selectAll.checked;
}
const count = document.querySelector('[data-placement-selected-count]');
if (count) count.textContent = `已选 ${selected.length}`;
}
function applyTableFilters(tableId) {
const table = document.getElementById(tableId);
if (!table) return;
@@ -174,6 +189,7 @@ function applyTableFilters(tableId) {
if (tableId === 'registrationTable') updateRegistrationSelection();
if (tableId === 'candidateTable') updateCandidateSelection();
if (tableId === 'paymentTable') updatePaymentSelection();
if (tableId === 'placementReviewTable') updatePlacementSelection();
if (table.closest('.qualification-ledger')) updateQualificationSelection(table.closest('.qualification-ledger'));
}
@@ -360,6 +376,20 @@ document.addEventListener('click', async event => {
toast(data.published ? '批量确认完成并自动公示' : '批量确认完成', `已更新 ${data.count} 名考生`);
return renderRoute();
}
if (action === 'bulk-placement-review') {
const ids = [...document.querySelectorAll('#placementReviewTable [data-placement-select]:checked')].map(input => input.value);
const decision = target.dataset.decision;
if (!ids.length) return toast('请先选择待审核考生', '可勾选单人,或选择当前筛选结果');
let note = '';
if (decision === 'withdraw') {
note = window.prompt(`将为所选 ${ids.length} 名考生申请退档,请填写统一的特殊理由(至少 8 个字)`, '') ?? '';
if (!note) return;
if (note.trim().length < 8) return toast('退档理由至少需要 8 个字');
} else if (!window.confirm(`确认批量接收所选 ${ids.length} 名投档考生吗?`)) return;
const result = await api('/api/admission/placements/bulk', { method: 'POST', body: { ids, decision, note } });
toast(decision === 'accept' ? '批量接收完成' : '批量退档申请已提交', `已处理 ${result.count} 名考生`);
return renderRoute();
}
if (action === 'toggle-admin-account') {
const active = target.dataset.active === 'true';
if (!active && !window.confirm('确认停用该管理员账户?其现有登录会话会立即失效,历史审批记录将保留。')) return;
@@ -373,6 +403,19 @@ document.addEventListener('click', async event => {
setModal(`<div class="modal-head"><div><span>ADMIN PASSWORD RESET</span><h2>管理员临时密码已生成</h2><p>请通过线下安全渠道交给管理员,本页面关闭后不再展示。</p></div><button data-action="close-modal">×</button></div><div class="issued-number"><span>登录账号</span><strong>${h(data.username)}</strong><span>临时密码</span><strong>${h(data.temporaryPassword)}</strong><p>旧密码和现有登录会话均已失效。</p></div><div class="modal-foot"><button class="solid-button" data-action="close-modal">我已保存</button></div>`);
return;
}
if (action === 'toggle-admission-account') {
const active = target.dataset.active === 'true';
if (!active && !window.confirm('确认停用该招生学校账户?现有登录会话会立即失效,历史审核记录继续保留。')) return;
await api(`/api/admin/admission-school-accounts/${target.dataset.id}`, { method: 'PATCH', body: { active } });
toast(active ? '招生学校账户已启用' : '招生学校账户已停用');
return renderRoute();
}
if (action === 'reset-admission-account-password') {
if (!window.confirm('确认重置该招生学校账户密码?旧密码和现有登录会话会立即失效。')) return;
const data = await api(`/api/admin/admission-school-accounts/${target.dataset.id}/reset-password`, { method: 'POST' });
setModal(`<div class="modal-head"><div><span>ADMISSION ACCOUNT RESET</span><h2>招生学校临时密码已生成</h2><p>请通过线下安全渠道交给招生学校,本页面关闭后不再展示。</p></div><button data-action="close-modal">×</button></div><div class="issued-number"><span>登录账号</span><strong>${h(data.username)}</strong><span>临时密码</span><strong>${h(data.temporaryPassword)}</strong><p>账户已同步启用,旧密码和现有会话均已失效。</p></div><div class="modal-foot"><button class="solid-button" data-action="close-modal">我已保存</button></div>`);
return;
}
if (action === 'add-admission-category') {
const sources = state.pageData?.sourceSchools || [];
target.closest('form')?.querySelector('[data-admission-categories]')?.insertAdjacentHTML('beforeend', admissionCategoryEditor(h, sources));
@@ -635,6 +678,14 @@ document.addEventListener('input', event => {
});
document.addEventListener('change', event => {
if (event.target.matches('[data-placement-select]')) updatePlacementSelection();
if (event.target.matches('[data-placement-select-all]')) {
const table = document.getElementById(event.target.dataset.target);
table?.querySelectorAll('[data-placement-select]:not(:disabled)').forEach(input => {
if (!input.closest('tr').hidden) input.checked = event.target.checked;
});
updatePlacementSelection();
}
if (event.target.matches('[data-action="result-bulk-exam"]')) {
state.resultExamFilter = event.target.value;
state.resultSubjectFilter = '';