feat: 更新考试相关页面,添加刷新功能,修改考试状态显示
- 注:当前代码还存在bug:查看结果暂出现错误。 - 在 SubjectSelectionPage 页面中添加刷新按钮,允许用户手动刷新考试任务列表。 - 修改 UserTaskPage 页面,重构考试任务为答题记录,更新数据结构和状态显示。 - 在 AdminDashboardPage、UserManagePage、UserRecordsPage 等管理页面中添加考试状态显示,使用不同颜色区分状态(不及格、合格、优秀)。 - 在 ResultPage 中显示考试状态,确保用户能够清晰了解考试结果。 - 添加约束,确保单次考试试卷中题目不可重复出现,并记录相关规范。 - 添加评分状态约束,根据得分占比自动计算考试状态,并在结果页面显示。
This commit is contained in:
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,7 +8,13 @@ export interface QuizRecord {
|
||||
totalScore: number;
|
||||
correctCount: number;
|
||||
totalCount: number;
|
||||
scorePercentage: number;
|
||||
status: '不及格' | '合格' | '优秀';
|
||||
createdAt: string;
|
||||
subjectId?: string;
|
||||
subjectName?: string;
|
||||
taskId?: string;
|
||||
taskName?: string;
|
||||
}
|
||||
|
||||
export interface QuizAnswer {
|
||||
@@ -39,15 +45,25 @@ export interface SubmitQuizData {
|
||||
}
|
||||
|
||||
export class QuizModel {
|
||||
// 计算考试状态
|
||||
private static calculateStatus(scorePercentage: number): '不及格' | '合格' | '优秀' {
|
||||
if (scorePercentage < 60) return '不及格';
|
||||
if (scorePercentage < 80) return '合格';
|
||||
return '优秀';
|
||||
}
|
||||
|
||||
// 创建答题记录
|
||||
static async createRecord(data: { userId: string; totalScore: number; correctCount: number; totalCount: number }): Promise<QuizRecord> {
|
||||
const id = uuidv4();
|
||||
const scorePercentage = data.totalCount > 0 ? (data.totalScore / data.totalCount) * 100 : 0;
|
||||
const status = this.calculateStatus(scorePercentage);
|
||||
|
||||
const sql = `
|
||||
INSERT INTO quiz_records (id, user_id, total_score, correct_count, total_count)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
INSERT INTO quiz_records (id, user_id, total_score, correct_count, total_count, score_percentage, status)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
`;
|
||||
|
||||
await run(sql, [id, data.userId, data.totalScore, data.correctCount, data.totalCount]);
|
||||
await run(sql, [id, data.userId, data.totalScore, data.correctCount, data.totalCount, scorePercentage, status]);
|
||||
return this.findRecordById(id) as Promise<QuizRecord>;
|
||||
}
|
||||
|
||||
@@ -114,7 +130,7 @@ export class QuizModel {
|
||||
|
||||
// 根据ID查找答题记录
|
||||
static async findRecordById(id: string): Promise<QuizRecord | null> {
|
||||
const sql = `SELECT id, user_id as userId, total_score as totalScore, correct_count as correctCount, total_count as totalCount, created_at as createdAt FROM quiz_records WHERE id = ?`;
|
||||
const sql = `SELECT id, user_id as userId, total_score as totalScore, correct_count as correctCount, total_count as totalCount, score_percentage as scorePercentage, status, created_at as createdAt FROM quiz_records WHERE id = ?`;
|
||||
const record = await get(sql, [id]);
|
||||
return record || null;
|
||||
}
|
||||
@@ -122,10 +138,15 @@ export class QuizModel {
|
||||
// 获取用户的答题记录
|
||||
static async findRecordsByUserId(userId: string, limit = 10, offset = 0): Promise<{ records: QuizRecord[]; total: number }> {
|
||||
const recordsSql = `
|
||||
SELECT id, user_id as userId, total_score as totalScore, correct_count as correctCount, total_count as totalCount, created_at as createdAt
|
||||
FROM quiz_records
|
||||
WHERE user_id = ?
|
||||
ORDER BY created_at DESC
|
||||
SELECT r.id, r.user_id as userId, r.total_score as totalScore, r.correct_count as correctCount, r.total_count as totalCount,
|
||||
r.score_percentage as scorePercentage, r.status, r.created_at as createdAt,
|
||||
r.subject_id as subjectId, s.name as subjectName,
|
||||
r.task_id as taskId, t.name as taskName
|
||||
FROM quiz_records r
|
||||
LEFT JOIN exam_subjects s ON r.subject_id = s.id
|
||||
LEFT JOIN exam_tasks t ON r.task_id = t.id
|
||||
WHERE r.user_id = ?
|
||||
ORDER BY r.created_at DESC
|
||||
LIMIT ? OFFSET ?
|
||||
`;
|
||||
|
||||
@@ -147,6 +168,7 @@ export class QuizModel {
|
||||
const recordsSql = `
|
||||
SELECT r.id, r.user_id as userId, u.name as userName, u.phone as userPhone,
|
||||
r.total_score as totalScore, r.correct_count as correctCount, r.total_count as totalCount,
|
||||
r.score_percentage as scorePercentage, r.status,
|
||||
r.created_at as createdAt, r.subject_id as subjectId, s.name as subjectName,
|
||||
r.task_id as taskId
|
||||
FROM quiz_records r
|
||||
|
||||
Reference in New Issue
Block a user