已录取且报到的考生:补录入口隐藏,接口再次提交会返回 403。
多学校补录:按同一轮全部获批学校开放,并修复“放弃考生仍占用名额”的计算问题。 志愿锁定显示:保存学校和类别名称快照;旧数据中的 general 等代码也能还原名称。考生端、管理员台账同步修复。 录取结果通知:改为正式签发卡片,展示学校、类别、考试、通知书编号和录取状态,并适配移动端。
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { admissionCutoffRows, admissionPlanProgress, admissionRoundPublications, assignAdmissionNoticeNumbers, buildVolunteerPlacements, candidateAdmissionScore, candidateTotalScore, publicAdmissionRows, remainingPlanQuota, sourceSchoolQualificationStatus } from '../src/services/volunteer-admission.mjs';
|
||||
import { admissionCutoffRows, admissionPlanProgress, admissionRoundPublications, assignAdmissionNoticeNumbers, buildVolunteerPlacements, candidateAdmissionScore, candidateTotalScore, publicAdmissionRows, remainingPlanQuota, sourceSchoolQualificationStatus, supplementarySchoolIds } from '../src/services/volunteer-admission.mjs';
|
||||
import { candidateEligibleForCategory, specialtyLabel } from '../src/data/specialty-types.mjs';
|
||||
import { systemNotificationItems } from '../src/services/system-notifications.mjs';
|
||||
|
||||
@@ -75,6 +75,25 @@ db.admissionRecords.push(...placements.map(item => ({ ...item, status: 'final' }
|
||||
const remaining = remainingPlanQuota(db, db.admissionRecords.find(item => item.id === 'plan-b'));
|
||||
assert.equal(remaining.find(item => item.code === 'general').remaining, 0, '普通生计划占用应准确统计');
|
||||
assert.equal(remaining.find(item => item.code === 'sport').remaining, 0, '特长生计划占用应准确统计');
|
||||
|
||||
const supplementDb = structuredClone(db);
|
||||
const supplementSetting = { id: 'setting-supplement', kind: 'setting', examId: 'exam', status: 'supplementary', payload: { round: 2 } };
|
||||
supplementDb.admissionRecords.push(
|
||||
supplementSetting,
|
||||
{ id: 'report-a', kind: 'notification', examId: 'exam', schoolId: 'target-a', userId: null, status: 'approved', payload: { type: 'admission_reporting', round: 1, supplementDecision: 'supplement' } },
|
||||
{ id: 'report-b', kind: 'notification', examId: 'exam', schoolId: 'target-b', userId: null, status: 'approved', payload: { type: 'admission_reporting', round: 1, supplementDecision: 'supplement' } }
|
||||
);
|
||||
for (const placement of supplementDb.admissionRecords.filter(item => item.kind === 'placement' && item.payload?.categoryCode === 'general')) placement.status = 'forfeited';
|
||||
for (const [suffix, schoolId, score] of [['a', 'target-a', 230], ['b', 'target-b', 225]]) {
|
||||
supplementDb.users.push({ id: `u-supp-${suffix}`, role: 'candidate', active: true, candidateNumber: `2026010${suffix === 'a' ? 1 : 2}`, displayName: `补录考生${suffix.toUpperCase()}` });
|
||||
supplementDb.candidateProfiles.push({ userId: `u-supp-${suffix}`, name: `补录考生${suffix.toUpperCase()}`, schoolId: 'source-a', profileCompleted: true, specialtyTypes: [] });
|
||||
supplementDb.registrations.push({ id: `r-supp-${suffix}`, examId: 'exam', userId: `u-supp-${suffix}`, status: 'approved', subjectIds: ['cn'] });
|
||||
supplementDb.results.push({ registrationId: `r-supp-${suffix}`, subjectId: 'cn', score, published: true });
|
||||
supplementDb.admissionRecords.push({ id: `pref-supp-${suffix}`, kind: 'preference', examId: 'exam', userId: `u-supp-${suffix}`, status: 'submitted', payload: { round: 2, choices: [{ schoolId, categoryCode: 'general', preferenceType: 'general' }] } });
|
||||
}
|
||||
assert.deepEqual([...supplementarySchoolIds(supplementDb, supplementSetting)].sort(), ['target-a', 'target-b'], '同轮多所学校获批补录时应完整保留学校集合');
|
||||
const supplementPlacements = buildVolunteerPlacements(supplementDb, supplementSetting, { uid: prefix => `${prefix}-supp-${++sequence}`, nowIso: () => now });
|
||||
assert.deepEqual(supplementPlacements.map(item => item.schoolId).sort(), ['target-a', 'target-b'], '放弃考生不得继续占用缺额,两所获批学校都应进入补录投档');
|
||||
const publicRows = publicAdmissionRows(db, 'exam');
|
||||
const highPublicRow = publicRows.find(item => item.registrationNumber === '20260001');
|
||||
assert.equal(highPublicRow.registrationNumber, '20260001', '公示必须公开报名号');
|
||||
|
||||
+19
-1
@@ -645,6 +645,9 @@ try {
|
||||
|
||||
const placementCandidates = qualificationExam.qualificationStatus.rows.slice(0, 3);
|
||||
assert.equal(placementCandidates.length, 3, '批量投档测试至少需要三名候选考生');
|
||||
const reportedCandidate = createClient();
|
||||
const reportedCandidateLogin = await reportedCandidate.request('/api/auth/login', { method: 'POST', body: { username: placementCandidates[0].registrationNumber, password: '12345678' } });
|
||||
assert.equal(reportedCandidateLogin.response.status, 200, '报到补录边界测试应能登录正式录取考生账号');
|
||||
const placementIds = placementCandidates.map((row, index) => `placement_bulk_test_${index + 1}`);
|
||||
const placementCreatedAt = new Date().toISOString();
|
||||
const placementWriter = new DatabaseSync(testDb);
|
||||
@@ -712,7 +715,8 @@ try {
|
||||
assert.equal(scannedReporting.response.status, 200, '确认页点击暂存后应能保存扫码报到结果');
|
||||
assert.equal(scannedReporting.data.row.status, 'reported', '确认页默认选择应能暂存为已报到而不是直接提交');
|
||||
|
||||
const secondRow = reportingBatch.rows[1];
|
||||
const secondRow = reportingBatch.rows.find(row => row.noticeNumber !== finalizedPlacement.payload.noticeNumber);
|
||||
assert.ok(secondRow, '报到测试应找到另一名尚未处理的正式录取考生');
|
||||
const importReportingFile = Buffer.from(await buildWorkbook('admission_reporting', [{ noticeNumber: secondRow.noticeNumber, candidateNumber: secondRow.candidateNumber, name: secondRow.name, examCode: exam.code, schoolCode: admissionOnlySchool.data.school.code, categoryName: secondRow.categoryName, reportingStatusCode: 'N', reportingNote: '逾期未报到' }]));
|
||||
const importedReporting = await admissionSchoolClient.request(`/api/admission/reporting/import?examId=${exam.id}`, { method: 'POST', headers: { 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }, body: importReportingFile });
|
||||
assert.equal(importedReporting.response.status, 200, '招生学校应能导入修改后的报到 Excel 并暂存');
|
||||
@@ -731,6 +735,12 @@ try {
|
||||
const approvedReporting = await admin.request(`/api/admin/admission-reporting/${pendingReportingApproval.id}`, { method: 'PATCH', body: { approved: true, approvalNote: '同意按缺额补录', preferenceEnd: supplementEnd } });
|
||||
assert.equal(approvedReporting.response.status, 200, '超级管理员应能批准补录并自动公开报到情况');
|
||||
assert.equal(approvedReporting.data.phase, 'supplementary', '全部学校审批完成且存在补录申请时应自动开启下一轮补录');
|
||||
const reportedCandidateSupplementView = await reportedCandidate.request('/api/candidate/admissions');
|
||||
const reportedCandidateAdmission = reportedCandidateSupplementView.data.admissions.find(item => item.examId === exam.id);
|
||||
assert.equal(reportedCandidateAdmission.supplementEligible, false, '已经正式录取并报到的考生不得再次进入补录填报');
|
||||
assert.match(reportedCandidateAdmission.supplementIneligibilityReason, /已被录取/, '考生页面应明确说明不能重复参加补录的原因');
|
||||
const repeatedSupplementPreference = await reportedCandidate.request(`/api/candidate/admissions/${exam.id}/preferences`, { method: 'PUT', body: { choices: [{ schoolId: admissionOnlySchool.data.school.id, categoryCode: 'general', preferenceType: 'general' }] } });
|
||||
assert.equal(repeatedSupplementPreference.response.status, 403, '服务端必须拒绝已录取且已报到考生再次提交补录志愿');
|
||||
const reportingAnnouncements = await anonymous.request('/api/public/announcements');
|
||||
const reportingPublication = reportingAnnouncements.data.reports.find(item => item.id === pendingReportingApproval.id);
|
||||
assert.ok(reportingPublication?.title.includes('补录说明'), '批准补录后报到公示标题应自动包含补录说明');
|
||||
@@ -1106,6 +1116,14 @@ try {
|
||||
] } });
|
||||
assert.equal(firstPreference.response.status, 200, '有资格考生应能分别填报一个指标志愿和普通志愿');
|
||||
assert.equal(firstPreference.data.locked, true, '达到管理员设置的提交次数后应自动锁定');
|
||||
const lockedPreferenceView = await candidate.request('/api/candidate/admissions');
|
||||
const lockedChoice = lockedPreferenceView.data.admissions.find(item => item.examId === exam.id).preference.payload.choices[0];
|
||||
assert.equal(lockedChoice.schoolName, '海州市招生实验学校', '考生志愿锁定后应稳定返回学校名称,而不是只返回代码');
|
||||
assert.equal(lockedChoice.categoryName, '普通生', '考生志愿锁定后应稳定返回招生类别名称');
|
||||
const adminPreferenceView = await admin.request('/api/admin/admissions');
|
||||
const adminLockedChoice = adminPreferenceView.data.preferences.find(item => item.id === firstPreference.data.preference.id).choices[0];
|
||||
assert.equal(adminLockedChoice.schoolName, '海州市招生实验学校', '管理员志愿台账应显示完整学校名称');
|
||||
assert.equal(adminLockedChoice.categoryName, '普通生', '管理员志愿台账应显示招生类别名称而不是类别代码');
|
||||
assert.equal((await candidate.request(`/api/candidate/admissions/${exam.id}/preferences`, { method: 'PUT', body: { choices: [{ schoolId: structuredPlan.data.plan.schoolId, categoryCode: 'general', preferenceType: 'general' }] } })).response.status, 409, '超过填报次数后服务端必须拒绝继续修改');
|
||||
const classResults = await classAdmin.request(`/api/admin/results?examId=${encodeURIComponent(exam.id)}`);
|
||||
assert.ok(classResults.data.results.some(item => item.score === 126 && item.candidateName === '测试考生新名'), '班级管理员应可查看本班成绩');
|
||||
|
||||
Reference in New Issue
Block a user