export function createAdmissionViews(context) { const { state, app, h, formatDate, badge, icons, api, renderError, requireLogin, brand } = context; const nav = [['dashboard','工作台','home','总览'],['plans','招生计划','exam','招生业务'],['placements','投档审核','check','招生业务'],['reporting','考生报到','users','招生业务'],['notice-template','通知书模板','ticket','文书中心']]; function shell(page, content, title, description) { const groups = [...new Set(nav.map(item => item[3]))]; return `
招生学校/${h(title)}
${h((state.user?.displayName || '招').slice(0,1))}${h(state.user?.displayName)}招生学校账号

SCHOOL ADMISSION

${h(title)}

${h(description)}

${content}
`; } async function renderAdmission(page) { if (state.user?.role !== 'admission_school') return requireLogin(); if (!nav.some(item => item[0] === page)) page = 'dashboard'; const meta = { dashboard:['招生工作台','查看本校计划完成率、报到进度与待办事项。'], plans:['本校招生计划','上传本年度普通生、特长生计划及指标分配,提交后由超级管理员审核。'], placements:['投档考生审核','查看投档考生资料和本场成绩;无特殊理由不得申请退档。'], reporting:['考生报到','暂存报到状态,支持 Excel 批量维护和通知书二维码核验。'], 'notice-template':['录取通知书模板','设计本校录取通知书的标题、正文、落款与主色,正式录取后由考生下载。'] }; app.innerHTML = shell(page, '
正在读取数据
', ...meta[page]); try { const endpoint = page === 'dashboard' ? 'context' : page; const data = await api(`/api/admission/${endpoint}`); state.pageData = data; const content = page === 'dashboard' ? dashboard(data) : page === 'plans' ? plans(data) : page === 'placements' ? placements(data) : page === 'reporting' ? reporting(data) : noticeTemplate(data); app.innerHTML = shell(page, content, ...meta[page]); } catch (error) { renderError(error); } } function dashboard(data) { const progress = data.plans || []; return `
ADMISSION OFFICE

${h(data.school.name)}

学校只接收超级管理员正式投档的数据,不可查看考生完整志愿表。

${progress.length ? `
${progress.map(plan => `
${h(plan.examName)}${h(plan.progress.admissionRate)}%

计划 ${h(plan.progress.totalQuota)} 人 · 正式录取 ${h(plan.progress.finalCount)} 人 · 已报到 ${h(plan.progress.reportedCount)} 人

实际报到完成率 ${h(plan.progress.reportingRate)}%
`).join('')}
` : ''}

本校工作入口

${data.exams.length} 场启用志愿
${data.notifications?.length ? `

系统自动通知

${data.notifications.length} 条
${data.notifications.map(notice => ``).join('')}
` : ''}
`; } function reporting(data) { if (!data.batches?.length) return `

暂无报到批次

超级管理员签发正式录取通知书并开启报到后,本页会生成报到台账。

`; const statusLabels = { draft: '暂存中', submitted: '报到已提交', pending_approval: '补录决定待审批', approved: '已审批并公示', rejected: '审批退回', not_started: '尚未开始' }; return data.batches.map(batch => { const key = `reporting-${batch.exam.id}-${batch.round}`; const page = paged(batch.rows, key, 20); const editable = ['draft', 'rejected'].includes(batch.status); const importSummary = state.reportingImportSummaries?.[batch.exam.id]; const rowHtml = page.items.map(item => `${editable ? `` : ''}${h(item.name)}${h(item.candidateNumber)}${h(item.noticeNumber)}${h(item.categoryName)}`).join(''); const actions = editable ? `
` : batch.status === 'submitted' ? `
报到情况已提交

请根据实际报到完成率决定是否申请补录;决定需超级管理员审批。

` : `
${h(statusLabels[batch.status] || batch.status)}

${h(batch.approvalNote || batch.decisionNote || '等待下一步处理')}

`; const bulkTools = editable ? `
已选 0 人
` : ''; const ledger = `
${bulkTools}
${editable ? '' : ''}${rowHtml || ``}
选择考生通知书 / 类别报到状态码备注
本轮没有正式录取考生
${pagination(page)}`; const ledgerBlock = editable ? `
${ledger}${actions}
` : `
${ledger}
${actions}`; return `
${h(batch.exam.code)} · 第 ${h(batch.round)} 轮

${h(batch.exam.name)}

计划 ${h(batch.progress.totalQuota)} 人,正式录取 ${h(batch.progress.finalCount)} 人,已报到 ${h(batch.progress.reportedCount)} 人。

${h(batch.progress.reportingRate)}%计划报到完成率
正式录取 ${h(batch.progress.finalCount)}已报到 ${h(batch.progress.reportedCount)}未报到 ${h(batch.progress.notReportedCount)}计划缺额 ${h(batch.progress.reportingGap)}${h(statusLabels[batch.status] || batch.status)}
${editable ? `
Excel 批量维护黄色列填写 Y、N 或 P,导入后只暂存,不会直接提交。
${importSummary ? `
${importSummary.changedCount ? `最近导入已更新 ${h(importSummary.changedCount)} 人` : '最近导入没有产生变化'}读取 ${h(importSummary.count)} 行 · 未变化 ${h(importSummary.unchangedCount)} 行${importSummary.changes?.length ? `${importSummary.changes.slice(0, 3).map(item => `${h(item.name)}:${h(item.fromCode)} → ${h(item.toCode)}`).join(';')}` : 'Excel 内容与当前暂存状态一致。'}
` : ''}
通知书二维码核验打开实时相机扫描;识别后先核对考生,再点击暂存。
` : ''}${ledgerBlock}
`; }).join(''); } function paged(items, key, defaultPageSize = 50) { items = filterTableItems(state, items, key); const current = state.tablePages[key] || {}; const pageSize = [20, 50, 100].includes(Number(current.pageSize)) ? Number(current.pageSize) : defaultPageSize; const total = items.length; const totalPages = Math.max(1, Math.ceil(total / pageSize)); const page = Math.min(Math.max(1, Number(current.page) || 1), totalPages); state.tablePages[key] = { page, pageSize }; return { items: items.slice((page - 1) * pageSize, page * pageSize), page, pageSize, total, totalPages, key }; } function noticeTemplate(data) { const template = data.template || {}; return `

模板设计

正文支持变量:{{考生姓名}}、{{考试名称}}、{{录取学校}}、{{录取类别}}

${data.updatedAt ? `更新于 ${formatDate(data.updatedAt, true)}` : '使用默认模板'}
${h(template.eyebrow || 'ADMISSION NOTICE')}

${h(template.title || '录 取 通 知 书')}

${h(data.school?.name)}

通知书编号:AD01-EX-2026-ZK-000001
张同学:

${h((template.body || '').replaceAll('{{考生姓名}}','张同学').replaceAll('{{考试名称}}','示例考试').replaceAll('{{录取学校}}',data.school?.name || '本校').replaceAll('{{录取类别}}','普通生'))}

${h(template.footer || '')}${h(data.school?.name)}
防伪二维码

右侧为 A4 通知书预览;正式下载件会自动写入通知书编号、防伪查询码与二维码。

`; } function pagination(meta) { if (!meta || meta.total <= meta.pageSize) return ''; const start = (meta.page - 1) * meta.pageSize + 1; const end = Math.min(meta.total, meta.page * meta.pageSize); const pages = [...new Set([1, meta.page - 1, meta.page, meta.page + 1, meta.totalPages])].filter(page => page >= 1 && page <= meta.totalPages); return ``; } function plans(data) { const planPage = paged(data.plans, 'schoolAdmissionPlanTable', 20); return `

提交本校招生计划

按招生类别设置计划人数、特长资格和各生源校指标,提交后由超级管理员审核。

${admissionCategoriesEditor(h, data.sourceSchools)}
${planPage.items.map(plan => ``).join('') || ''}
考试类别计划实时完成率指标分配状态审核意见
${h(data.exams.find(exam => exam.id === plan.examId)?.name || plan.examId)}${plan.payload.categories.map(item => `${h(item.name)} ${h(item.quota)} 人${h(specialtyLabel(item.specialtyCategory, item.specialtyType) || '普通 / 政策类')}`).join('')}${h(plan.progress?.admissionRate || 0)}%正式录取 ${h(plan.progress?.finalCount || 0)} / ${h(plan.progress?.totalQuota || 0)}实际报到 ${h(plan.progress?.reportingRate || 0)}%${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('
') || '无定向指标'}
${badge(plan.status)}${h(plan.payload.reviewNote || '等待审核')}
尚未提交计划
${pagination(planPage)}
`; } function placements(data) { const exportBar = data.completedExams?.length ? `
FINAL ROSTER正式录取考生信息 Excel仅录取工作结束后开放,包含本校全部正式录取考生资料与当次成绩。
` : ''; const exams = [...new Map(data.placements.map(item => [item.examId, item.examName])).entries()]; const categories = [...new Set(data.placements.map(item => item.payload.categoryName).filter(Boolean))]; const pendingCount = data.placements.filter(item => item.status === 'school_review').length; const placementPage = paged(data.placements, 'placementReviewTable'); const rows = placementPage.items.map(item => `${h(item.candidate.name)}${h(item.candidate.registrationNumber)} · ${h(item.candidate.idNumberMasked)}${h(item.examName)}${h(item.candidate.specialtyLabel || '普通生')}${h(item.candidate.specialtyCertificate || '')}${h(item.candidate.policyEligibility || '')}${item.results.map(result => `${h(result.subjectName)} ${h(result.score)}`).join('
')}投档分 ${h(item.payload.totalScore)} · 特征分 ${h(item.featureScore || 0)}${h(item.payload.categoryName)}第 ${h(item.payload.preferenceOrder)} 志愿${badge(item.status)}${item.status === 'school_review' ? `
` : `${h(item.payload.schoolDecisionNote || '已处理')}`}`).join(''); return `${exportBar}

本校投档审核台账

可搜索、筛选和多选批量处理;仅待审核记录可被选中。

${pendingCount} 人待审 / 共 ${data.placements.length} 人
已选 0 人
${rows || ''}
选择考生 / 考试资格当次成绩投档类别状态单人审核
暂无投档考生
${pagination(placementPage)}
`; } return { renderAdmission }; } import { admissionCategoriesEditor } from './admission-plan-editor.mjs'; import { specialtyLabel } from '../data/specialty-types.mjs'; import { filterTableItems } from './table-state.mjs';