Files
NextEdu/src/modules/lesson-preparation/actions-publish.ts
SpecialX 20023e13fd 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
2026-07-03 10:25:21 +08:00

90 lines
3.3 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 server";
import { revalidatePath } from "next/cache";
import { getTranslations } from "next-intl/server";
import {
requirePermission,
} from "@/shared/lib/auth-guard";
import { Permissions } from "@/shared/types/permissions";
import { handleActionError, safeParseDate } from "@/shared/lib/action-utils";
import { getLessonPlanById } from "./data-access";
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: {
planId: string;
blockId: string;
classIds: string[];
availableAt?: string;
dueAt?: string;
}): Promise<ActionState<{ examId: string; assignmentId: string }>> {
const t = await getTranslations("lessonPreparation");
try {
const parsed = publishLessonPlanHomeworkSchema.safeParse(input);
if (!parsed.success) {
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);
// P0-6 修复:先查询课案标题,用于作业标题的 i18n 翻译
// (原代码错误地传入 planId 作为 title 参数)
const plan = await getLessonPlanById(parsed.data.planId, ctx.userId);
if (!plan) {
return { success: false, message: t("error.notFound") };
}
const homeworkTitle = t("publish.homeworkTitle", { title: plan.title });
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, availableAtLabel)
: undefined,
dueAt: parsed.data.dueAt
? safeParseDate(parsed.data.dueAt, dueAtLabel)
: undefined,
homeworkTitle,
homeworkDescription,
});
revalidatePath("/teacher/lesson-plans");
revalidatePath("/teacher/homework");
return {
success: true,
data: {
examId: result.examId,
assignmentId: result.assignmentId,
},
};
} catch (e) {
// publish-service 抛出 PublishServiceError含 code翻译为 i18n 消息
if (e instanceof PublishServiceError) {
const messageKey = PUBLISH_ERROR_KEY_MAP[e.code] ?? "error.publish";
return { success: false, message: t(messageKey) };
}
return handleActionError(e);
}
}
// publish-service 错误码 → i18n 键映射
const PUBLISH_ERROR_KEY_MAP: Record<string, string> = {
PLAN_NOT_FOUND: "publish.planNotFound",
NO_PERMISSION: "publish.noPermission",
NO_EXERCISE_BLOCK: "publish.noExerciseBlock",
NO_QUESTIONS: "publish.noQuestions",
ALREADY_PUBLISHED: "publish.alreadyPublished",
NO_SUBJECT_OR_GRADE: "publish.noSubjectOrGrade",
NO_STUDENTS: "publish.noStudents",
INVALID_QUESTION_TYPE: "error.invalidQuestionType",
};