feat: 更新考试相关页面,添加刷新功能,修改考试状态显示

- 注:当前代码还存在bug:查看结果暂出现错误。
- 在 SubjectSelectionPage 页面中添加刷新按钮,允许用户手动刷新考试任务列表。
- 修改 UserTaskPage 页面,重构考试任务为答题记录,更新数据结构和状态显示。
- 在 AdminDashboardPage、UserManagePage、UserRecordsPage 等管理页面中添加考试状态显示,使用不同颜色区分状态(不及格、合格、优秀)。
- 在 ResultPage 中显示考试状态,确保用户能够清晰了解考试结果。
- 添加约束,确保单次考试试卷中题目不可重复出现,并记录相关规范。
- 添加评分状态约束,根据得分占比自动计算考试状态,并在结果页面显示。
This commit is contained in:
2025-12-29 20:28:33 +08:00
parent 03eb858749
commit 57101fac37
26 changed files with 480 additions and 216 deletions

View File

@@ -96,11 +96,10 @@ export class ExamSubjectModel {
const targetTypeScore = Math.round((typeRatio / 100) * subject.totalScore);
let currentTypeScore = 0;
let typeQuestions: Awaited<ReturnType<typeof QuestionModel.getRandomQuestions>> = [];
while (currentTypeScore < targetTypeScore) {
const randomCategory = weightedCategories[Math.floor(Math.random() * weightedCategories.length)];
const availableQuestions = await QuestionModel.getRandomQuestions(type as any, 10, [randomCategory]);
const availableQuestions = await QuestionModel.getRandomQuestions(type as any, 100, [randomCategory]);
if (availableQuestions.length === 0) break;
@@ -114,13 +113,11 @@ export class ExamSubjectModel {
return currDiff < prevDiff ? curr : prev;
});
typeQuestions.push(selectedQuestion);
questions.push(selectedQuestion);
currentTypeScore += selectedQuestion.score;
if (typeQuestions.length > 100) break;
if (questions.length > 200) break;
}
questions.push(...typeQuestions);
}
let totalScore = questions.reduce((sum, q) => sum + q.score, 0);
while (totalScore < subject.totalScore) {
@@ -128,7 +125,7 @@ export class ExamSubjectModel {
if (allTypes.length === 0) break;
const randomType = allTypes[Math.floor(Math.random() * allTypes.length)];
const availableQuestions = await QuestionModel.getRandomQuestions(randomType as any, 10, categories);
const availableQuestions = await QuestionModel.getRandomQuestions(randomType as any, 100, categories);
if (availableQuestions.length === 0) break;
const availableUnselected = availableQuestions.filter((q) => !questions.some((selected) => selected.id === q.id));
@@ -165,9 +162,13 @@ export class ExamSubjectModel {
questions.splice(closestIndex, 1);
}
const uniqueQuestions = questions.filter((q, index, self) =>
index === self.findIndex((t) => t.id === q.id)
);
return {
questions,
totalScore,
questions: uniqueQuestions,
totalScore: uniqueQuestions.reduce((sum, q) => sum + q.score, 0),
timeLimitMinutes: subject.timeLimitMinutes,
};
}
@@ -213,7 +214,7 @@ export class ExamSubjectModel {
tried.add(category);
const desiredAvg = remainingSlots > 0 ? (subject.totalScore - currentTotal) / remainingSlots : 0;
const fetched = await QuestionModel.getRandomQuestions(type as any, 30, [category]);
const fetched = await QuestionModel.getRandomQuestions(type as any, 100, [category]);
const candidates = fetched.filter((q) => !questions.some((selectedQ) => selectedQ.id === q.id));
if (candidates.length === 0) continue;
@@ -227,7 +228,7 @@ export class ExamSubjectModel {
}
if (!selected || !selectedCategory) {
throw new Error('题库中缺少满足当前配置的题目');
continue;
}
questions.push(selected);
@@ -245,8 +246,8 @@ export class ExamSubjectModel {
const idx = Math.floor(Math.random() * questions.length);
const base = questions[idx];
const fetched = await QuestionModel.getRandomQuestions(base.type as any, 30, [base.category]);
const candidates = fetched.filter((q) => !questions.some((selectedQ) => selectedQ.id === q.id));
const fetched = await QuestionModel.getRandomQuestions(base.type as any, 100, [base.category]);
const candidates = fetched.filter((q) => !questions.some((selectedQ) => selectedQ.id === q.id) && q.id !== base.id);
if (candidates.length === 0) continue;
const currentBest = Math.abs(diff);
@@ -267,9 +268,13 @@ export class ExamSubjectModel {
totalScore = totalScore - base.score + best.score;
}
const uniqueQuestions = questions.filter((q, index, self) =>
index === self.findIndex((t) => t.id === q.id)
);
return {
questions,
totalScore,
questions: uniqueQuestions,
totalScore: uniqueQuestions.reduce((sum, q) => sum + q.score, 0),
timeLimitMinutes: subject.timeLimitMinutes,
};
}