用户端页面构建完成---待测试

This commit is contained in:
2025-12-25 21:54:52 +08:00
parent de0c7377c9
commit 7b52abfea3
13 changed files with 539 additions and 113 deletions

View File

@@ -190,9 +190,21 @@ export class QuizController {
}
});
} catch (error: any) {
res.status(500).json({
const message = error?.message || '生成试卷失败';
const status = message.includes('不存在')
? 404
: [
'用户ID不能为空',
'subjectId或taskId必须提供其一',
'当前时间不在任务有效范围内',
'用户未被分派到此任务',
'考试次数已用尽',
].some((m) => message.includes(m))
? 400
: 500;
res.status(status).json({
success: false,
message: error.message || '生成试卷失败'
message,
});
}
}
@@ -390,4 +402,4 @@ export class QuizController {
});
}
}
}
}

View File

@@ -11,6 +11,15 @@ export interface ExamTask {
selectionConfig?: string; // JSON string
}
export interface UserExamTask extends ExamTask {
subjectName: string;
totalScore: number;
timeLimitMinutes: number;
usedAttempts: number;
maxAttempts: number;
bestScore: number;
}
export interface ExamTaskUser {
id: string;
taskId: string;
@@ -558,6 +567,13 @@ export class ExamTaskModel {
);
if (!isAssigned) throw new Error('用户未被分派到此任务');
const attemptRow = await get(
`SELECT COUNT(*) as count FROM quiz_records WHERE user_id = ? AND task_id = ?`,
[userId, taskId],
);
const usedAttempts = Number(attemptRow?.count) || 0;
if (usedAttempts >= 3) throw new Error('考试次数已用尽');
const subject = await import('./examSubject').then(({ ExamSubjectModel }) => ExamSubjectModel.findById(task.subjectId));
if (!subject) throw new Error('科目不存在');
@@ -705,27 +721,48 @@ export class ExamTaskModel {
};
}
static async getUserTasks(userId: string): Promise<ExamTask[]> {
static async getUserTasks(userId: string): Promise<UserExamTask[]> {
const now = new Date().toISOString();
const rows = await all(`
SELECT t.*, s.name as subjectName, s.totalScore, s.timeLimitMinutes
SELECT
t.id,
t.name,
t.subject_id as subjectId,
t.start_at as startAt,
t.end_at as endAt,
t.created_at as createdAt,
s.name as subjectName,
s.total_score as totalScore,
s.duration_minutes as timeLimitMinutes,
COALESCE(q.usedAttempts, 0) as usedAttempts,
3 as maxAttempts,
COALESCE(q.bestScore, 0) as bestScore
FROM exam_tasks t
INNER JOIN exam_task_users tu ON t.id = tu.task_id
INNER JOIN exam_subjects s ON t.subject_id = s.id
WHERE tu.user_id = ? AND t.start_at <= ?
ORDER BY t.start_at DESC
`, [userId, now]);
LEFT JOIN (
SELECT task_id, COUNT(*) as usedAttempts, MAX(total_score) as bestScore
FROM quiz_records
WHERE user_id = ?
GROUP BY task_id
) q ON q.task_id = t.id
WHERE tu.user_id = ? AND t.start_at <= ? AND t.end_at >= ?
ORDER BY t.start_at ASC, t.end_at ASC
`, [userId, userId, now, now]);
return rows.map(row => ({
id: row.id,
name: row.name,
subjectId: row.subject_id,
startAt: row.start_at,
endAt: row.end_at,
createdAt: row.created_at,
subjectId: row.subjectId,
startAt: row.startAt,
endAt: row.endAt,
createdAt: row.createdAt,
subjectName: row.subjectName,
totalScore: row.totalScore,
timeLimitMinutes: row.timeLimitMinutes
totalScore: Number(row.totalScore) || 0,
timeLimitMinutes: Number(row.timeLimitMinutes) || 0,
usedAttempts: Number(row.usedAttempts) || 0,
maxAttempts: Number(row.maxAttempts) || 3,
bestScore: Number(row.bestScore) || 0,
}));
}
}