- Add data-access-error-collection in exams module for collecting wrong exam answers - Add data-access-error-collection in homework module for collecting wrong homework answers - Update exams actions, exam-ai-generator, data-access, and types - Update homework actions and data-access-write
95 lines
2.7 KiB
TypeScript
95 lines
2.7 KiB
TypeScript
import "server-only"
|
||
|
||
import { and, eq } from "drizzle-orm"
|
||
|
||
import { db } from "@/shared/db"
|
||
import { examQuestions, examSubmissions, exams, submissionAnswers } from "@/shared/db/schema"
|
||
|
||
/**
|
||
* 错题采集所需的答案数据(单题)
|
||
*/
|
||
export type AnswerForErrorCollection = {
|
||
questionId: string
|
||
answerContent: unknown
|
||
score: number | null
|
||
feedback: string | null
|
||
maxScore: number
|
||
}
|
||
|
||
/**
|
||
* 考试提交的错题采集数据
|
||
*/
|
||
export type ExamSubmissionDataForErrorCollection = {
|
||
examId: string
|
||
subjectId: string | null
|
||
answers: AnswerForErrorCollection[]
|
||
}
|
||
|
||
/**
|
||
* 跨模块接口:获取考试提交的错题采集数据。
|
||
*
|
||
* 供 error-book 模块调用,避免 error-book 直接查询 examSubmissions、
|
||
* submissionAnswers、examQuestions、exams 等属于 exams 模块的表。
|
||
*
|
||
* 返回该提交的所有答案(含得分、反馈、满分),由 error-book 模块
|
||
* 自行筛选错题(score < maxScore)并采集。
|
||
*
|
||
* @param submissionId 考试提交 ID
|
||
* @param studentId 学生 ID(用于校验提交归属)
|
||
* @returns 提交数据;若提交不存在或 studentId 不匹配则返回 null
|
||
*/
|
||
export async function getExamSubmissionDataForErrorCollection(
|
||
submissionId: string,
|
||
studentId: string,
|
||
): Promise<ExamSubmissionDataForErrorCollection | null> {
|
||
const submission = await db.query.examSubmissions.findFirst({
|
||
where: and(
|
||
eq(examSubmissions.id, submissionId),
|
||
eq(examSubmissions.studentId, studentId),
|
||
),
|
||
columns: { id: true, examId: true },
|
||
})
|
||
|
||
if (!submission) return null
|
||
|
||
// 并行获取考试学科、提交答案、题目满分
|
||
const [exam, answers, examQuestionScores] = await Promise.all([
|
||
db.query.exams.findFirst({
|
||
where: eq(exams.id, submission.examId),
|
||
columns: { subjectId: true },
|
||
}),
|
||
db
|
||
.select({
|
||
questionId: submissionAnswers.questionId,
|
||
answerContent: submissionAnswers.answerContent,
|
||
score: submissionAnswers.score,
|
||
feedback: submissionAnswers.feedback,
|
||
})
|
||
.from(submissionAnswers)
|
||
.where(eq(submissionAnswers.submissionId, submissionId)),
|
||
db
|
||
.select({
|
||
questionId: examQuestions.questionId,
|
||
maxScore: examQuestions.score,
|
||
})
|
||
.from(examQuestions)
|
||
.where(eq(examQuestions.examId, submission.examId)),
|
||
])
|
||
|
||
const maxScoreMap = new Map(examQuestionScores.map((q) => [q.questionId, q.maxScore ?? 0]))
|
||
|
||
const mappedAnswers: AnswerForErrorCollection[] = answers.map((a) => ({
|
||
questionId: a.questionId,
|
||
answerContent: a.answerContent,
|
||
score: a.score,
|
||
feedback: a.feedback,
|
||
maxScore: maxScoreMap.get(a.questionId) ?? 0,
|
||
}))
|
||
|
||
return {
|
||
examId: submission.examId,
|
||
subjectId: exam?.subjectId ?? null,
|
||
answers: mappedAnswers,
|
||
}
|
||
}
|