This commit is contained in:
2026-07-21 16:43:57 +08:00 Unverified
parent 722bb6f016
commit 48bef02904
7 changed files with 168 additions and 5 deletions
+21 -1
View File
@@ -62,7 +62,7 @@ export function createAdmissionRoutes(context) {
return { subjectName: exam?.subjects.find(subject => subject.id === result.subjectId)?.name || result.subjectId, score: result.score };
});
const qualification = resolveProfileSpecialty(profile);
return { ...item, candidate: { registrationNumber: account.candidateNumber, name: profile.name, gender: profile.gender, idNumberMasked: maskId(profile.idNumber), specialtyCategory: qualification.category, specialtyType: qualification.type, specialtyLabel: specialtyLabel(qualification.category, qualification.type), specialtyCertificate: profile.specialtyCertificate || '', policyEligibility: profile.policyEligibility || '' }, featureScore: Number(registration?.featureScore || 0), results };
return { ...item, examName: db.exams.find(exam => exam.id === item.examId)?.name || item.examId, candidate: { registrationNumber: account.candidateNumber, name: profile.name, gender: profile.gender, idNumberMasked: maskId(profile.idNumber), specialtyCategory: qualification.category, specialtyType: qualification.type, specialtyLabel: specialtyLabel(qualification.category, qualification.type), specialtyCertificate: profile.specialtyCertificate || '', policyEligibility: profile.policyEligibility || '' }, featureScore: Number(registration?.featureScore || 0), results };
});
const completedExams = db.exams.filter(exam => admissionRecords(db, 'setting', exam.id).some(setting => setting.status === 'completed') && placements.some(item => item.examId === exam.id && item.status === 'final'));
return sendJson(response, 200, { ok: true, school, placements, completedExams });
@@ -93,6 +93,26 @@ export function createAdmissionRoutes(context) {
const buffer = Buffer.from(await buildWorkbook('admitted_candidates', rows, { subtitle: `${exam.name}${school.name}` }));
return sendWorkbook(response, buffer, `${exam.name}-${school.name}-录取考生信息.xlsx`);
}
if (request.method === 'POST' && pathname === '/api/admission/placements/bulk') {
const body = await readJson(request);
const ids = [...new Set((Array.isArray(body.ids) ? body.ids : []).map(id => cleanText(id, 64)).filter(Boolean))];
const decision = cleanText(body.decision, 30);
const note = cleanText(body.note, 500);
if (!ids.length) return sendError(response, 400, '请至少选择一名待审核考生');
if (!['accept', 'withdraw'].includes(decision)) return sendError(response, 400, '请选择接收或申请退档');
if (decision === 'withdraw' && note.length < 8) return sendError(response, 400, '批量申请退档必须填写至少 8 个字的特殊理由');
const placements = admissionRecords(db, 'placement').filter(item => ids.includes(item.id) && item.schoolId === school.id && item.status === 'school_review');
if (placements.length !== ids.length) return sendError(response, 409, '所选记录中包含已处理或不属于本校的投档记录,请刷新后重试');
const now = nowIso();
for (const placement of placements) {
placement.status = decision === 'accept' ? 'admitted' : 'withdrawal_pending';
placement.payload.schoolDecisionNote = note;
if (decision === 'withdraw') placement.payload.withdrawalReason = note;
placement.updatedAt = now;
}
await database.saveAdmissionRecords(placements, logAction(db, user, decision === 'accept' ? '批量接收投档考生' : '批量申请退档', `${school.name} · ${placements.length}`));
return sendJson(response, 200, { ok: true, count: placements.length, decision });
}
const placementMatch = pathname.match(/^\/api\/admission\/placements\/([^/]+)$/);
if (request.method === 'PATCH' && placementMatch) {
const placement = admissionRecords(db, 'placement').find(item => item.id === placementMatch[1] && item.schoolId === school.id);