feat(lesson-preparation): 备课模块审计重构 — 跨模块解耦 + i18n + 纯函数抽取 + 错误边界
P0-1 跨模块直查修复:publish-service 不再直查 examQuestions 表,新增 exams/data-access.addExamQuestions 接口,复用 classes/data-access.getStudentIdsByClassIds P0-2 i18n 接入:新增 zh-CN/en 翻译文件,注册 lessonPreparation 命名空间,17 个组件改造为 useTranslations/getTranslations P1 纯函数抽取:lib/document-migration.ts(类型守卫替代 as 断言)、lib/node-summary.ts(翻译函数注入)、lib/rf-mappers.ts P1 错误边界+骨架屏:新增 LessonPlanErrorBoundary 和 4 个 Skeleton 组件 P1 Block 注册表:新增 config/block-registry.tsx(BlockRenderer 组件),node-edit-panel 重构为配置驱动渲染 P1 其他修复:exercise-block 改用 router.refresh(),node-editor/lesson-node 复用 lib/ 纯函数 架构图同步:更新 004 和 005 文档 Refs: docs/architecture/audit/lesson-preparation-audit-report.md
This commit is contained in:
@@ -4,13 +4,11 @@ import { eq } from "drizzle-orm";
|
||||
import { createId } from "@paralleldrive/cuid2";
|
||||
|
||||
import { db } from "@/shared/db";
|
||||
import {
|
||||
lessonPlans,
|
||||
examQuestions,
|
||||
} from "@/shared/db/schema";
|
||||
import { lessonPlans } from "@/shared/db/schema";
|
||||
import { createQuestionWithRelations } from "@/modules/questions/data-access";
|
||||
import { persistExamDraft } from "@/modules/exams/data-access";
|
||||
import { persistExamDraft, addExamQuestions } from "@/modules/exams/data-access";
|
||||
import { createHomeworkAssignment } from "@/modules/homework/data-access-write";
|
||||
import { getStudentIdsByClassIds } from "@/modules/classes/data-access";
|
||||
import { normalizeDocument } from "./data-access";
|
||||
import type { LessonPlanDocument, ExerciseBlockData } from "./types";
|
||||
|
||||
@@ -29,20 +27,6 @@ interface PublishResult {
|
||||
updatedContent: LessonPlanDocument;
|
||||
}
|
||||
|
||||
// 查询班级学生列表(避免直接依赖 classes 模块的内部表)
|
||||
async function getStudentIdsByClassIds(
|
||||
classIds: string[],
|
||||
): Promise<string[]> {
|
||||
if (classIds.length === 0) return [];
|
||||
const { inArray } = await import("drizzle-orm");
|
||||
const { classEnrollments } = await import("@/shared/db/schema");
|
||||
const rows = await db
|
||||
.select({ studentId: classEnrollments.studentId })
|
||||
.from(classEnrollments)
|
||||
.where(inArray(classEnrollments.classId, classIds));
|
||||
return rows.map((r) => r.studentId);
|
||||
}
|
||||
|
||||
export async function publishLessonPlanHomework(
|
||||
input: PublishInput,
|
||||
): Promise<PublishResult> {
|
||||
@@ -80,9 +64,7 @@ export async function publishLessonPlanHomework(
|
||||
throw new Error("该练习块已发布,请使用'重新发布'");
|
||||
|
||||
// 3. inline 题目入库,替换占位 ID
|
||||
const newContent: LessonPlanDocument = JSON.parse(
|
||||
JSON.stringify(plan.content),
|
||||
);
|
||||
const newContent: LessonPlanDocument = structuredClone(plan.content);
|
||||
const newBlock = newContent.nodes.find((b) => b.id === input.blockId);
|
||||
if (!newBlock || newBlock.type !== "exercise")
|
||||
throw new Error("练习块不存在");
|
||||
@@ -122,17 +104,15 @@ export async function publishLessonPlanHomework(
|
||||
scheduledAt: undefined,
|
||||
description: `来自课案:${plan.title}`,
|
||||
});
|
||||
// 插入 examQuestions
|
||||
if (newData.items.length > 0) {
|
||||
await db.insert(examQuestions).values(
|
||||
newData.items.map((it, i) => ({
|
||||
examId,
|
||||
questionId: it.questionId,
|
||||
score: it.score,
|
||||
order: i,
|
||||
})),
|
||||
);
|
||||
}
|
||||
// 插入 examQuestions(通过 exams data-access 跨模块接口)
|
||||
await addExamQuestions(
|
||||
examId,
|
||||
newData.items.map((it, i) => ({
|
||||
questionId: it.questionId,
|
||||
score: it.score,
|
||||
order: i,
|
||||
})),
|
||||
);
|
||||
|
||||
// 5. 下发作业
|
||||
const assignmentId = createId();
|
||||
|
||||
Reference in New Issue
Block a user