Add structured admission plans and school role management

This commit is contained in:
2026-07-21 14:04:19 +08:00 Unverified
parent 1b6e860013
commit 5e0bee60e2
23 changed files with 483 additions and 82 deletions
+5 -2
View File
@@ -24,11 +24,14 @@ export function createAdmissionViews(context) {
}
function plans(data) {
return `<section class="panel admission-plan-console"><div class="panel-title"><div><h2>提交本校招生计划</h2><p>每行格式:类别名称 | 计划人数 | 特长类型(普通生留空)。</p></div></div><form data-form="school-admission-plan"><label><span>招生考试 *</span><select name="examId">${data.exams.map(exam => `<option value="${h(exam.id)}">${h(exam.name)}</option>`).join('')}</select></label><label><span>招生类别 *</span><textarea name="categoriesText" rows="5" required placeholder="普通生 | 120 |&#10;体育特长生 | 8 | 田径"></textarea></label><label><span>计划说明</span><textarea name="note" rows="2"></textarea></label><button class="solid-button" type="submit">提交超级管理员审核</button></form></section><section class="panel data-panel"><div class="table-scroll"><table><thead><tr><th>考试</th><th>类别计划</th><th>状态</th><th>审核意见</th></tr></thead><tbody>${data.plans.map(plan => `<tr><td>${h(data.exams.find(exam => exam.id === plan.examId)?.name || plan.examId)}</td><td>${plan.payload.categories.map(item => `${h(item.name)} ${h(item.quota)}`).join('<br>')}</td><td>${badge(plan.status)}</td><td>${h(plan.payload.reviewNote || '等待审核')}</td></tr>`).join('') || '<tr><td colspan="4" class="empty-state">尚未提交计划</td></tr>'}</tbody></table></div></section>`;
return `<section class="panel admission-plan-console structured"><div class="panel-title"><div><h2>提交本校招生计划</h2><p>按招生类别设置计划人数、特长资格和各生源校指标,提交后由超级管理员审核。</p></div></div><form data-form="school-admission-plan"><label><span>招生考试 *</span><select name="examId" required>${data.exams.map(exam => `<option value="${h(exam.id)}">${h(exam.name)}</option>`).join('')}</select></label>${admissionCategoriesEditor(h, data.sourceSchools)}<label><span>计划说明</span><textarea name="note" rows="2" placeholder="填写政策依据或补充说明"></textarea></label><button class="solid-button" type="submit">提交超级管理员审核</button></form></section><section class="panel data-panel"><div class="table-scroll"><table><thead><tr><th>考试</th><th>类别计划</th><th>指标分配</th><th>状态</th><th>审核意见</th></tr></thead><tbody>${data.plans.map(plan => `<tr><td>${h(data.exams.find(exam => exam.id === plan.examId)?.name || plan.examId)}</td><td>${plan.payload.categories.map(item => `<strong>${h(item.name)} ${h(item.quota)}</strong><small>${h(specialtyLabel(item.specialtyCategory, item.specialtyType) || '普通 / 政策类')}</small>`).join('')}</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>${h(plan.payload.reviewNote || '等待审核')}</td></tr>`).join('') || '<tr><td colspan="5" class="empty-state">尚未提交计划</td></tr>'}</tbody></table></div></section>`;
}
function placements(data) {
return `<section class="panel data-panel"><div class="panel-title"><div><h2>本校投档名单</h2><p>显示投档所需的考生信息与当次成绩,不包含其余志愿。</p></div><span>${data.placements.length} 人</span></div><div class="table-scroll"><table><thead><tr><th>考生</th><th>资格</th><th>当次成绩</th><th>投档类别</th><th>状态</th><th>审核</th></tr></thead><tbody>${data.placements.map(item => `<tr><td><strong>${h(item.candidate.name)}</strong><small class="mono">${h(item.candidate.registrationNumber)} · ${h(item.candidate.idNumberMasked)}</small></td><td>${h((item.candidate.specialtyTypes || []).join('、') || '普通生')}<small>${h(item.candidate.policyEligibility || '')}</small></td><td>${item.results.map(result => `${h(result.subjectName)} ${h(result.score)}`).join('<br>')}<strong>总分 ${h(item.payload.totalScore)}</strong></td><td>${h(item.payload.categoryName)}<small>第 ${h(item.payload.preferenceOrder)} 志愿</small></td><td>${badge(item.status)}</td><td>${item.status === 'school_review' ? `<form class="placement-review-form" data-form="placement-review"><input type="hidden" name="id" value="${h(item.id)}"><select name="decision"><option value="accept">接收</option><option value="withdraw">申请退档</option></select><input name="note" placeholder="退档须填写特殊理由"><button class="row-action primary" type="submit">确认</button></form>` : `<small>${h(item.payload.schoolDecisionNote || '已处理')}</small>`}</td></tr>`).join('') || '<tr><td colspan="6" class="empty-state">暂无投档考生</td></tr>'}</tbody></table></div></section>`;
const exportBar = data.completedExams?.length ? `<section class="panel admission-export-bar"><div><span>FINAL ROSTER</span><strong>正式录取考生信息 Excel</strong><small>仅录取工作结束后开放,包含本校全部正式录取考生资料与当次成绩</small></div><label><span>已完成考试</span><select name="exportExamId">${data.completedExams.map(exam => `<option value="${h(exam.id)}">${h(exam.name)}</option>`).join('')}</select></label><button class="solid-button" data-action="download-admitted-candidates">下载 Excel</button></section>` : '';
return `${exportBar}<section class="panel data-panel"><div class="panel-title"><div><h2>本校投档名单</h2><p>显示投档所需的考生信息与当次成绩,不包含其余志愿。</p></div><span>${data.placements.length} 人</span></div><div class="table-scroll"><table><thead><tr><th>考生</th><th>资格</th><th>当次成绩</th><th>投档类别</th><th>状态</th><th>审核</th></tr></thead><tbody>${data.placements.map(item => `<tr><td><strong>${h(item.candidate.name)}</strong><small class="mono">${h(item.candidate.registrationNumber)} · ${h(item.candidate.idNumberMasked)}</small></td><td>${h(item.candidate.specialtyLabel || '普通生')}<small>${h(item.candidate.specialtyCertificate || '')}</small><small>${h(item.candidate.policyEligibility || '')}</small></td><td>${item.results.map(result => `${h(result.subjectName)} ${h(result.score)}`).join('<br>')}<strong>总分 ${h(item.payload.totalScore)} · 特征分 ${h(item.featureScore || 0)}</strong></td><td>${h(item.payload.categoryName)}<small>第 ${h(item.payload.preferenceOrder)} 志愿</small></td><td>${badge(item.status)}</td><td>${item.status === 'school_review' ? `<form class="placement-review-form" data-form="placement-review"><input type="hidden" name="id" value="${h(item.id)}"><select name="decision"><option value="accept">接收</option><option value="withdraw">申请退档</option></select><input name="note" placeholder="退档须填写特殊理由"><button class="row-action primary" type="submit">确认</button></form>` : `<small>${h(item.payload.schoolDecisionNote || '已处理')}</small>`}</td></tr>`).join('') || '<tr><td colspan="6" class="empty-state">暂无投档考生</td></tr>'}</tbody></table></div></section>`;
}
return { renderAdmission };
}
import { admissionCategoriesEditor } from './admission-plan-editor.mjs';
import { specialtyLabel } from '../data/specialty-types.mjs';