实现考试归档并永久锁定成绩流程

This commit is contained in:
2026-07-20 17:08:17 +08:00 Unverified
parent 6d22b41ce8
commit 1a87e06fc8
15 changed files with 265 additions and 39 deletions
+17 -7
View File
@@ -57,7 +57,7 @@ function buildSeedOperations(state) {
const nullable = value => value == null || value === '' ? null : value;
add(
'UPDATE schema_metadata SET schema_version = 13, app_version = ?, self_registration_enabled = ?, created_at = ? WHERE id = 1',
'UPDATE schema_metadata SET schema_version = 14, app_version = ?, self_registration_enabled = ?, created_at = ? WHERE id = 1',
Number(state.meta?.version || 1), state.settings?.selfRegistrationEnabled ? 1 : 0,
state.meta?.createdAt || new Date().toISOString()
);
@@ -126,11 +126,12 @@ function buildSeedOperations(state) {
add(
`INSERT INTO exams (
id, code, name, description, registration_start, registration_end, exam_start, exam_end,
admit_download_start, admit_download_end, location, pass_policy, pass_value, status, created_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
admit_download_start, admit_download_end, location, pass_policy, pass_value, status, archived_at, archived_by, created_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
exam.id, exam.code, exam.name, exam.description || '', exam.registrationStart, exam.registrationEnd,
exam.examStart, exam.examEnd, exam.admitDownloadStart, exam.admitDownloadEnd, exam.location || '',
exam.passPolicy === 'score_ratio' ? 'rank_percent' : (exam.passPolicy || 'rank_percent'), Number(exam.passValue ?? 60), exam.status, exam.createdAt
exam.passPolicy === 'score_ratio' ? 'rank_percent' : (exam.passPolicy || 'rank_percent'), Number(exam.passValue ?? 60), exam.status,
nullable(exam.archivedAt), nullable(exam.archivedBy), exam.createdAt
);
exam.subjects.forEach((subject, index) => add(
`INSERT INTO exam_subjects (
@@ -533,6 +534,8 @@ function stateFromRows(rows) {
passPolicy: row.pass_policy === 'score_ratio' ? 'rank_percent' : (row.pass_policy || 'rank_percent'),
passValue: Number(row.pass_value ?? 60),
status: row.status,
archivedAt: row.archived_at || null,
archivedBy: row.archived_by || null,
createdAt: row.created_at,
subjects: subjectsByExam.get(row.id) || []
})),
@@ -1314,11 +1317,11 @@ function createRepository({ client, location, read, transaction, close }) {
const operations = [operation(
`INSERT INTO exams (
id, code, name, description, registration_start, registration_end, exam_start, exam_end,
admit_download_start, admit_download_end, location, pass_policy, pass_value, status, created_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
admit_download_start, admit_download_end, location, pass_policy, pass_value, status, archived_at, archived_by, created_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
exam.id, exam.code, exam.name, exam.description || '', exam.registrationStart, exam.registrationEnd,
exam.examStart, exam.examEnd, exam.admitDownloadStart, exam.admitDownloadEnd,
exam.location || '', exam.passPolicy, exam.passValue, exam.status, exam.createdAt
exam.location || '', exam.passPolicy, exam.passValue, exam.status, optional(exam.archivedAt), optional(exam.archivedBy), exam.createdAt
)];
exam.subjects.forEach((subject, index) => operations.push(operation(
`INSERT INTO exam_subjects (
@@ -1357,6 +1360,13 @@ function createRepository({ client, location, read, transaction, close }) {
operations.push(auditOperation(log));
await transaction(operations);
},
async archiveExam(exam, log) {
await transaction([
operation('UPDATE exams SET status = ?, archived_at = ?, archived_by = ? WHERE id = ? AND archived_at IS NULL',
exam.status, exam.archivedAt, exam.archivedBy, exam.id),
auditOperation(log)
]);
},
async createNotice(notice, log) {
await transaction([
operation(