录取设置页新增“志愿填报实时快照”,任意阶段均可导出。
Build and publish Docker images / Test, build and publish (push) Successful in 14m13s
Build and publish Docker images / Test, build and publish (push) Successful in 14m13s
志愿台账覆盖未填报、已填报、已锁定、成绩未齐及不可补录考生。 支持按考试、生源学校、状态和关键词筛选。 录取台账支持按考试、招生学校、录取状态和关键词筛选搜索。 两类 Excel 均按页面当前筛选条件导出,并包含学校名称、报名号、轮次、报到状态等完整信息。 全市台账仅超级管理员可导出。
This commit is contained in:
1 parent
c70a97231a
commit
f264103417
6 files changed
+284
-13
No files matched your search
@@ -515,6 +515,21 @@ document.addEventListener('click', async event => {
|
||||
toast(approved ? '审批完成并自动公开' : '已退回招生学校', approved ? (supplement ? '全部学校审批完成后将自动开启补录' : '报到统计已进入公开通知') : '招生学校可修改暂存数据后重新提交');
|
||||
return renderRoute();
|
||||
}
|
||||
if (action === 'admission-ledger-export') {
|
||||
const ledger = target.dataset.ledger;
|
||||
if (!['preferences', 'placements'].includes(ledger)) return;
|
||||
const query = new URLSearchParams();
|
||||
if (target.dataset.examId) query.set('examId', target.dataset.examId);
|
||||
if (target.dataset.round) query.set('round', target.dataset.round);
|
||||
if (target.dataset.table) {
|
||||
const control = getTableControl(state, target.dataset.table);
|
||||
if (String(control.query || '').trim()) query.set('q', String(control.query).trim());
|
||||
if (control.status && control.status !== 'all') query.set('status', control.status);
|
||||
Object.entries(control.filters || {}).forEach(([key, value]) => { if (value) query.set(key, value); });
|
||||
}
|
||||
window.location.href = `/api/admin/admissions/${ledger}/export?${query}`;
|
||||
return;
|
||||
}
|
||||
if (action === 'clear-table-filters') {
|
||||
const tableId = target.dataset.target;
|
||||
state.tableFilters[tableId] = { query: '', status: 'all', filters: {} };
|
||||
|
||||
@@ -125,6 +125,37 @@ const resourceSpecs = {
|
||||
numberColumns: ['featureScore', 'totalScore', 'preferenceOrder'],
|
||||
numberFormats: { featureScore: '0.00', totalScore: '0.00', preferenceOrder: '0' }
|
||||
},
|
||||
admission_preferences: {
|
||||
title: '考生志愿填报实时台账', sheet: '志愿填报情况',
|
||||
columns: [
|
||||
['examCode', '考试代码', 20, 'EX-2026-ZK'], ['examName', '考试名称', 30, '初中学业水平考试'],
|
||||
['round', '填报轮次', 12, 1], ['fillStatus', '填报状态', 16, '已填报'], ['lockStatus', '锁定状态', 16, '未锁定'],
|
||||
['submissionCount', '已提交次数', 14, 1], ['maxSubmissions', '提交次数上限', 16, 3],
|
||||
['candidateNumber', '报名号', 26, '2026-HZ01-F-0001'], ['candidateName', '姓名', 14, '张同学'],
|
||||
['sourceSchoolCode', '生源学校代码', 18, 'HZ01'], ['sourceSchoolName', '生源学校', 26, '海州市第一中学'], ['className', '班级', 18, '九年级一班'],
|
||||
['specialty', '特长生资格', 22, '普通生'], ['indicatorStatus', '指标分配资格', 18, '有资格'],
|
||||
['preferenceOrder', '志愿顺序', 14, 1], ['preferenceType', '志愿类型', 14, '普通志愿'],
|
||||
['targetSchoolCode', '志愿学校代码', 18, 'AD01'], ['targetSchoolName', '志愿学校', 28, '海州市高级中学'],
|
||||
['categoryName', '招生类别', 20, '普通生'], ['submittedAt', '最近提交时间', 24, '2026-07-22 10:18']
|
||||
],
|
||||
numberColumns: ['round', 'submissionCount', 'maxSubmissions', 'preferenceOrder'],
|
||||
numberFormats: { round: '0', submissionCount: '0', maxSubmissions: '0', preferenceOrder: '0' }
|
||||
},
|
||||
admission_placements: {
|
||||
title: '招生录取情况台账', sheet: '录取情况',
|
||||
columns: [
|
||||
['examCode', '考试代码', 20, 'EX-2026-ZK'], ['examName', '考试名称', 30, '初中学业水平考试'], ['round', '录取轮次', 12, 1],
|
||||
['candidateNumber', '报名号', 26, '2026-HZ01-F-0001'], ['candidateName', '姓名', 14, '张同学'],
|
||||
['sourceSchoolCode', '生源学校代码', 18, 'HZ01'], ['sourceSchoolName', '生源学校', 26, '海州市第一中学'], ['className', '班级', 18, '九年级一班'],
|
||||
['specialty', '特长生资格', 22, '普通生'], ['culturalScore', '文化课总分', 14, 560], ['featureScore', '特征分', 12, 0], ['totalScore', '投档总分', 14, 560],
|
||||
['preferenceOrder', '命中志愿序号', 16, 1], ['admissionSchoolCode', '招生学校代码', 18, 'AD01'], ['admissionSchoolName', '招生学校', 28, '海州市高级中学'],
|
||||
['categoryName', '招生类别', 20, '普通生'], ['quotaBucket', '计划类型', 18, '普通计划'], ['admissionStatus', '录取状态', 18, '正式录取'],
|
||||
['reportingStatus', '报到状态', 16, '已报到'], ['noticeNumber', '录取通知书编号', 34, 'AD01-EX-2026-ZK-000001'],
|
||||
['withdrawalReason', '退档或放弃原因', 34, ''], ['updatedAt', '状态更新时间', 24, '2026-07-22 10:18']
|
||||
],
|
||||
numberColumns: ['round', 'culturalScore', 'featureScore', 'totalScore', 'preferenceOrder'],
|
||||
numberFormats: { round: '0', culturalScore: '0.00', featureScore: '0.00', totalScore: '0.00', preferenceOrder: '0' }
|
||||
},
|
||||
admission_reporting: {
|
||||
title: '录取考生报到状态维护表', sheet: '考生报到',
|
||||
columns: [
|
||||
|
||||
@@ -82,9 +82,11 @@ export function createAdminViews(context) {
|
||||
|
||||
function mountPreferenceLedger(data) {
|
||||
const container = app.querySelector('.portal-content');
|
||||
if (!container || !data.preferences?.length) return;
|
||||
const preferencePage = paged(data.preferences, 'adminPreferenceTable');
|
||||
container.insertAdjacentHTML('beforeend', `<section class="panel data-panel admission-preference-ledger"><div class="panel-title"><div><h2>考生志愿只读台账</h2><p>仅超级管理员可查看;系统不提供任何管理员修改入口。</p></div><span>${data.preferences.length} 份</span></div><div class="data-toolbar"><label class="search-box">${icons.search}<input data-action="table-search" data-target="adminPreferenceTable" placeholder="搜索考生、报名号、考试、志愿学校或类别"></label><div class="table-filter-selects"><select data-table-filter="exam" data-target="adminPreferenceTable"><option value="">全部考试</option>${data.exams.map(exam => `<option value="${h(exam.id)}">${h(exam.name)}</option>`).join('')}</select><button class="row-action" data-action="clear-table-filters" data-target="adminPreferenceTable">清除筛选</button></div></div><div class="table-scroll"><table id="adminPreferenceTable"><thead><tr><th>报名号 / 考生</th><th>考试</th><th>轮次</th><th>志愿顺序</th><th>本人提交时间</th></tr></thead><tbody>${preferencePage.items.map(item => `<tr data-exam="${h(item.examId)}"><td><strong>${h(item.candidate.name)}</strong><small class="mono">${h(item.candidate.registrationNumber)}</small></td><td>${h(data.exams.find(exam => exam.id === item.examId)?.name || item.examId)}</td><td>第 ${h(item.payload.round || 1)} 轮</td><td><div class="admin-preference-choices">${item.choices.map((choice, index) => `<span><b>${choice.preferenceType === 'indicator' ? '指标' : index + 1}</b><i><strong>${h(choice.schoolName || choice.schoolId)}</strong><small>${h([choice.schoolCode, choice.categoryName || choice.categoryCode].filter(Boolean).join(' · '))}</small></i></span>`).join('')}</div></td><td>${formatDate(item.payload.submittedAt, true)}</td></tr>`).join('') || '<tr><td colspan="5" class="empty-state">没有符合条件的志愿记录</td></tr>'}</tbody></table></div>${pagination(preferencePage)}</section>`);
|
||||
if (!container) return;
|
||||
const rows = data.preferenceRows || [];
|
||||
const preferencePage = paged(rows, 'adminPreferenceTable');
|
||||
const statusClass = { unfilled: 'pending', submitted: 'approved', locked: 'completed', unavailable: 'closed', ineligible: 'rejected' };
|
||||
container.insertAdjacentHTML('beforeend', `<section class="panel data-panel admission-preference-ledger"><div class="panel-title"><div><h2>考生志愿实时台账</h2><p>同时显示未填报、已填报和已锁定考生;页面仅供监督,不提供代改入口。</p></div><span>当前筛选 ${preferencePage.total} / 共 ${rows.length} 人</span></div><div class="data-toolbar admission-ledger-toolbar"><label class="search-box">${icons.search}<input data-action="table-search" data-target="adminPreferenceTable" placeholder="搜索考生、报名号、生源校、志愿学校或类别"></label><div class="table-filter-selects"><select data-table-filter="examId" data-target="adminPreferenceTable"><option value="">全部考试</option>${data.exams.map(exam => `<option value="${h(exam.id)}">${h(exam.name)}</option>`).join('')}</select><select data-table-filter="sourceSchoolId" data-target="adminPreferenceTable"><option value="">全部生源学校</option>${data.sourceSchools.map(school => `<option value="${h(school.id)}">${h(school.name)}</option>`).join('')}</select></div><div class="filter-pills"><button class="active" data-action="status-filter" data-target="adminPreferenceTable" data-status="all">全部</button><button data-action="status-filter" data-target="adminPreferenceTable" data-status="unfilled">尚未填报</button><button data-action="status-filter" data-target="adminPreferenceTable" data-status="submitted">已填报</button><button data-action="status-filter" data-target="adminPreferenceTable" data-status="locked">已锁定</button><button data-action="status-filter" data-target="adminPreferenceTable" data-status="unavailable">成绩未齐</button><button data-action="status-filter" data-target="adminPreferenceTable" data-status="ineligible">不可补录</button></div><div class="ledger-toolbar-actions"><button class="row-action" data-action="clear-table-filters" data-target="adminPreferenceTable">清除筛选</button><button class="row-action primary" data-action="admission-ledger-export" data-ledger="preferences" data-table="adminPreferenceTable">导出当前筛选</button></div></div><div class="table-scroll"><table id="adminPreferenceTable"><thead><tr><th>报名号 / 考生</th><th>考试 / 生源校</th><th>轮次 / 状态</th><th>志愿顺序</th><th>提交与锁定</th></tr></thead><tbody>${preferencePage.items.map(item => `<tr data-status="${h(item.status)}"><td><strong>${h(item.candidate.name)}</strong><small class="mono">${h(item.candidate.registrationNumber)}</small><small>${h(item.specialty)}</small></td><td><strong>${h(item.examName)}</strong><small>${h(item.sourceSchoolName)}${item.className ? ` · ${h(item.className)}` : ''}</small></td><td>第 ${h(item.round)} 轮<small><span class="status status-${h(statusClass[item.status] || 'pending')}">${h(item.fillStatus)}</span></small></td><td><div class="admin-preference-choices">${item.choices.map((choice, index) => `<span><b>${choice.preferenceType === 'indicator' ? '指标' : index + 1}</b><i><strong>${h(choice.schoolName || choice.schoolId)}</strong><small>${h([choice.schoolCode, choice.categoryName || choice.categoryCode].filter(Boolean).join(' · '))}</small></i></span>`).join('') || '<em class="preference-empty">尚未填报志愿</em>'}</div></td><td><strong>${h(item.submissionCount)} / ${h(item.maxSubmissions)} 次</strong><small>${item.submittedAt ? formatDate(item.submittedAt, true) : '暂无提交时间'} · ${h(item.lockStatus)}</small></td></tr>`).join('') || '<tr><td colspan="5" class="empty-state">没有符合条件的考生填报记录</td></tr>'}</tbody></table></div>${pagination(preferencePage)}</section>`);
|
||||
}
|
||||
|
||||
function adminDashboard(data) {
|
||||
@@ -234,6 +236,13 @@ export function createAdminViews(context) {
|
||||
const accountPage = paged(data.schoolAccounts, 'admissionAccountTable', 20);
|
||||
const planPage = paged(data.plans, 'adminAdmissionPlanTable', 20);
|
||||
const placementPage = paged(data.placements, 'adminPlacementTable');
|
||||
const preferenceSnapshots = data.preferenceRows || [];
|
||||
const preferenceSnapshotPanel = `<section class="panel admission-snapshot-console"><div class="panel-title"><div><h2>志愿填报实时快照</h2><p>不受填报阶段限制,可随时导出当前轮次全部考生的填报、未填报与锁定情况。</p></div><span>${preferenceSnapshots.length} 人</span></div><div class="snapshot-ledger-grid">${data.settings.filter(item => item.payload?.enabled).map(setting => {
|
||||
const exam = data.exams.find(item => item.id === setting.examId) || {};
|
||||
const round = Number(setting.payload?.round || 1);
|
||||
const rows = preferenceSnapshots.filter(item => item.examId === setting.examId && Number(item.round) === round);
|
||||
return `<article><div><span>${h(exam.code || 'EXAM')}</span><h3>${h(exam.name || setting.examId)}</h3><p>第 ${h(round)} 轮 · ${h(phaseLabels[setting.status] || setting.status)}</p></div><dl><div><dt>全部考生</dt><dd>${rows.length}</dd></div><div><dt>尚未填报</dt><dd>${rows.filter(item => item.status === 'unfilled').length}</dd></div><div><dt>已填报</dt><dd>${rows.filter(item => ['submitted', 'locked'].includes(item.status)).length}</dd></div><div><dt>已锁定</dt><dd>${rows.filter(item => item.status === 'locked').length}</dd></div></dl><button class="row-action primary" data-action="admission-ledger-export" data-ledger="preferences" data-exam-id="${h(setting.examId)}" data-round="${h(round)}">导出本轮填报情况</button></article>`;
|
||||
}).join('') || '<p class="empty-state">启用志愿填报后,可在这里随时导出实时台账。</p>'}</div></section>`;
|
||||
const settings = `<section class="panel admission-settings-panel"><div class="panel-title"><div><h2>考试志愿设置</h2><p>成绩发布后按场次开放,并持续向考生展示录取进度。</p></div></div><form data-form="admission-setting"><label><span>考试 *</span><select name="examId" required>${data.exams.map(exam => `<option value="${h(exam.id)}" ${exam.id === selected?.examId ? 'selected' : ''}>${h(exam.name)}</option>`).join('')}</select></label><div class="field-row"><label><span>填报开始</span><input name="preferenceStart" type="datetime-local" value="${h(selected?.payload?.preferenceStart?.slice(0,16))}"></label><label><span>填报结束</span><input name="preferenceEnd" type="datetime-local" value="${h(selected?.payload?.preferenceEnd?.slice(0,16))}"></label></div><div class="field-row"><label><span>当前阶段</span><select name="status">${Object.entries(phaseLabels).map(([value,label]) => `<option value="${value}" ${value === (selected?.status || 'draft') ? 'selected' : ''}>${label}</option>`).join('')}</select></label><label><span>普通志愿数</span><input name="maxChoices" type="number" min="1" max="20" value="${h(selected?.payload?.maxChoices || 5)}"></label></div><div class="field-row"><label><span>最多提交次数</span><input name="maxSubmissions" type="number" min="1" max="50" value="${h(selected?.payload?.maxSubmissions || 3)}"><small>首次保存也计 1 次;达到上限自动锁定。</small></label><label><span>考生进度说明</span><input name="progress" value="${h(selected?.payload?.progress || '')}" placeholder="例如:招生学校正在审核投档名单"></label></div><label class="agreement"><input type="checkbox" name="enabled" ${selected?.payload?.enabled ? 'checked' : ''}><span>为本场考试启用志愿填报</span></label><label class="agreement"><input type="checkbox" name="autoPublish" ${selected?.payload?.autoPublish === false ? '' : 'checked'}><span>录取结束后自动脱敏公示录取结果与分数线</span></label><button class="solid-button" type="submit">保存志愿设置</button></form>${selected ? `<div class="admission-control-actions"><button class="solid-button" data-action="admission-match" data-exam-id="${h(selected.examId)}">按规则投档</button><button class="ghost-button" data-action="admission-finalize" data-exam-id="${h(selected.examId)}">签发通知书并开启报到</button></div><small class="workflow-hint">补录不能手工开启,必须由招生学校提交报到情况和补录决定,并经超级管理员审批。</small>` : ''}</section>`;
|
||||
const accountRows = accountPage.items.map(account => `<tr data-status="${account.active ? 'active' : 'disabled'}" data-school="${h(account.schoolId)}"><td><div class="person-cell"><span>${h((account.displayName || '招').slice(0, 1))}</span><div><strong>${h(account.displayName)}</strong><small>${h(account.id)}</small></div></div></td><td><strong class="mono">${h(account.username)}</strong></td><td><strong>${h(account.schoolName || '未绑定')}</strong><small class="mono">${h(account.schoolCode || '')}</small></td><td><span class="status status-${account.active ? 'approved' : 'closed'}">${account.active ? '已启用' : '已停用'}</span></td><td>${formatDate(account.createdAt, true)}</td><td><div class="admin-account-actions"><button class="row-action" data-action="reset-admission-account-password" data-id="${h(account.id)}">重置密码</button><button class="row-action ${account.active ? 'danger' : 'primary'}" data-action="toggle-admission-account" data-id="${h(account.id)}" data-active="${account.active ? 'false' : 'true'}">${account.active ? '停用账户' : '重新启用'}</button></div></td></tr>`).join('');
|
||||
const accounts = `<section class="panel admission-account-panel admission-account-management"><div class="panel-title"><div><h2>招生学校账户管理</h2><p>创建并维护各招生学校登录账户;停用会立即结束该账户现有会话。</p></div><span>${data.schoolAccounts.filter(item => item.active).length} 个启用 / 共 ${data.schoolAccounts.length} 个</span></div><form data-form="admission-account"><label><span>招生学校 *</span><select name="schoolId" required>${data.admissionSchools.map(school => `<option value="${h(school.id)}">${h(school.code)} · ${h(school.name)}</option>`).join('')}</select></label><div class="field-row"><label><span>登录账号 *</span><input name="username" required></label><label><span>初始密码 *</span><input name="password" type="password" minlength="8" required></label></div><label><span>显示名称</span><input name="displayName" placeholder="学校招生办公室"></label><button class="solid-button" type="submit">创建招生学校账号</button></form><div class="account-management-divider"><strong>已建账户</strong><span>保留历史记录,不提供物理删除</span></div><div class="data-toolbar"><label class="search-box">${icons.search}<input data-action="table-search" data-target="admissionAccountTable" placeholder="跨页搜索学校、账号或显示名称"></label><div class="table-filter-selects"><select data-table-filter="school" data-target="admissionAccountTable"><option value="">全部招生学校</option>${data.admissionSchools.map(school => `<option value="${h(school.id)}">${h(school.name)}</option>`).join('')}</select></div></div><div class="filter-pills account-status-pills"><button type="button" class="active" data-action="status-filter" data-target="admissionAccountTable" data-status="all">全部</button><button type="button" data-action="status-filter" data-target="admissionAccountTable" data-status="active">已启用</button><button type="button" data-action="status-filter" data-target="admissionAccountTable" data-status="disabled">已停用</button></div><div class="table-scroll"><table id="admissionAccountTable"><thead><tr><th>账户</th><th>登录账号</th><th>绑定招生学校</th><th>状态</th><th>创建时间</th><th>账户操作</th></tr></thead><tbody>${accountRows || '<tr><td colspan="6" class="empty-state">还没有招生学校账户</td></tr>'}</tbody></table></div>${pagination(accountPage)}</section>`;
|
||||
@@ -241,10 +250,10 @@ export function createAdminViews(context) {
|
||||
const plans = `<section class="panel data-panel"><div class="panel-title"><div><h2>招生计划审核与完成率</h2><p>实时核对计划、正式录取和实际报到完成情况。</p></div><span>${pendingPlans.length} 份待审</span></div><div class="data-toolbar"><label class="search-box">${icons.search}<input data-action="table-search" data-target="adminAdmissionPlanTable" placeholder="搜索考试、学校、招生类别或指标学校"></label><div class="filter-pills"><button class="active" data-action="status-filter" data-target="adminAdmissionPlanTable" data-status="all">全部</button><button data-action="status-filter" data-target="adminAdmissionPlanTable" data-status="pending">待审核</button><button data-action="status-filter" data-target="adminAdmissionPlanTable" data-status="approved">已通过</button><button data-action="status-filter" data-target="adminAdmissionPlanTable" data-status="rejected">已退回</button></div></div><div class="table-scroll"><table id="adminAdmissionPlanTable"><thead><tr><th>考试 / 学校</th><th>计划构成</th><th>实时完成率</th><th>指标分配</th><th>状态</th><th>操作</th></tr></thead><tbody>${planPage.items.map(plan => `<tr data-status="${h(plan.status)}"><td><strong>${h(plan.examName)}</strong><small>${h(plan.schoolName)}</small></td><td>${plan.payload.categories.map(category => `<strong>${h(category.name)} ${h(category.quota)} 人</strong><small>${h(specialtyLabel(category.specialtyCategory, category.specialtyType) || '普通 / 政策类')}</small>`).join('')}</td><td><strong>${h(plan.progress?.admissionRate || 0)}%</strong><small>正式录取 ${h(plan.progress?.finalCount || 0)} / ${h(plan.progress?.totalQuota || 0)}</small><small>实际报到 ${h(plan.progress?.reportingRate || 0)}%</small></td><td>${plan.payload.categories.flatMap(category => (category.indicatorAllocations || []).map(allocation => `${h(data.sourceSchools.find(item => item.id === allocation.sourceSchoolId)?.name || allocation.sourceSchoolId)} ${h(allocation.quota)} 人`)).join('<br>') || '无定向指标'}</td><td>${badge(plan.status)}</td><td>${plan.status === 'pending' ? `<button class="row-action primary" data-action="admission-plan-review" data-id="${h(plan.id)}" data-status="approved">通过</button><button class="row-action" data-action="admission-plan-review" data-id="${h(plan.id)}" data-status="rejected">退回</button>` : h(plan.payload.reviewNote || '')}</td></tr>`).join('') || '<tr><td colspan="6" class="empty-state">暂无招生计划</td></tr>'}</tbody></table></div>${pagination(planPage)}</section>`;
|
||||
const reportingPage = paged(data.reportingRequests || [], 'adminReportingApprovalTable', 20);
|
||||
const reportingApprovals = `<section class="panel data-panel"><div class="panel-title"><div><h2>报到情况与补录审批</h2><p>学校决定审批通过后,统计数据和说明将自动进入公开通知。</p></div><span>${(data.reportingRequests || []).filter(item => item.status === 'pending_approval').length} 项待审批</span></div><div class="data-toolbar"><label class="search-box">${icons.search}<input data-action="table-search" data-target="adminReportingApprovalTable" placeholder="搜索考试、学校、轮次、决定或说明"></label><div class="filter-pills"><button class="active" data-action="status-filter" data-target="adminReportingApprovalTable" data-status="all">全部</button><button data-action="status-filter" data-target="adminReportingApprovalTable" data-status="draft">草稿</button><button data-action="status-filter" data-target="adminReportingApprovalTable" data-status="submitted">已提交</button><button data-action="status-filter" data-target="adminReportingApprovalTable" data-status="pending_approval">待审批</button><button data-action="status-filter" data-target="adminReportingApprovalTable" data-status="approved">已通过</button><button data-action="status-filter" data-target="adminReportingApprovalTable" data-status="rejected">已退回</button></div></div><div class="table-scroll"><table id="adminReportingApprovalTable"><thead><tr><th>考试 / 学校</th><th>报到统计</th><th>学校决定</th><th>状态</th><th>审批</th></tr></thead><tbody>${reportingPage.items.map(item => `<tr data-status="${h(item.status)}"><td><strong>${h(item.examName)}</strong><small>${h(item.schoolName)} · 第 ${h(item.payload?.round || 1)} 轮</small></td><td>计划 ${h(item.progress.totalQuota)} 人 · 已报到 ${h(item.progress.reportedCount)} 人<small>完成率 ${h(item.progress.reportingRate)}% · 缺额 ${h(item.progress.reportingGap)} 人</small></td><td><strong>${item.payload?.supplementDecision === 'supplement' ? '申请补录' : '不进行补录'}</strong><small>${h(item.payload?.decisionNote || '')}</small></td><td>${badge(item.status)}</td><td>${item.status === 'pending_approval' ? `<button class="row-action primary" data-action="review-admission-reporting" data-id="${h(item.id)}" data-approved="true" data-supplement="${item.payload?.supplementDecision === 'supplement'}">批准并公开</button><button class="row-action" data-action="review-admission-reporting" data-id="${h(item.id)}" data-approved="false">退回</button>` : h(item.payload?.approvalNote || '—')}</td></tr>`).join('') || '<tr><td colspan="5" class="empty-state">暂无报到与补录审批记录</td></tr>'}</tbody></table></div>${pagination(reportingPage)}</section>`;
|
||||
const placements = `<section class="panel data-panel"><div class="panel-title"><div><h2>投档与退档监督</h2><p>支持跨页搜索考生、报名号、学校与类别;志愿保持只读。</p></div><span>共 ${data.placements.length} 条</span></div><div class="data-toolbar placement-supervision-toolbar"><label class="search-box">${icons.search}<input data-action="table-search" data-target="adminPlacementTable" placeholder="搜索考生、报名号、投档学校、类别或退档理由"></label><div class="filter-pills"><button class="active" data-action="status-filter" data-target="adminPlacementTable" data-status="all">全部</button><button data-action="status-filter" data-target="adminPlacementTable" data-status="school_review">学校审核中</button><button data-action="status-filter" data-target="adminPlacementTable" data-status="withdrawal_pending">退档待审</button><button data-action="status-filter" data-target="adminPlacementTable" data-status="final">正式录取</button><button data-action="status-filter" data-target="adminPlacementTable" data-status="withdrawn">已退档</button><button data-action="status-filter" data-target="adminPlacementTable" data-status="forfeited">未报到放弃</button></div><button class="row-action" data-action="clear-table-filters" data-target="adminPlacementTable">清除筛选</button></div><div class="table-scroll"><table id="adminPlacementTable"><thead><tr><th>考生</th><th>成绩 / 志愿</th><th>投档学校</th><th>类别</th><th>状态</th><th>退档审核</th></tr></thead><tbody>${placementPage.items.map(item => `<tr data-status="${h(item.status)}"><td><strong>${h(item.candidate.name)}</strong><small class="mono">${h(item.candidate.registrationNumber)}</small><small>${h(item.candidate.specialtyLabel || '普通生')}</small></td><td>${h(item.payload.totalScore)} 分 · 特征分 ${h(item.payload.featureScore || 0)} · 第 ${h(item.payload.preferenceOrder)} 志愿</td><td>${h(item.schoolName)}</td><td>${h(item.payload.categoryName)}</td><td>${badge(item.status)}</td><td>${item.status === 'withdrawal_pending' ? `<small>${h(item.payload.withdrawalReason)}</small><button class="row-action primary" data-action="withdrawal-review" data-id="${h(item.id)}" data-approved="true">批准</button><button class="row-action" data-action="withdrawal-review" data-id="${h(item.id)}" data-approved="false">驳回</button>` : '—'}</td></tr>`).join('') || '<tr><td colspan="6" class="empty-state">尚未产生投档记录</td></tr>'}</tbody></table></div>${pagination(placementPage)}</section>`;
|
||||
const placements = `<section class="panel data-panel"><div class="panel-title"><div><h2>录取情况台账</h2><p>支持跨页搜索、考试/学校/状态筛选,并按当前筛选结果导出 Excel。</p></div><span>当前筛选 ${placementPage.total} / 共 ${data.placements.length} 条</span></div><div class="data-toolbar placement-supervision-toolbar"><label class="search-box">${icons.search}<input data-action="table-search" data-target="adminPlacementTable" placeholder="搜索考生、报名号、考试、学校、类别或退档理由"></label><div class="table-filter-selects"><select data-table-filter="examId" data-target="adminPlacementTable"><option value="">全部考试</option>${data.exams.map(exam => `<option value="${h(exam.id)}">${h(exam.name)}</option>`).join('')}</select><select data-table-filter="schoolId" data-target="adminPlacementTable"><option value="">全部招生学校</option>${data.admissionSchools.map(school => `<option value="${h(school.id)}">${h(school.name)}</option>`).join('')}</select></div><div class="filter-pills"><button class="active" data-action="status-filter" data-target="adminPlacementTable" data-status="all">全部</button><button data-action="status-filter" data-target="adminPlacementTable" data-status="school_review">学校审核中</button><button data-action="status-filter" data-target="adminPlacementTable" data-status="withdrawal_pending">退档待审</button><button data-action="status-filter" data-target="adminPlacementTable" data-status="final">正式录取</button><button data-action="status-filter" data-target="adminPlacementTable" data-status="withdrawn">已退档</button><button data-action="status-filter" data-target="adminPlacementTable" data-status="forfeited">未报到放弃</button></div><div class="ledger-toolbar-actions"><button class="row-action" data-action="clear-table-filters" data-target="adminPlacementTable">清除筛选</button><button class="row-action primary" data-action="admission-ledger-export" data-ledger="placements" data-table="adminPlacementTable">导出当前筛选</button></div></div><div class="table-scroll"><table id="adminPlacementTable"><thead><tr><th>考生 / 生源校</th><th>考试 / 成绩</th><th>录取学校</th><th>类别</th><th>录取 / 报到状态</th><th>退档审核</th></tr></thead><tbody>${placementPage.items.map(item => `<tr data-status="${h(item.status)}"><td><strong>${h(item.candidate.name)}</strong><small class="mono">${h(item.candidate.registrationNumber)}</small><small>${h(item.sourceSchoolName || '生源校未登记')}${item.className ? ` · ${h(item.className)}` : ''}</small></td><td><strong>${h(item.examName || item.examId)}</strong><small>${h(item.payload.totalScore)} 分 · 特征分 ${h(item.payload.featureScore || 0)} · 第 ${h(item.payload.preferenceOrder)} 志愿</small></td><td><strong>${h(item.schoolName)}</strong><small class="mono">${h(item.schoolCode || '')}</small></td><td>${h(item.payload.categoryName)}<small>${h(item.candidate.specialtyLabel || '普通生')}</small></td><td>${badge(item.status)}<small>报到:${h(item.reportingStatusLabel || '—')}</small></td><td>${item.status === 'withdrawal_pending' ? `<small>${h(item.payload.withdrawalReason)}</small><button class="row-action primary" data-action="withdrawal-review" data-id="${h(item.id)}" data-approved="true">批准</button><button class="row-action" data-action="withdrawal-review" data-id="${h(item.id)}" data-approved="false">驳回</button>` : '—'}</td></tr>`).join('') || '<tr><td colspan="6" class="empty-state">没有符合条件的录取记录</td></tr>'}</tbody></table></div>${pagination(placementPage)}</section>`;
|
||||
const banner = `<section class="admission-command-banner"><div><span>ADMISSION COMMAND</span><h2>中考招生录取控制台</h2><p>计划完成率、考生报到与补录审批在同一条可审计链路中实时更新。</p></div><dl><div><dt>待审计划</dt><dd>${pendingPlans.length}</dd></div><div><dt>补录待审批</dt><dd>${(data.reportingRequests || []).filter(item => item.status === 'pending_approval').length}</dd></div><div><dt>正式录取</dt><dd>${data.placements.filter(item => item.status === 'final').length}</dd></div><div><dt>已报到</dt><dd>${(data.reportingRequests || []).reduce((sum, item) => sum + Number(item.progress?.reportedCount || 0), 0)}</dd></div></dl></section>`;
|
||||
const sections = {
|
||||
settings: `<div class="admission-admin-grid single">${settings}</div>`,
|
||||
settings: `<div class="admission-admin-grid single">${settings}${preferenceSnapshotPanel}</div>`,
|
||||
accounts,
|
||||
plans: `${planForm}${plans}`,
|
||||
reporting: reportingApprovals,
|
||||
|
||||
Loaded 3 of 6 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user