性能
This commit is contained in:
+58
-3
@@ -247,10 +247,62 @@ function publicExam(exam) {
|
||||
const end = new Date(exam.registrationEnd).getTime();
|
||||
return {
|
||||
...exam,
|
||||
totalScore: exam.subjects.reduce((sum, subject) => sum + Number(subject.fullScore || 0), 0),
|
||||
registrationState: now < start ? 'upcoming' : now > end ? 'closed' : 'open'
|
||||
};
|
||||
}
|
||||
|
||||
function examResultSummary(db, registration) {
|
||||
const exam = db.exams.find(item => item.id === registration.examId);
|
||||
if (!exam) return null;
|
||||
const subjects = exam.subjects.filter(subject => registration.subjectIds.includes(subject.id));
|
||||
const published = db.results.filter(result => result.registrationId === registration.id && result.published);
|
||||
const resultsBySubject = new Map(published.map(result => [result.subjectId, result]));
|
||||
const complete = subjects.length > 0 && subjects.every(subject => resultsBySubject.has(subject.id));
|
||||
const total = subjects.reduce((sum, subject) => sum + Number(resultsBySubject.get(subject.id)?.score || 0), 0);
|
||||
const fullScore = subjects.reduce((sum, subject) => sum + Number(subject.fullScore || 0), 0);
|
||||
const scoreRatio = fullScore ? total / fullScore * 100 : 0;
|
||||
const policy = exam.passPolicy || 'score_ratio';
|
||||
const value = Number(exam.passValue ?? 60);
|
||||
let qualified = null;
|
||||
let rank = null;
|
||||
let cohortSize = null;
|
||||
|
||||
if (complete && policy === 'fixed_score') qualified = total >= value;
|
||||
if (complete && policy === 'score_ratio') qualified = scoreRatio >= value;
|
||||
if (complete && policy === 'subject_scores') qualified = subjects.every(subject => Number(resultsBySubject.get(subject.id).score) >= Number(subject.passScore));
|
||||
if (complete && policy === 'none') qualified = null;
|
||||
if (complete && policy === 'rank_percent') {
|
||||
const subjectKey = [...registration.subjectIds].sort().join('|');
|
||||
const totals = db.registrations
|
||||
.filter(item => item.examId === exam.id && item.status === 'approved' && [...item.subjectIds].sort().join('|') === subjectKey)
|
||||
.map(item => {
|
||||
const itemResults = db.results.filter(result => result.registrationId === item.id && result.published);
|
||||
if (!item.subjectIds.every(id => itemResults.some(result => result.subjectId === id))) return null;
|
||||
return itemResults.filter(result => item.subjectIds.includes(result.subjectId)).reduce((sum, result) => sum + Number(result.score), 0);
|
||||
})
|
||||
.filter(item => item != null);
|
||||
cohortSize = totals.length;
|
||||
rank = 1 + totals.filter(item => item > total).length;
|
||||
qualified = rank <= Math.max(1, Math.ceil(cohortSize * value / 100));
|
||||
}
|
||||
|
||||
return {
|
||||
examId: exam.id,
|
||||
complete,
|
||||
publishedSubjects: published.length,
|
||||
subjectCount: subjects.length,
|
||||
total,
|
||||
fullScore,
|
||||
scoreRatio: Number(scoreRatio.toFixed(2)),
|
||||
passPolicy: policy,
|
||||
passValue: value,
|
||||
qualified,
|
||||
rank,
|
||||
cohortSize
|
||||
};
|
||||
}
|
||||
|
||||
function examRegistrationView(db, registration) {
|
||||
const exam = db.exams.find(item => item.id === registration.examId);
|
||||
const subjects = (exam?.subjects || []).filter(subject => registration.subjectIds.includes(subject.id));
|
||||
@@ -313,7 +365,8 @@ function excelRowsForResource(db, user, resource, searchParams) {
|
||||
return db.results.filter(result => scopedRegistrations.some(item => item.id === result.registrationId)).map(result => {
|
||||
const registration = db.registrations.find(item => item.id === result.registrationId);
|
||||
const exam = db.exams.find(item => item.id === registration?.examId);
|
||||
return { candidateNumber: db.users.find(item => item.id === registration?.userId)?.candidateNumber || '', examCode: exam?.code || '', subjectName: exam?.subjects.find(item => item.id === result.subjectId)?.name || '', score: result.score, grade: result.grade, published: result.published ? '发布' : '不发布' };
|
||||
const subject = exam?.subjects.find(item => item.id === result.subjectId);
|
||||
return { candidateNumber: db.users.find(item => item.id === registration?.userId)?.candidateNumber || '', examCode: exam?.code || '', subjectName: subject?.name || '', fullScore: subject?.fullScore || '', passScore: subject?.passScore || '', score: result.score, grade: result.grade, published: result.published ? '发布' : '不发布' };
|
||||
});
|
||||
}
|
||||
return [];
|
||||
@@ -427,11 +480,12 @@ async function importExcelResource(db, user, resource, rows) {
|
||||
const registration = db.registrations.find(item => item.userId === account?.id && item.examId === exam?.id && item.status === 'approved');
|
||||
const subject = exam?.subjects.find(item => item.name === cleanText(row.subjectName, 50));
|
||||
const score = Number(row.score);
|
||||
if (!registration || !subject || !registration.subjectIds.includes(subject.id) || !Number.isFinite(score) || score < 0 || score > 150) throw excelImportError(row, '报名号、考试、科目或成绩无效');
|
||||
if (!registration || !subject || !registration.subjectIds.includes(subject.id) || !Number.isFinite(score) || score < 0 || score > subject.fullScore) throw excelImportError(row, `报名号、考试、科目无效,或成绩不在 0—${subject?.fullScore || 0} 之间`);
|
||||
let result = db.results.find(item => item.registrationId === registration.id && item.subjectId === subject.id);
|
||||
const isNew = !result;
|
||||
if (!result) result = { id: uid('result'), registrationId: registration.id, subjectId: subject.id };
|
||||
Object.assign(result, { score, grade: cleanText(row.grade, 10) || (score >= 120 ? 'A' : score >= 90 ? 'B' : score >= 60 ? 'C' : 'D'), published: row.published === '发布', updatedAt: nowIso(), publishedAt: row.published === '发布' ? nowIso() : null });
|
||||
const ratio = score / subject.fullScore;
|
||||
Object.assign(result, { score, grade: cleanText(row.grade, 10) || (ratio >= .9 ? 'A+' : ratio >= .8 ? 'A' : ratio >= .7 ? 'B+' : ratio >= .6 ? 'B' : ratio >= .4 ? 'C' : 'D'), published: row.published === '发布', updatedAt: nowIso(), publishedAt: row.published === '发布' ? nowIso() : null });
|
||||
await database.saveResult(result, isNew, logAction(db, user, 'Excel 导入成绩', `${row.candidateNumber} · ${exam.name} · ${subject.name}`));
|
||||
if (isNew) db.results.push(result);
|
||||
}
|
||||
@@ -484,6 +538,7 @@ const routeContext = {
|
||||
maskId,
|
||||
publicExam,
|
||||
examRegistrationView,
|
||||
examResultSummary,
|
||||
logAction,
|
||||
excelResourceNames,
|
||||
excelRowsForResource,
|
||||
|
||||
Reference in New Issue
Block a user