Files
NextEdu/src/modules/exams/data-access-error-collection.ts
SpecialX f0f713ff33 feat(exams,homework): add error collection data-access for error book integration
- 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
2026-06-24 12:03:03 +08:00

95 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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,
}
}