Files
NextEdu/src/modules/lesson-preparation/config/block-registry.tsx
SpecialX 25dca843be feat(lesson-preparation): major update with AI features, schedules, and new components
- Add actions-schedules.ts and data-access-schedules.ts for schedule management

- Add AI differentiation, AI feedback, consistency check dialogs

- Add attachment-picker, curriculum-heatmap, print-view, version-diff-view

- Add lesson-plan-mobile-view and schedule-dialog components

- Add lib: ai-differentiation, ai-feedback, auto-layout, consistency-check,

  curriculum-coverage, export, version-diff

- Add history-slice hook for version history

- Update existing components, hooks, providers, services, types

- Add teacher lesson-plans heatmap and library pages
2026-07-04 10:22:10 +08:00

205 lines
5.9 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.
"use client";
import type { ReactElement } from "react";
import type {
BlockData,
BlockType,
} from "../types";
import {
isBlackboardBlockData,
isExerciseBlockData,
isHomeworkBlockData,
isImportBlockData,
isKeyPointBlockData,
isNewTeachingBlockData,
isObjectiveBlockData,
isReflectionBlockData,
isRichTextBlockData,
isSummaryBlockData,
isTextStudyBlockData,
} from "../lib/type-guards";
import { RichTextBlock } from "../components/blocks/rich-text-block";
import { ExerciseBlock } from "../components/blocks/exercise-block";
import { TextStudyBlock } from "../components/blocks/text-study-block";
import { ObjectiveBlock } from "../components/blocks/objective-block";
import { KeyPointBlock } from "../components/blocks/key-point-block";
import { ImportBlock } from "../components/blocks/import-block";
import { NewTeachingBlock } from "../components/blocks/new-teaching-block";
import { SummaryBlock } from "../components/blocks/summary-block";
import { HomeworkBlock } from "../components/blocks/homework-block";
import { BlackboardBlock } from "../components/blocks/blackboard-block";
import { ReflectionBlock } from "../components/blocks/reflection-block";
/**
* Block 注册表:配置驱动渲染。
* 新增 Block 类型只需在此注册,无需修改 NodeEditPanel。
*/
export interface BlockRenderProps {
blockId: string;
data: BlockData;
textbookId?: string;
chapterId?: string;
classes?: { id: string; name: string }[];
/** V5-5当前课案 ID仅 RichTextBlock 用于素材库 picker 关联) */
planId?: string;
onUpdate: (data: BlockData) => void;
}
export interface BlockRegistryEntry {
/** 是否为富文本类(共享 RichTextBlock 编辑器) */
isRichText?: boolean;
}
/**
* Block 注册表元数据单一数据源P0-9 修复)。
* isRichText 属性是判断富文本 block 的唯一权威来源。
* 组件渲染由 BlockRenderer 统一处理,避免在 render 中动态获取组件引用。
*/
export const BLOCK_REGISTRY: Record<BlockType, BlockRegistryEntry> = {
objective: {},
key_point: {},
import: {},
new_teaching: {},
consolidation: { isRichText: true },
summary: {},
homework: {},
blackboard: {},
text_study: {},
exercise: {},
rich_text: { isRichText: true },
reflection: {},
};
/**
* 判断某 BlockType 是否为富文本类。
* P0-9 修复:统一以 BLOCK_REGISTRY.isRichText 为唯一数据源,
* 删除 constants.ts 中的 RICH_TEXT_BLOCK_TYPES 和此处的 RICH_TEXT_TYPES 冗余定义。
*/
export function isRichTextBlock(type: BlockType): boolean {
return BLOCK_REGISTRY[type]?.isRichText === true;
}
/**
* 静态 Block 渲染组件。
* 根据 type 从注册表查找并渲染对应 Block所有组件引用均为模块顶层静态声明
* 满足 react-hooks/static-components 规则。
* 新增 Block 类型时,在此 switch 中添加对应 case 即可。
*
* V3 修复:使用类型守卫替代 `as` 断言,安全收窄 BlockData 联合类型。
* 类型守卫失败时返回 null理论上不会发生因为 type 与 data 由调用方保证一致)。
*/
export function BlockRenderer(props: BlockRenderProps & { type: BlockType }): ReactElement | null {
const { type, ...rest } = props;
switch (type) {
case "objective": {
if (!isObjectiveBlockData(rest.data)) return null;
return (
<ObjectiveBlock
data={rest.data}
onUpdate={(d) => rest.onUpdate(d)}
/>
);
}
case "key_point": {
if (!isKeyPointBlockData(rest.data)) return null;
return (
<KeyPointBlock
data={rest.data}
onUpdate={(d) => rest.onUpdate(d)}
/>
);
}
case "import": {
if (!isImportBlockData(rest.data)) return null;
return (
<ImportBlock
data={rest.data}
onUpdate={(d) => rest.onUpdate(d)}
/>
);
}
case "new_teaching": {
if (!isNewTeachingBlockData(rest.data)) return null;
return (
<NewTeachingBlock
data={rest.data}
textbookId={rest.textbookId}
chapterId={rest.chapterId}
onUpdate={(d) => rest.onUpdate(d)}
/>
);
}
case "summary": {
if (!isSummaryBlockData(rest.data)) return null;
return (
<SummaryBlock
data={rest.data}
onUpdate={(d) => rest.onUpdate(d)}
/>
);
}
case "homework": {
if (!isHomeworkBlockData(rest.data)) return null;
return (
<HomeworkBlock
data={rest.data}
onUpdate={(d) => rest.onUpdate(d)}
/>
);
}
case "blackboard": {
if (!isBlackboardBlockData(rest.data)) return null;
return (
<BlackboardBlock
data={rest.data}
textbookId={rest.textbookId}
chapterId={rest.chapterId}
onUpdate={(d) => rest.onUpdate(d)}
/>
);
}
case "reflection": {
if (!isReflectionBlockData(rest.data)) return null;
return (
<ReflectionBlock
data={rest.data}
onUpdate={(d) => rest.onUpdate(d)}
/>
);
}
case "exercise": {
if (!isExerciseBlockData(rest.data)) return null;
return (
<ExerciseBlock
blockId={rest.blockId}
data={rest.data}
classes={rest.classes ?? []}
textbookId={rest.textbookId}
chapterId={rest.chapterId}
/>
);
}
case "text_study": {
if (!isTextStudyBlockData(rest.data)) return null;
return <TextStudyBlock blockId={rest.blockId} data={rest.data} />;
}
case "rich_text":
case "consolidation": {
if (!isRichTextBlockData(rest.data)) return null;
return (
<RichTextBlock
data={rest.data}
textbookId={rest.textbookId}
chapterId={rest.chapterId}
planId={rest.planId}
blockId={rest.blockId}
onUpdate={(d) => rest.onUpdate(d)}
/>
);
}
default:
return null;
}
}