refactor(modules): update classes, course-plans, diagnostic, questions, settings, student, layout
- Update classes data-access (invitations, main) for invitation management - Update course-plans actions, data-access, and types - Update diagnostic data-access for report queries - Update questions data-access for question bank queries - Update settings actions, ai-provider-settings-card, data-access, and types - Update student course-filters, student-courses-view, student-schedule-filters, student-schedule-view - Update layout app-sidebar, site-header, and navigation config
This commit is contained in:
@@ -8,6 +8,7 @@ import { knowledgePointMastery, knowledgePoints } from "@/shared/db/schema"
|
||||
|
||||
import { getClassNameById, getActiveStudentIdsByClassId, getClassExists } from "@/modules/classes/data-access"
|
||||
import { getExamSubmissionWithAnswers, getExamWithQuestionsForHomework } from "@/modules/exams/data-access"
|
||||
import { getHomeworkSubmissionWithAnswersForMastery } from "@/modules/homework/data-access-error-collection"
|
||||
import { getKnowledgePointsForQuestions } from "@/modules/questions/data-access"
|
||||
import { getUserIdsByGradeId, getUserNamesByIds } from "@/modules/users/data-access"
|
||||
|
||||
@@ -141,6 +142,91 @@ export async function updateMasteryFromSubmission(submissionId: string): Promise
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 从作业提交更新掌握度(累积模式)。
|
||||
*
|
||||
* 与 updateMasteryFromSubmission 类似,但数据来源是作业提交而非考试提交。
|
||||
* 通过 homework 模块的跨模块接口获取作业提交的答案数据,避免直查 homeworkSubmissions 表。
|
||||
*
|
||||
* @param submissionId 作业提交 ID
|
||||
*/
|
||||
export async function updateMasteryFromHomeworkSubmission(submissionId: string): Promise<void> {
|
||||
const submission = await getHomeworkSubmissionWithAnswersForMastery(submissionId)
|
||||
if (!submission) return
|
||||
|
||||
const answers = submission.answers
|
||||
if (answers.length === 0) return
|
||||
|
||||
const questionIds = Array.from(new Set(answers.map((a) => a.questionId)))
|
||||
const kpMap = await getKnowledgePointsForQuestions(questionIds)
|
||||
|
||||
// Build a Map for O(1) answer lookup instead of find() in loop
|
||||
const answerByQuestionId = new Map(answers.map((a) => [a.questionId, a]))
|
||||
|
||||
const kpStats = new Map<string, { total: number; correct: number }>()
|
||||
for (const [questionId, kpLinks] of kpMap.entries()) {
|
||||
const answer = answerByQuestionId.get(questionId)
|
||||
if (!answer) continue
|
||||
for (const link of kpLinks) {
|
||||
const stat = kpStats.get(link.knowledgePointId) ?? { total: 0, correct: 0 }
|
||||
stat.total += 1
|
||||
if ((answer.score ?? 0) > 0) stat.correct += 1
|
||||
kpStats.set(link.knowledgePointId, stat)
|
||||
}
|
||||
}
|
||||
|
||||
// 读取已有掌握度记录,累积计算(而非覆盖)
|
||||
const existingRows = await db
|
||||
.select()
|
||||
.from(knowledgePointMastery)
|
||||
.where(
|
||||
and(
|
||||
eq(knowledgePointMastery.studentId, submission.studentId),
|
||||
inArray(knowledgePointMastery.knowledgePointId, Array.from(kpStats.keys())),
|
||||
),
|
||||
)
|
||||
|
||||
const existingByKp = new Map<string, { total: number; correct: number }>()
|
||||
for (const row of existingRows) {
|
||||
existingByKp.set(row.knowledgePointId, {
|
||||
total: row.totalQuestions,
|
||||
correct: row.correctQuestions,
|
||||
})
|
||||
}
|
||||
|
||||
const now = new Date()
|
||||
// 使用事务保证多个 upsert 的原子性
|
||||
await db.transaction(async (tx) => {
|
||||
await Promise.all(
|
||||
Array.from(kpStats.entries()).map(async ([kpId, stat]) => {
|
||||
const existing = existingByKp.get(kpId)
|
||||
const totalQuestions = (existing?.total ?? 0) + stat.total
|
||||
const correctQuestions = (existing?.correct ?? 0) + stat.correct
|
||||
const masteryLevel = computeMasteryLevel(correctQuestions, totalQuestions)
|
||||
await tx
|
||||
.insert(knowledgePointMastery)
|
||||
.values({
|
||||
studentId: submission.studentId,
|
||||
knowledgePointId: kpId,
|
||||
masteryLevel: String(masteryLevel),
|
||||
totalQuestions,
|
||||
correctQuestions,
|
||||
lastAssessedAt: now,
|
||||
})
|
||||
.onDuplicateKeyUpdate({
|
||||
set: {
|
||||
masteryLevel: String(masteryLevel),
|
||||
totalQuestions,
|
||||
correctQuestions,
|
||||
lastAssessedAt: now,
|
||||
updatedAt: now,
|
||||
},
|
||||
})
|
||||
}),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* v3-P1-5:从手动录入的成绩更新掌握度。
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user