=test_update_homework_tests_and_work_log
Some checks failed
CI / build-deploy (push) Has been cancelled

This commit is contained in:
SpecialX
2026-03-19 13:16:49 +08:00
parent eb08c0ab68
commit 99f116cb64
70 changed files with 7470 additions and 20220 deletions

View File

@@ -1,9 +1,10 @@
import { db } from "@/shared/db"
import { exams } from "@/shared/db/schema"
import { exams, examQuestions, questions, subjects, grades } from "@/shared/db/schema"
import { eq, desc, like, and, or } from "drizzle-orm"
import { cache } from "react"
import type { Exam, ExamDifficulty, ExamStatus } from "./types"
import type { AiGeneratedQuestion, AiGeneratedStructureNode } from "./ai-pipeline"
export type GetExamsParams = {
q?: string
@@ -158,3 +159,139 @@ export const omitScheduledAtFromDescription = (description: string | null): stri
return description || "{}"
}
}
export const resolveSubjectGradeNames = async (input: {
subjectId?: string
gradeId?: string
}) => {
const [subjectRecord, gradeRecord] = await Promise.all([
input.subjectId
? db.query.subjects.findFirst({
where: eq(subjects.id, input.subjectId),
})
: Promise.resolve(null),
input.gradeId
? db.query.grades.findFirst({
where: eq(grades.id, input.gradeId),
})
: Promise.resolve(null),
])
return {
subjectName: subjectRecord?.name,
gradeName: gradeRecord?.name,
}
}
export const buildExamDescription = (input: {
subject: string
grade: string
difficulty: number
totalScore: number
durationMin: number
scheduledAt?: string
questionCount?: number
}) => JSON.stringify({
subject: input.subject,
grade: input.grade,
difficulty: input.difficulty,
totalScore: input.totalScore,
durationMin: input.durationMin,
scheduledAt: input.scheduledAt,
questionCount: input.questionCount,
})
export const persistExamDraft = async (input: {
examId: string
title: string
creatorId: string
subjectId: string
gradeId: string
scheduledAt?: string
description: string
}) => {
await db.insert(exams).values({
id: input.examId,
title: input.title,
description: input.description,
creatorId: input.creatorId,
subjectId: input.subjectId,
gradeId: input.gradeId,
startTime: input.scheduledAt ? new Date(input.scheduledAt) : null,
status: "draft",
})
}
const buildOrderedQuestionsFromStructure = (
structure: AiGeneratedStructureNode[],
generated: AiGeneratedQuestion[]
) => {
const questionById = new Map(generated.map((q) => [q.id, q] as const))
const orderedQuestions: Array<{ id: string; score: number }> = []
const collectOrder = (nodes: AiGeneratedStructureNode[]) => {
for (const node of nodes) {
if (node.type === "question" && typeof node.questionId === "string" && node.questionId) {
const score = typeof node.score === "number" ? node.score : questionById.get(node.questionId)?.score ?? 0
orderedQuestions.push({ id: node.questionId, score })
continue
}
if (node.type === "group" && Array.isArray(node.children) && node.children.length > 0) {
collectOrder(node.children)
}
}
}
collectOrder(structure)
if (orderedQuestions.length === 0) {
return generated.map((q) => ({ id: q.id, score: q.score ?? 0 }))
}
return orderedQuestions
}
export const persistAiGeneratedExamDraft = async (input: {
examId: string
title: string
creatorId: string
subjectId: string
gradeId: string
scheduledAt?: string
description: string
structure: AiGeneratedStructureNode[]
generated: AiGeneratedQuestion[]
}) => {
const orderedQuestions = buildOrderedQuestionsFromStructure(input.structure, input.generated)
await db.transaction(async (tx) => {
await tx.insert(exams).values({
id: input.examId,
title: input.title,
description: input.description,
creatorId: input.creatorId,
subjectId: input.subjectId,
gradeId: input.gradeId,
startTime: input.scheduledAt ? new Date(input.scheduledAt) : null,
status: "draft",
structure: input.structure,
})
if (input.generated.length > 0) {
await tx.insert(questions).values(
input.generated.map((q) => ({
id: q.id,
content: q.content,
type: q.type,
difficulty: q.difficulty,
authorId: input.creatorId,
}))
)
}
if (orderedQuestions.length > 0) {
await tx.insert(examQuestions).values(
orderedQuestions.map((q, idx) => ({
examId: input.examId,
questionId: q.id,
score: q.score ?? 0,
order: idx,
}))
)
}
})
}