Files
NextEdu/src/modules/lesson-preparation/actions-ai-evaluation.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

121 lines
3.5 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.
/**
* M8 AI 评估 - Server Actions
*/
"use server";
import { getTranslations } from "next-intl/server";
import { z } from "zod";
import {
getEvaluationsByPlanId,
getLatestEvaluation,
createEvaluation,
deleteEvaluation,
evaluateDocument,
} from "./data-access-ai-evaluation";
import type { AiEvaluation } from "./data-access-ai-evaluation";
import type { ActionState } from "@/shared/types/action-state";
import { getAuthContext, requirePermission } from "@/shared/lib/auth-guard";
import { handleActionError } from "@/shared/lib/action-utils";
import { Permissions } from "@/shared/types/permissions";
import { getLessonPlanById } from "./data-access";
import { getStandardsByPlanId } from "../standards/data-access";
import { normalizeDocument } from "./lib/document-migration";
const createEvaluationSchema = z.object({
planId: z.string().min(1),
versionNo: z.number().int().positive(),
});
/**
* 查询课案的所有 AI 评估
*/
export async function getLessonPlanEvaluationsAction(
planId: string,
): Promise<ActionState<{ items: AiEvaluation[] }>> {
try {
await requirePermission(Permissions.LESSON_PLAN_READ);
const items = await getEvaluationsByPlanId(planId);
return { success: true, data: { items } };
} catch (e) {
return handleActionError(e);
}
}
/**
* 查询最新评估
*/
export async function getLatestEvaluationAction(
planId: string,
): Promise<ActionState<{ evaluation: AiEvaluation | null }>> {
try {
await requirePermission(Permissions.LESSON_PLAN_READ);
const evaluation = await getLatestEvaluation(planId);
return { success: true, data: { evaluation } };
} catch (e) {
return handleActionError(e);
}
}
/**
* 触发 AI 评估(当前为本地规则评估,未来可替换为远程 AI API
*/
export async function evaluateLessonPlanAction(
input: Record<string, unknown>,
): Promise<ActionState<{ evaluation: AiEvaluation }>> {
try {
await requirePermission(Permissions.LESSON_PLAN_READ);
const t = await getTranslations("lessonPreparation");
const parseResult = createEvaluationSchema.safeParse(input);
if (!parseResult.success) {
return { success: false, message: t("error.invalidInput") };
}
const { planId, versionNo } = parseResult.data;
const auth = await getAuthContext();
if (!auth.userId) {
return { success: false, message: t("error.unauthorized") };
}
const plan = await getLessonPlanById(planId, auth.userId);
if (!plan) {
return { success: false, message: t("error.notFound") };
}
const doc = normalizeDocument(plan.content as unknown);
const standards = await getStandardsByPlanId(planId);
const result = evaluateDocument(doc, {
standardsLinkedCount: standards.length,
hasInteractiveItems: false, // TODO: 查询 M5 formative items
});
const evaluation = await createEvaluation(
{
planId,
versionNo,
overallScore: result.overallScore,
dimensionScores: result.dimensionScores,
suggestions: result.suggestions,
},
auth.userId,
);
return { success: true, data: { evaluation } };
} catch (e) {
return handleActionError(e);
}
}
/**
* 删除评估
*/
export async function deleteEvaluationAction(
id: string,
): Promise<ActionState<null>> {
try {
await requirePermission(Permissions.LESSON_PLAN_UPDATE);
await deleteEvaluation(id);
return { success: true, data: null };
} catch (e) {
return handleActionError(e);
}
}