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
This commit is contained in:
SpecialX
2026-07-03 10:25:21 +08:00
parent a16f09d3c3
commit 20023e13fd
75 changed files with 5131 additions and 1186 deletions

View File

@@ -1,5 +1,6 @@
"use client";
import { useCallback } from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useTranslations } from "next-intl";
@@ -69,7 +70,8 @@ export function LessonPlanCard({
// 只读视图(非 teacher不显示编辑操作
const isReadOnly = viewMode !== "teacher";
async function handleArchive() {
// P2 修复:使用 useCallback 包裹异步处理函数,避免每次渲染重新创建
const handleArchive = useCallback(async () => {
if (!service) return;
try {
const res = await service.deleteLessonPlan(plan.id);
@@ -84,9 +86,9 @@ export function LessonPlanCard({
console.error("[LessonPlanCard] archive failed", e);
toast.error(t("error.delete"));
}
}
}, [service, plan.id, tracker, t, router]);
async function handleDuplicate() {
const handleDuplicate = useCallback(async () => {
if (!service) return;
try {
const res = await service.duplicateLessonPlan(plan.id);
@@ -100,9 +102,9 @@ export function LessonPlanCard({
console.error("[LessonPlanCard] duplicate failed", e);
toast.error(t("error.duplicate"));
}
}
}, [service, plan.id, tracker, t, router]);
async function handlePublish() {
const handlePublish = useCallback(async () => {
if (!service) return;
try {
const res = await service.publishLessonPlan(plan.id);
@@ -117,9 +119,9 @@ export function LessonPlanCard({
console.error("[LessonPlanCard] publish failed", e);
toast.error(t("error.save"));
}
}
}, [service, plan.id, tracker, t, router]);
async function handleUnpublish() {
const handleUnpublish = useCallback(async () => {
if (!service) return;
try {
const res = await service.unpublishLessonPlan(plan.id);
@@ -134,7 +136,7 @@ export function LessonPlanCard({
console.error("[LessonPlanCard] unpublish failed", e);
toast.error(t("error.save"));
}
}
}, [service, plan.id, tracker, t, router]);
return (
<div className="border border-outline-variant rounded-lg p-4 bg-surface-container-lowest hover:shadow-md transition-shadow">