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

155 lines
5.0 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 { requirePermission } from "@/shared/lib/auth-guard";
import { handleActionError } from "@/shared/lib/action-utils";
import { Permissions } from "@/shared/types/permissions";
import { getKnowledgePointsByTextbookId } from "@/modules/textbooks/data-access";
import { suggestKnowledgePoints } from "./ai-suggest";
import { suggestKnowledgePointsSchema } from "./schema";
import { translateFieldErrors } from "./lib/i18n-errors";
import { generateLessonPlanFeedback, type AiFeedbackResult } from "./lib/ai-feedback";
import {
generateDifferentiationSuggestions,
checkCurriculumAlignment,
generateExplainableAssessment,
type DifferentiationSuggestion,
type CurriculumCheckItem,
type ExplainableAssessment,
} from "./lib/ai-differentiation";
import type { LessonPlanDocument } from "./types";
import type { ActionState } from "@/shared/types/action-state";
export async function suggestKnowledgePointsAction(input: {
doc: unknown;
textbookId?: string;
chapterId?: string;
}): Promise<
ActionState<{
suggestions: { id: string; name: string; reason: string }[];
}>
> {
try {
const parsed = suggestKnowledgePointsSchema.safeParse(input);
if (!parsed.success) {
const errors = await translateFieldErrors(parsed.error.flatten().fieldErrors);
return { success: false, errors };
}
// 并行校验两个权限点
await Promise.all([
requirePermission(Permissions.LESSON_PLAN_READ),
requirePermission(Permissions.AI_CHAT),
]);
// P1 修复:从 unknown 安全提取 nodes 数组,显式类型标注替代隐式 any
// Zod 已校验 doc 是 Record<string, unknown>,但 nodes 字段需运行时检查
const doc = parsed.data.doc;
const nodes: unknown[] = Array.isArray(doc.nodes) ? doc.nodes : [];
const suggestions = await suggestKnowledgePoints(
{ nodes },
parsed.data.textbookId,
parsed.data.chapterId,
);
return { success: true, data: { suggestions } };
} catch (e) {
// P1 修复:统一使用 handleActionError 处理错误,避免手动判断 PermissionDeniedError
return handleActionError(e);
}
}
/**
* V5-17 A1/A2AI 反馈闭环。
* 调用 AI 对课案文档生成结构化反馈(含解释性展示)。
*/
export async function generateLessonPlanFeedbackAction(
doc: LessonPlanDocument,
): Promise<ActionState<AiFeedbackResult>> {
try {
await Promise.all([
requirePermission(Permissions.LESSON_PLAN_READ),
requirePermission(Permissions.AI_CHAT),
]);
const result = await generateLessonPlanFeedback(doc);
return { success: true, data: result };
} catch (e) {
return handleActionError(e);
}
}
/**
* V5-21 A3AI 差异化教学建议生成。
* 根据课案内容生成基础/提高/拓展三个层次的教学建议。
*/
export async function generateDifferentiationSuggestionsAction(
doc: LessonPlanDocument,
): Promise<ActionState<{ items: DifferentiationSuggestion[] }>> {
try {
await Promise.all([
requirePermission(Permissions.LESSON_PLAN_READ),
requirePermission(Permissions.AI_CHAT),
]);
const items = await generateDifferentiationSuggestions(doc);
return { success: true, data: { items } };
} catch (e) {
return handleActionError(e);
}
}
/**
* V5-21 A4AI 课标实时核对。
* 检查课案是否覆盖教材课标要求。
*/
export async function checkCurriculumAlignmentAction(
doc: LessonPlanDocument,
knowledgePoints: { id: string; name: string }[],
): Promise<ActionState<{ items: CurriculumCheckItem[] }>> {
try {
await Promise.all([
requirePermission(Permissions.LESSON_PLAN_READ),
requirePermission(Permissions.AI_CHAT),
]);
const items = await checkCurriculumAlignment(doc, knowledgePoints);
return { success: true, data: { items } };
} catch (e) {
return handleActionError(e);
}
}
/**
* V5-21 A5AI 可解释评估。
* 对课案中的练习节点给出可解释的评分依据。
*/
export async function generateExplainableAssessmentAction(
doc: LessonPlanDocument,
): Promise<ActionState<{ items: ExplainableAssessment[] }>> {
try {
await Promise.all([
requirePermission(Permissions.LESSON_PLAN_READ),
requirePermission(Permissions.AI_CHAT),
]);
const items = await generateExplainableAssessment(doc);
return { success: true, data: { items } };
} catch (e) {
return handleActionError(e);
}
}
/**
* V5-21 A4 辅助:按教材 ID 获取知识点列表(仅 id + name
* 供课标核对 Tab 按需加载,避免编辑页首屏负担。
*/
export async function getKnowledgePointsForAlignmentAction(
textbookId: string,
): Promise<ActionState<{ items: { id: string; name: string }[] }>> {
try {
await requirePermission(Permissions.LESSON_PLAN_READ);
const kps = await getKnowledgePointsByTextbookId(textbookId);
return {
success: true,
data: { items: kps.map((kp) => ({ id: kp.id, name: kp.name })) },
};
} catch (e) {
return handleActionError(e);
}
}