feat(lesson-preparation): add AI evaluation, analytics, attachments, calendar, comments, review, substitutes, formative, and version diff

- Add actions-ai-evaluation, actions-analytics, actions-attachments, actions-calendar, actions-comments, actions-formative, actions-questions, actions-review, actions-substitutes

- Add corresponding data-access layers for each new action module

- Add calendar-view, curriculum-map-view, version-diff-viewer components

- Add editor-slice, selection-slice, version-slice hooks for state management

- Add document-diff and scope-check lib utilities

- Add default-question-service and external-questions-bridge services
This commit is contained in:
SpecialX
2026-07-03 10:25:21 +08:00
parent a16f09d3c3
commit 20023e13fd
75 changed files with 5131 additions and 1186 deletions

View File

@@ -11,25 +11,33 @@ export const createLessonPlanSchema = z.object({
});
export const updateLessonPlanContentSchema = z.object({
planId: z.string().min(1),
title: z.string().min(1).max(255).optional(),
planId: z.string().min(1, "error.planIdRequired"),
title: z.string().min(1, "error.titleRequired").max(255, "error.titleTooLong").optional(),
// Block 文档结构由 types 守卫,运行时只校验是对象
content: z.record(z.string(), z.unknown()),
});
// P0-5 修复saveVersionSchema 补全 content 字段校验
// LessonPlanDocument 至少包含 version 和 nodes 数组,具体结构由类型守卫保证
export const saveVersionSchema = z.object({
planId: z.string().min(1),
label: z.string().max(100).optional(),
planId: z.string().min(1, "error.planIdRequired"),
label: z.string().max(100, "error.labelTooLong").optional(),
content: z.object({
version: z.string(),
nodes: z.array(z.unknown()),
edges: z.array(z.unknown()).optional(),
anchors: z.array(z.unknown()).optional(),
}),
});
export const revertVersionSchema = z.object({
planId: z.string().min(1),
versionNo: z.number().int().positive(),
planId: z.string().min(1, "error.planIdRequired"),
versionNo: z.number().int().positive("error.versionNoInvalid"),
});
export const saveAsTemplateSchema = z.object({
sourcePlanId: z.string().min(1),
name: z.string().min(1).max(100),
sourcePlanId: z.string().min(1, "error.planIdRequired"),
name: z.string().min(1, "error.nameRequired").max(100, "error.nameTooLong"),
});
// AI 知识点推荐输入校验
@@ -45,19 +53,52 @@ export const getKnowledgePointOptionsSchema = z.object({
chapterId: z.string().optional(),
});
// P0-7 修复getLessonPlansAction params Zod 验证
export const getLessonPlansParamsSchema = z.object({
query: z.string().max(200, "error.queryTooLong").optional(),
textbookId: z.string().optional(),
chapterId: z.string().optional(),
subjectId: z.string().optional(),
status: z.enum(["draft", "submitted", "approved", "published", "rejected", "archived"]).optional(),
});
// 发布作业输入校验
const dateStringSchema = z
.string()
.refine((v) => !Number.isNaN(new Date(v).getTime()), "error.invalidDate");
export const publishLessonPlanHomeworkSchema = z.object({
planId: z.string().min(1),
blockId: z.string().min(1),
planId: z.string().min(1, "error.planIdRequired"),
blockId: z.string().min(1, "error.blockIdRequired"),
classIds: z.array(z.string().min(1)).min(1, "error.classRequired"),
availableAt: dateStringSchema.optional(),
dueAt: dateStringSchema.optional(),
});
// M3 审核工作流 schemas
export const submitLessonPlanForReviewSchema = z.object({
planId: z.string().min(1, "error.planIdRequired"),
reviewComment: z.string().max(500, "error.commentTooLong").optional(),
});
export const reviewLessonPlanSchema = z.object({
planId: z.string().min(1, "error.planIdRequired"),
decision: z.enum(["approved", "rejected"]),
reviewComment: z.string().max(500, "error.commentTooLong").optional(),
});
// M3 审核工作流:创建审核记录输入
export const createReviewRecordSchema = z.object({
planId: z.string().min(1, "error.planIdRequired"),
decision: z.enum(["approved", "rejected"]),
reviewerId: z.string().min(1, "error.reviewerRequired"),
comment: z.string().max(500, "error.commentTooLong").optional(),
});
export type CreateLessonPlanInput = z.infer<typeof createLessonPlanSchema>;
export type UpdateLessonPlanContentInput = z.infer<typeof updateLessonPlanContentSchema>;
export type PublishLessonPlanHomeworkInput = z.infer<typeof publishLessonPlanHomeworkSchema>;
export type GetLessonPlansParams = z.infer<typeof getLessonPlansParamsSchema>;
export type SubmitLessonPlanForReviewInput = z.infer<typeof submitLessonPlanForReviewSchema>;
export type ReviewLessonPlanInput = z.infer<typeof reviewLessonPlanSchema>;
export type CreateReviewRecordInput = z.infer<typeof createReviewRecordSchema>;