feat(lesson-preparation): add readonly view, anchor node selector, and type guards

- Add lesson-plan-readonly-view for viewing published plans

- Add anchor-node-selector and textbook-segments for canvas anchor positioning

- Add i18n-errors and type-guards lib utilities

- Add lesson-plan-provider-setup for provider initialization

- Update actions, data-access (knowledge, versions, main), publish-service

- Update blocks (blackboard, exercise, homework, import, key-point, objective, reflection)

- Update editor, node-editor, node-edit-panel, pickers, and providers
This commit is contained in:
SpecialX
2026-06-24 12:02:42 +08:00
parent a48e7d0e27
commit 6bc113eaff
39 changed files with 2129 additions and 571 deletions

View File

@@ -9,6 +9,7 @@ import { Permissions } from "@/shared/types/permissions";
import { handleActionError, safeParseDate } from "@/shared/lib/action-utils";
import { publishLessonPlanHomework, PublishServiceError } from "./publish-service";
import { publishLessonPlanHomeworkSchema } from "./schema";
import { translateFieldErrors } from "./lib/i18n-errors";
import type { ActionState } from "./types";
export async function publishLessonPlanHomeworkAction(input: {
@@ -22,24 +23,32 @@ export async function publishLessonPlanHomeworkAction(input: {
try {
const parsed = publishLessonPlanHomeworkSchema.safeParse(input);
if (!parsed.success) {
return { success: false, errors: parsed.error.flatten().fieldErrors };
const errors = await translateFieldErrors(parsed.error.flatten().fieldErrors);
return { success: false, errors };
}
const ctx = await requirePermission(
Permissions.LESSON_PLAN_PUBLISH,
);
await requirePermission(Permissions.HOMEWORK_CREATE);
// V3 修复:作业标题/描述由 actions 层 i18n 翻译后传入,避免 service 层硬编码中文
const homeworkTitle = t("publish.homeworkTitle", { title: parsed.data.planId });
const homeworkDescription = t("publish.homeworkDescription");
const availableAtLabel = t("publish.availableAtLabel");
const dueAtLabel = t("publish.dueAtLabel");
const result = await publishLessonPlanHomework({
planId: parsed.data.planId,
blockId: parsed.data.blockId,
userId: ctx.userId,
classIds: parsed.data.classIds,
availableAt: parsed.data.availableAt
? safeParseDate(parsed.data.availableAt, "可用时间")
? safeParseDate(parsed.data.availableAt, availableAtLabel)
: undefined,
dueAt: parsed.data.dueAt
? safeParseDate(parsed.data.dueAt, "截止时间")
? safeParseDate(parsed.data.dueAt, dueAtLabel)
: undefined,
homeworkTitle,
homeworkDescription,
});
revalidatePath("/teacher/lesson-plans");
revalidatePath("/teacher/homework");
@@ -69,4 +78,5 @@ const PUBLISH_ERROR_KEY_MAP: Record<string, string> = {
ALREADY_PUBLISHED: "publish.alreadyPublished",
NO_SUBJECT_OR_GRADE: "publish.noSubjectOrGrade",
NO_STUDENTS: "publish.noStudents",
INVALID_QUESTION_TYPE: "error.invalidQuestionType",
};