已录取且报到的考生:补录入口隐藏,接口再次提交会返回 403。

多学校补录:按同一轮全部获批学校开放,并修复“放弃考生仍占用名额”的计算问题。
志愿锁定显示:保存学校和类别名称快照;旧数据中的 general 等代码也能还原名称。考生端、管理员台账同步修复。
录取结果通知:改为正式签发卡片,展示学校、类别、考试、通知书编号和录取状态,并适配移动端。
This commit is contained in:
2026-07-22 12:00:09 +08:00 Unverified
parent 7430c7bb89
commit c70a97231a
8 changed files with 140 additions and 20 deletions
+19 -1
View File
@@ -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 === '测试考生新名'), '班级管理员应可查看本班成绩');