feat(portal-shell): 管理域 §9.4 B5 全量迁移(24 + 21 补充批次共 44 页 + 42 features)
按 ARCHITECTURE.md §9.4 规划口径 + admin-NeedTodo.md §四补充批次完成管理域全量页面迁移: 【§9.4 规划 24 页(B5)】 - users(2) + roles(1) + permissions(1) + audit-logs(4) + invitation-codes(1) - school(6: redirect/schools/classes/departments/academic-year/grades) - announcements(1) + files(1) + ai-settings(1) + system(1) + viewports(1) - students(1) + teachers(1) + organization(1) + plugins(1, config-service) - 仪表盘已存在(/shell/admin/page.tsx) 【§四补充批次 21 页】 - course-plans(4) + elective(4) + questions(1) + lesson-plans(2) + error-book(1) - scheduling(3: auto/changes/rules) + attendance(1) + curriculum-map(1) - announcements 详情/编辑(2) + roles/[id] 详情(1) + users/import(1) 【实现要点】 - 全部使用 ListPageShell + loading/error/empty 三态规范(§11.3 DoD) - 走 lib/api hooks;未就绪契约走 MSW + @contract-pending 注释(§11.4) - 文案走 useTranslations(zh-CN + en 两份同步更新) - 42 个 features/<domain>/transformations.ts 纯函数 + 配套 vitest 单测 - catch 块统一 notify.error;无空 catch;lint:tokens 通过 - 路由全部登记到 route-permissions.ts(39 EXACT + 8 PREFIX) 【验收】 - tsc --noEmit: 0 errors - ESLint src: 0 errors (4 generated-files warnings, pre-existing) - lint:tokens: 0 errors - vitest: 1639/1639 passed (含 23 admin 测试文件 671 用例) - check:routes: PASS (143 routes, 4 ghost entries pre-existing) - check:pages: PASS (146 pages) - check:codegen: PASS - arch:scan: 24 modules, 8262 symbols 关联:ARCHITECTURE.md §9.4 / §10 P5 / §11.3 DoD / §11.6
This commit is contained in:
579
apps/portal-shell/docs/needtodo/teacher-NeedTodo.md
Normal file
579
apps/portal-shell/docs/needtodo/teacher-NeedTodo.md
Normal file
@@ -0,0 +1,579 @@
|
||||
# 教师域(Teacher)待完成功能分析
|
||||
|
||||
> 参考项目:`e:\desktop\CICD\src\app\(dashboard)\teacher\`(53 个 page.tsx)
|
||||
> 当前项目:`e:\Desktop\Edu\apps\portal-shell\src\app\shell\teacher\`(53 个 page.tsx)
|
||||
> 规划依据:`apps\portal-shell\ARCHITECTURE.md` §9.1(教师域 56 页,B1+B2)
|
||||
> 分析日期:2026-07-24
|
||||
> 分析方式:逐页面对比 CICD 实现 vs portal-shell 实现,逐个读取 page.tsx + features/*-client.tsx
|
||||
|
||||
---
|
||||
|
||||
## 〇、方法论与对比基线
|
||||
|
||||
1. CICD 单体(Next.js App Router + Server Actions + Drizzle)作为**功能基线**,反映"老版单体已实现"的教师功能完整态。
|
||||
2. portal-shell 作为**目标态**,遵循 ARCH §9.1 的契约与批次规划(B1+B2+B2末)。
|
||||
3. portal-shell 普遍采用「Server Component page.tsx 仅做 `<Suspense>` 边界包裹 + Client Component `*-client.tsx` 承载业务」的统一架构;CICD 多为「Server Component 直接拉数据 + Rich Client Component 渲染」。
|
||||
4. ARCH §9.1 规划 56 页,portal-shell 已实现 53 页,**3 页缺口** = `exams/[id]/proctoring`(B2末)+ `notifications`(B1 共享)+ `settings`(B1 共享)。
|
||||
5. CICD 中 `exams/page.tsx`、`classes/page.tsx`、`exams/grading/*`、`exams/create` 等为**重定向/等价路径**,不算独立功能缺口。
|
||||
6. CICD 中 `diagnostic/student/[studentId]` 在 ARCH §9.1 中**未规划**(ARCH 仅规划 `diagnostic` + `diagnostic/class/[classId]` 共 2 页),属 CICD 历史功能,portal-shell 缺失但**不违反 ARCH**。
|
||||
|
||||
---
|
||||
|
||||
## 一、页面完成度总览
|
||||
|
||||
| 状态 | 数量 | 说明 |
|
||||
| --------------------- | ---- | ---------------------------------------------------------------------------------------------------- |
|
||||
| ✅ 已完成且功能完整 | 33 | 功能与 CICD 持平或为 ARCH 新建且实现完整(含 MSW 兜底契约页) |
|
||||
| 🟡 已完成但功能不完整 | 14 | 页面存在但子功能/技术栈与 CICD 有差距 |
|
||||
| ❌ 完全缺失 | 4 | `exams/[id]/proctoring`、`diagnostic/student/[studentId]`、`/shell/notifications`、`/shell/settings` |
|
||||
|
||||
### ✅ 已完成且功能完整(33 页)
|
||||
|
||||
| 模块 | 页面 | 备注 |
|
||||
| ---------------- | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
|
||||
| dashboard | `/shell/teacher`(teacher/page.tsx) | 仪表盘,4 StatCard + 班级概况 + 预警(注:标题用硬编码中文,违反 i18n,但功能完整) |
|
||||
| exams | `/shell/teacher/exams/[id]/analytics` | 汇总卡片 + 分数段分布图 + 每题正确率 + 学生排名,混合契约 ✅ `assignmentAnalysis` |
|
||||
| homework | `/shell/teacher/homework/submissions/[submissionId]` | 单份提交批改,含题目分数/教师评语/AI 建议应用/上下导航/总反馈 |
|
||||
| homework | `/shell/teacher/homework/submissions/[submissionId]/scan-grading` | 扫描批改 |
|
||||
| homework | `/shell/teacher/homework/submissions` | 提交列表 |
|
||||
| homework | `/shell/teacher/homework/assignments/[id]/submissions` | 作业子提交列表 |
|
||||
| homework | `/shell/teacher/homework` | 作业列表 |
|
||||
| grades | `/shell/teacher/grades` | 成绩列表 |
|
||||
| grades | `/shell/teacher/grades/analytics` | 成绩分析,汇总 + 分布 + 排名,混合契约 |
|
||||
| grades | `/shell/teacher/grades/stats` | 成绩统计 |
|
||||
| grades | `/shell/teacher/grades/report-card` | 报告卡 |
|
||||
| attendance | `/shell/teacher/attendance` | 考勤列表 |
|
||||
| attendance | `/shell/teacher/attendance/report` | 考勤报告 |
|
||||
| attendance | `/shell/teacher/attendance/stats` | 考勤统计 |
|
||||
| classes | `/shell/teacher/classes` | 班级列表(含 gradeId/subjectId/q 筛选) |
|
||||
| classes | `/shell/teacher/classes/schedule` | 班级课表 |
|
||||
| students | (见 🟡 学生列表,因缺科目成绩) | — |
|
||||
| course-plans | `/shell/teacher/course-plans`、`/[id]` | 2 页 |
|
||||
| elective | `/shell/teacher/elective`、`/create`、`/[id]/edit` | 3 页 |
|
||||
| error-book | `/shell/teacher/error-book` | ✅ `errorBookItems/Stats` 真实契约 |
|
||||
| diagnostic | `/shell/teacher/diagnostic` | 诊断列表 |
|
||||
| analytics | `/shell/teacher/analytics`、`/[studentId]` | ARCH 新建 2 页,MSW 兜底 |
|
||||
| ai | `/shell/teacher/ai/ai-assist`、`/ai-lesson-plan`、`/ai-report` | ARCH 新建 B2末 3 页,全 MSW 兜底,工作台布局完整 |
|
||||
| knowledge-graph | `/shell/teacher/knowledge-graph` | ARCH 新建 B2末,三栏工作台,`knowledgePoint(id)` ✅ 真实 + 列表 MSW |
|
||||
| questions | `/shell/teacher/questions` | 题库列表,🟡 `question(id)` |
|
||||
| textbooks | `/shell/teacher/textbooks`、`/[id]` | 2 页,🟡 `textbook(id)` |
|
||||
| lesson-plans | `/shell/teacher/lesson-plans`、`/new`、`/calendar`、`/heatmap`、`/library` | 5 页(edit 见 🟡) |
|
||||
| practice | `/shell/teacher/practice` | 练习 |
|
||||
| leave | `/shell/teacher/leave` | 请假 |
|
||||
| schedule-changes | `/shell/teacher/schedule-changes` | 调课 |
|
||||
|
||||
### 🟡 已完成但功能不完整(14 页)
|
||||
|
||||
详见 §三。
|
||||
|
||||
### ❌ 完全缺失(4 页)
|
||||
|
||||
详见 §二。
|
||||
|
||||
---
|
||||
|
||||
## 二、缺失页面清单
|
||||
|
||||
### 2.1 `/shell/teacher/exams/[id]/proctoring`(监考工作台)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\teacher\exams\[id]\proctoring\page.tsx`
|
||||
- **功能描述**:实时监考面板,包含 `ProctoringDashboard` 组件,并行拉取:
|
||||
- `getExamForProctoring(id)` — 考试基础信息
|
||||
- `getExamProctoringSummary(id)` — 监考汇总(应到/实到/异常数)
|
||||
- `getStudentProctoringStatuses(id)` — 学生实时状态列表
|
||||
- `getRecentProctoringEvents(id, 20)` — 最近 20 条监考事件
|
||||
- **技术栈**:Server Component + `requirePermission(Permissions.EXAM_PROCTOR)` + `ProctoringDashboard` 客户端组件(实时 WS 推送)
|
||||
- **ARCHITECTURE.md 契约**:❌(schema 无,需 WS 契约工单 + MSW 先行)
|
||||
- **批次**:B2 末(二期,WS)
|
||||
- **建议**:✅ 必须补做。需先定 WS 协议契约(push-gateway),再写 MSW mock,最后实现 `ProctoringDashboard` 客户端组件。这是 B2末 明确规划页。
|
||||
|
||||
### 2.2 `/shell/teacher/diagnostic/student/[studentId]`(学生诊断详情)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\teacher\diagnostic\student\[studentId]\page.tsx`
|
||||
- **功能描述**:单个学生的学情诊断页,包含:
|
||||
- `StudentDiagnosticView` 组件,渲染 `MasteryRadarPoint` 雷达图(学生 vs 班级平均对比)
|
||||
- `getStudentMasterySummary(studentId)` — 学生掌握度汇总
|
||||
- `getDiagnosticReports({ studentId }, ctx.dataScope)` — 诊断报告列表(教师可看草稿)
|
||||
- `getKnowledgePointStats(studentClassId)` — 班级平均掌握度(雷达图对比)
|
||||
- DataScope 二次校验:`class_taught` scope 验师生关系,`class_members`/`children` scope 限制访问
|
||||
- **技术栈**:Server Component + `requirePermission(Permissions.DIAGNOSTIC_READ)` + `WidgetBoundary` + `StudentDiagnosticView` 客户端组件
|
||||
- **ARCHITECTURE.md 契约**:🟡(`diagnosticReports` ✅,但单生维度查询未明确)— **注意:ARCH §9.1 仅规划 2 页(`/diagnostic` + `/diagnostic/class/[classId]`),未含学生维度**
|
||||
- **批次**:B2(CICD 历史功能,ARCH 未规划)
|
||||
- **建议**:⚠️ 建议补做。虽 ARCH §9.1 未明确规划,但 CICD 已有完整实现且属于教师核心诊断场景(查看单个学生的掌握度雷达图 + 班级对比)。补做时需同步更新 ARCH §9.1 + 004。
|
||||
|
||||
### 2.3 `/shell/notifications`(通知中心,B1 共享)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\teacher\notifications\page.tsx`(教师角色入口)
|
||||
- **功能描述**:通知中心,按 `userId` 拉取通知列表
|
||||
- **技术栈**:Server Component + `notifications(userId)` 查询
|
||||
- **ARCHITECTURE.md 契约**:✅ `notifications(userId)` schema 已就绪
|
||||
- **批次**:B1(共享,所有角色共用)
|
||||
- **建议**:✅ 必须补做。B1 共享页,schema 已就绪,缺页面入口。需在 `/shell/notifications/page.tsx` 实现,供教师/学生/家长/管理员共用。
|
||||
|
||||
### 2.4 `/shell/settings`(设置,B1 共享)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\teacher\settings\page.tsx`
|
||||
- **功能描述**:用户设置页(个人资料、偏好、安全等)
|
||||
- **技术栈**:Server Component
|
||||
- **ARCHITECTURE.md 契约**:✅
|
||||
- **批次**:B1(共享)
|
||||
- **建议**:✅ 必须补做。B1 共享页,需在 `/shell/settings/page.tsx` 实现。
|
||||
|
||||
### 2.5 不算缺失的"伪缺失"(路径合并/重定向)
|
||||
|
||||
以下 CICD 路径在 portal-shell 中通过路径合并或等价入口覆盖,**不算缺失**:
|
||||
|
||||
| CICD 路径 | portal-shell 等价 | 说明 |
|
||||
| --------------------------------------- | --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `exams/page.tsx` | `/exams/page.tsx`(直接列表) | CICD 是 redirect 到 `/exams/all`,portal-shell 直接渲染列表 |
|
||||
| `exams/all/page.tsx` | `/exams/page.tsx`(ExamsListClient) | 同上,功能等价(但筛选/计数/分页有差距,见 §3.1) |
|
||||
| `exams/create/page.tsx` | `/exams/new/page.tsx`(NewExamClient) | CICD 有 `/create`(ExamForm 简单表单)+ `/new`(ExamRichForm 富文本),portal-shell 合并为 `/new`(简单表单),富文本编辑只在 `/[id]/edit`(见 §3.4) |
|
||||
| `exams/grading/page.tsx` | 无(CICD 自身是 redirect) | CICD `grading/page.tsx` 仅 `redirect("/teacher/homework/submissions")`,无实际功能 |
|
||||
| `exams/grading/[submissionId]/page.tsx` | 无(CICD 自身是 redirect) | 同上,仅 redirect |
|
||||
| `classes/page.tsx` | `/classes/page.tsx`(ClassesListClient) | CICD 是 redirect 到 `/classes/my`,portal-shell 直接渲染列表 |
|
||||
| `classes/my/page.tsx` | `/classes/page.tsx`(ClassesListClient) | 路径合并,MyClassesGrid 改为 ClassesTable(视觉差异,功能等价) |
|
||||
| `classes/my/[id]/page.tsx` | `/classes/[id]/page.tsx`(ClassDetailClient) | 路径合并,但功能差距大(见 §3.5) |
|
||||
| `classes/students/page.tsx` | `/students/page.tsx`(StudentsListClient) | 路径从 `/classes/students` 迁到顶级 `/students`(ARCH §9.1 规划),功能差距见 §3.6 |
|
||||
|
||||
---
|
||||
|
||||
## 三、功能不完整的页面
|
||||
|
||||
### 3.1 exams - 考试列表页 `/shell/teacher/exams`
|
||||
|
||||
- **路径**:`/shell/teacher/exams`
|
||||
- **portal-shell 实现**:`exams/page.tsx` + `features/teacher/exams/exams-list-client.tsx`
|
||||
- **CICD 实现**:`exams/all/page.tsx` + `exam-filters.tsx` + `ExamDataTable` + `ExamFilters`
|
||||
- **已有功能**:
|
||||
- 关键词搜索(q)、状态筛选(status)、客户端二次筛选
|
||||
- 简单表格展示(title/status/examDate/duration/totalScore/actions)
|
||||
- 状态徽章、新建按钮、EmptyState、ListPageShell 骨架
|
||||
- ✅ 真实查询 `useExams(classId)`(classId 默认 `cls-001`,MSW 兜底)
|
||||
- **缺失功能**:
|
||||
- ❌ **难度筛选**(difficulty filter)— CICD 有 difficulty 维度筛选
|
||||
- ❌ **状态计数徽章**(draft/published/archived 三个 Badge + 数字)— CICD 顶部统计栏
|
||||
- ❌ **真正的分页控件** — portal-shell 仅显示 `total: N`,无分页器;CICD `ExamDataTable` 内置分页
|
||||
- ❌ **高级 DataTable 组件** — CICD 用 `ExamDataTable`(含排序/列控制/分页),portal-shell 是手写 `<table>`
|
||||
- ❌ **EmptyState "清除筛选" action** — CICD 在有筛选时显示"清除筛选"按钮回到 `/exams/all`,portal-shell 无
|
||||
- ❌ **服务端筛选** — CICD 在 Server Component 内调 `getExams({ q, status, difficulty, scope })`,portal-shell 是客户端二次过滤
|
||||
- ❌ **DataScope 过滤** — CICD 用 `ctx.dataScope` 做权限过滤,portal-shell 无
|
||||
- **技术差距**:
|
||||
- CICD:Server Component + Drizzle `getExams` + `ExamDataTable` + `ExamFilters` 组件
|
||||
- portal-shell 需补:分页器组件、状态计数 Badge 行、difficulty 筛选 select、EmptyState clearFilters action、后续契约就绪后改服务端筛选
|
||||
|
||||
### 3.2 exams - 考试详情页 `/shell/teacher/exams/[id]`
|
||||
|
||||
- **路径**:`/shell/teacher/exams/[id]`
|
||||
- **portal-shell 实现**:`exams/[id]/page.tsx` + `features/teacher/exams/exam-detail-client.tsx`
|
||||
- **CICD 实现**:**CICD 无此页面**(CICD `/exams/[id]/` 目录下只有 analytics/build/edit-rich/proctoring 子路由,无 `page.tsx`)
|
||||
- **已有功能**:
|
||||
- ✅ 真实查询 `useExam(examId)`(schema 已就绪)
|
||||
- 基本信息区(title/description/examDate/duration/totalScore/classId/subjectId)
|
||||
- 状态信息区(currentStatus/statusChangedAt/statusChangedBy/createdBy/createdAt/updatedAt)
|
||||
- 编辑按钮(status 可编辑时显示,但 onClick 无路由跳转,**按钮无实际行为**)
|
||||
- **缺失功能**:
|
||||
- ⚠️ **编辑按钮未接路由** — `<Button variant="outline">{t("detail.edit")}</Button>` 无 `asChild` / `href` / `onClick`,点击无反应,应跳 `/shell/teacher/exams/[id]/edit`
|
||||
- 💡 **无提交列表预览** — CICD 在 homework 详情有提交列表,exam 详情可考虑加 submissions 摘要(CICD 无此页,属增量)
|
||||
- 💡 **无分析入口卡片** — 可加"查看分析"快捷入口跳 `/analytics`
|
||||
- **技术差距**:
|
||||
- 编辑按钮需补 `asChild` + `<Link href=".../edit">`
|
||||
- ARCH §9.1 规划此页为 M 详情页,portal-shell 已满足基本契约,但交互不完整
|
||||
|
||||
### 3.3 exams - 新建考试表单 `/shell/teacher/exams/new`
|
||||
|
||||
- **路径**:`/shell/teacher/exams/new`
|
||||
- **portal-shell 实现**:`exams/new/page.tsx` + `features/teacher/exams/new-exam-client.tsx`
|
||||
- **CICD 实现**:`exams/new/page.tsx`(ExamRichForm 富文本)+ `exams/create/page.tsx`(ExamForm 简单)
|
||||
- **已有功能**:
|
||||
- 简单表单:classId/subjectId/title/description/examDate/duration/totalScore
|
||||
- 内联校验(classId/title/examDate 必填)
|
||||
- ✅ mutation `useCreateExam` MSW 兜底
|
||||
- 成功后 `router.push` 回列表
|
||||
- **缺失功能**:
|
||||
- ❌ **富文本编辑器** — CICD `/exams/new` 用 `ExamRichForm`(含 Tiptap 富文本 + 题目结构),portal-shell 是纯字段表单
|
||||
- ❌ **班级/科目下拉选择器** — portal-shell 用 `<input type="text">`,CICD 应为 select(CICD ExamRichForm 内部)
|
||||
- 💡 **题目结构编辑** — CICD 富文本编辑器支持插入题目占位、分值、排序
|
||||
- **技术差距**:
|
||||
- CICD:`ExamRichForm` 客户端组件(Tiptap + 结构化节点)
|
||||
- portal-shell 把 CICD 的 `/exams/new`(rich)+ `/exams/create`(basic)合并为 `/exams/new`(basic),富文本能力下沉到 `/[id]/edit`
|
||||
- **是否补做**:取决于产品决策。若新建时即需富文本,需补 Tiptap;若新建只创建元数据、富文本在编辑页做,则当前实现可接受
|
||||
|
||||
### 3.4 exams - 富文本试卷编辑 `/shell/teacher/exams/[id]/edit`
|
||||
|
||||
- **路径**:`/shell/teacher/exams/[id]/edit`(对应 CICD `/exams/[id]/edit-rich`)
|
||||
- **portal-shell 实现**:`exams/[id]/edit/page.tsx` + `features/teacher/exams/exam-edit-client.tsx`
|
||||
- **CICD 实现**:`exams/[id]/edit-rich/page.tsx` + `ExamRichForm` + `examNodesToEditorDoc` + `structureToEditorDoc`
|
||||
- **已有功能**:
|
||||
- 三栏工作台:中栏富文本编辑器 + 右栏属性面板(examId/totalScore/questionCount/updatedAt)
|
||||
- 工具栏:B/I/U/H1/H2/H3/列表/P
|
||||
- `useExamRichEditor` + `useSaveExamRichContent` MSW 兜底
|
||||
- 保存为 HTML(`editorRef.current.innerHTML`)
|
||||
- **缺失功能**:
|
||||
- ❌ **真正的 Tiptap 编辑器** — portal-shell 用 `contentEditable` + `document.execCommand`(**deprecated**),CICD 用 Tiptap JSON 结构化文档
|
||||
- ❌ **题目结构加载** — CICD 在 Server Component 内调 `getExamById` + `getQuestions`,把 `exam.structure` + `questions` 转换为 `EditorDoc`(`examNodesToEditorDoc` + `structureToEditorDoc`),portal-shell 完全无此逻辑
|
||||
- ❌ **题目占位符插入** — CICD 富文本支持插入题目节点(含 order/options/content),portal-shell 仅纯文本 HTML
|
||||
- ❌ **服务端初始数据预加载** — CICD Server Component 预加载 exam + questions,portal-shell 纯客户端 MSW
|
||||
- ❌ **编辑模式 (mode="edit")** — CICD `ExamRichForm` 支持 create/edit 双模式,portal-shell 仅 edit
|
||||
- ⚠️ **dangerouslySetInnerHTML** — portal-shell 用 `dangerouslySetInnerHTML` 注入 HTML,违反 §4 安全规范(如必须使用,先用 DOMPurify 清洗)
|
||||
- **技术差距**:
|
||||
- CICD:Server Component + Tiptap + `examNodesToEditorDoc`/`structureToEditorDoc` 转换层 + `ExamRichForm`
|
||||
- portal-shell 需补:引入 Tiptap(或 Lexical)、编写 structure→EditorDoc 转换、Server Component 预加载、题目节点类型、DOMPurify 清洗
|
||||
|
||||
### 3.5 classes - 班级详情页 `/shell/teacher/classes/[id]`
|
||||
|
||||
- **路径**:`/shell/teacher/classes/[id]`(对应 CICD `/classes/my/[id]`)
|
||||
- **portal-shell 实现**:`classes/[id]/page.tsx` + `features/teacher/classes/class-detail-client.tsx`
|
||||
- **CICD 实现**:`classes/my/[id]/page.tsx` + 5 个 widget 组件
|
||||
- **已有功能**:
|
||||
- ✅ 真实查询 `useClassInfo(classId)`(schema 已就绪)
|
||||
- 基本信息区(name/gradeId/headTeacherId/description/createdAt/updatedAt)
|
||||
- 学生名单区(studentNo/name/enrolledAt,MSW 兜底)
|
||||
- 任课老师区(name/subjectName/role,MSW 兜底)
|
||||
- **缺失功能**:
|
||||
- ❌ **ClassHeader** — CICD 有独立头部组件(classId/name/grade/homeroom/room/schoolName/studentCount)
|
||||
- ❌ **ClassOverviewStats 概览统计** — 平均分、提交率、待批改数(papersToGrade)、逾期数(overdueCount)
|
||||
- ❌ **ClassTrendsWidget 趋势 widget** — 作业趋势列表(id/title/status/subject/isActive/isOverdue/dueAt/submittedCount/targetCount/avgScore/medianScore)
|
||||
- ❌ **ClassScheduleWidget 课表 widget** — 班级课表展示
|
||||
- ❌ **ClassAssignmentsWidget 作业 widget** — 班级作业列表
|
||||
- ❌ **学生科目成绩展示** — CICD 通过 `getClassStudentSubjectScoresV2` 拉取每个学生的科目成绩,portal-shell 学生表只有 studentNo/name/enrolledAt
|
||||
- ❌ **三栏布局** — CICD 是 2/3 主区 + 1/3 侧栏,portal-shell 是单栏 DetailSection 堆叠
|
||||
- ❌ **服务端并行数据预加载** — CICD `Promise.all([getClassHomeworkInsights, getClassStudents, getClassSchedule, getClassStudentSubjectScoresV2])`
|
||||
- **技术差距**:
|
||||
- CICD:Server Component + 4 个并行 data-access 查询 + 5 个 widget 组件 + `SectionErrorBoundary`
|
||||
- portal-shell 需补:5 个 widget 组件、4 个 data-access 查询(含 MSW 兜底)、三栏布局、概览统计计算逻辑
|
||||
|
||||
### 3.6 students - 学生列表页 `/shell/teacher/students`
|
||||
|
||||
- **路径**:`/shell/teacher/students`(对应 CICD `/classes/students`)
|
||||
- **portal-shell 实现**:`students/page.tsx` + `features/teacher/students/students-list-client.tsx`
|
||||
- **CICD 实现**:`classes/students/page.tsx` + `StudentsFilters` + `StudentsTable` + `students-filters.tsx`
|
||||
- **已有功能**:
|
||||
- 关键词搜索(q)、classId/gradeId 筛选(**纯 text input**)
|
||||
- 表格:studentNo/name/gender/className/gradeId/enrolledAt
|
||||
- 性别徽章、EmptyState、ListPageShell
|
||||
- **缺失功能**:
|
||||
- ❌ **班级下拉选择器** — CICD 用 `StudentsFilters` 组件(含 `<select>` 班级列表),portal-shell 用 `<input type="text">` 让用户手输 classId
|
||||
- ❌ **默认班级选择逻辑** — CICD 默认选中教师第一个班级(`defaultClassId = classes[0].id`),portal-shell 无默认
|
||||
- ❌ **学生科目成绩展示** — CICD 调 `getStudentsSubjectScores(studentIds)` 拉取每个学生科目成绩,`StudentsTable` 有科目成绩列,portal-shell 无
|
||||
- ❌ **服务端学生列表预加载** — CICD Server Component 调 `getClassStudents` + `getStudentsSubjectScores`,portal-shell 纯客户端 MSW
|
||||
- ❌ **状态筛选** — CICD 有 status 维度筛选(active/inactive 等),portal-shell 无
|
||||
- **技术差距**:
|
||||
- CICD:Server Component + `getTeacherClasses` + `getClassStudents` + `getStudentsSubjectScores` + `StudentsFilters`/`StudentsTable` 组件
|
||||
- portal-shell 需补:班级 select 组件、默认班级逻辑、科目成绩列、status 筛选
|
||||
|
||||
### 3.7 homework - 作业详情页 `/shell/teacher/homework/[id]`
|
||||
|
||||
- **路径**:`/shell/teacher/homework/[id]`(对应 CICD `/homework/assignments/[id]`)
|
||||
- **portal-shell 实现**:`homework/[id]/page.tsx` + `features/teacher/homework/homework-detail-client.tsx`
|
||||
- **CICD 实现**:`homework/assignments/[id]/page.tsx` + `HomeworkAssignmentQuestionErrorOverviewCard` + `HomeworkAssignmentExamContentCard`
|
||||
- **已有功能**:
|
||||
- ✅ 真实查询 `useHomework(homeworkId)`(schema 已就绪)
|
||||
- 基本信息区(title/description/dueDate/gracePeriod/status/classId/subjectId/createdBy/updatedAt)
|
||||
- 提交列表区(studentName/studentNo/status/submittedAt/totalScore/maxScore/actions,MSW 兜底)
|
||||
- 内联批改表单(studentId/score/feedback,MSW 兜底)
|
||||
- 跳转"查看所有提交"按钮 → `/homework/assignments/[id]/submissions`
|
||||
- **缺失功能**:
|
||||
- ❌ **头部统计行** — CICD 头部有 dueDate/targetCount/submissionCount/gradedCount 四个统计指标,portal-shell 无
|
||||
- ❌ **HomeworkAssignmentQuestionErrorOverviewCard 题目错误概览卡片** — CICD 用 `getHomeworkAssignmentAnalytics(id)` 拉取每题错误率,渲染分析卡片(带 Suspense + SectionErrorBoundary)
|
||||
- ❌ **HomeworkAssignmentExamContentCard 作业内容卡片** — CICD 渲染 `assignment.structure` + `questions`(含 gradedSampleCount),portal-shell 无作业内容展示
|
||||
- ❌ **服务端 analytics 预加载** — CICD 调 `getHomeworkAssignmentAnalytics(id)` 返回 `{ assignment, questions, gradedSampleCount }`
|
||||
- ❌ **流式渲染** — CICD 用 `<Suspense fallback={<AnalyticsSkeleton />}>` 包裹 analytics 卡片,portal-shell 无
|
||||
- **技术差距**:
|
||||
- CICD:Server Component + `getHomeworkAssignmentAnalytics` + 2 个分析卡片组件 + `SectionErrorBoundary` + Suspense 流式
|
||||
- portal-shell 需补:题目错误概览卡片、作业内容卡片(structure + questions 渲染)、头部统计、analytics 查询
|
||||
|
||||
### 3.8 homework - 布置作业表单 `/shell/teacher/homework/new`
|
||||
|
||||
- **路径**:`/shell/teacher/homework/new`(对应 CICD `/homework/assignments/create`)
|
||||
- **portal-shell 实现**:`homework/new/page.tsx` + `features/teacher/homework/new-homework-client.tsx`
|
||||
- **CICD 实现**:`homework/assignments/create/page.tsx` + `HomeworkAssignmentForm`
|
||||
- **已有功能**:
|
||||
- 简单表单:classId/subjectId/title/description/dueDate/gracePeriod
|
||||
- 内联校验、MSW 兜底 mutation `useAssignHomework`
|
||||
- 成功后回列表
|
||||
- **缺失功能**:
|
||||
- ❌ **关联考试选择** — CICD Server Component 调 `getExams({ scope })` 拉取考试列表,传给 `HomeworkAssignmentForm` 作下拉选项(作业可基于试卷结构生成),portal-shell 无 examId 字段
|
||||
- ❌ **班级下拉选择器** — CICD 调 `getTeacherClasses()` 拉取班级,portal-shell 用 `<input type="text">` 手输 classId
|
||||
- ❌ **EmptyState when no classes** — CICD 在 `classes.length === 0` 时显示 EmptyState 提示"无可用班级,去班级管理",portal-shell 无
|
||||
- ❌ **HomeworkAssignmentForm 富表单** — CICD 用专门组件(含 exam 关联、班级 select、可能含题目结构选择)
|
||||
- **技术差距**:
|
||||
- CICD:Server Component + `getExams` + `getTeacherClasses` + `HomeworkAssignmentForm` 组件 + EmptyState
|
||||
- portal-shell 需补:examId 字段 + 考试下拉、班级下拉、无班级 EmptyState
|
||||
|
||||
### 3.9 lesson-plans - 教案编辑工作台 `/shell/teacher/lesson-plans/[planId]/edit`
|
||||
|
||||
- **路径**:`/shell/teacher/lesson-plans/[planId]/edit`
|
||||
- **portal-shell 实现**:`lesson-plans/[planId]/edit/page.tsx` + `features/teacher/lesson-plans/lesson-plan-edit-client.tsx`
|
||||
- **CICD 实现**:`lesson-plans/[planId]/edit/page.tsx` + `LessonPlanEditor` + `LessonPlanProviderSetup` + `AiClientProvider`
|
||||
- **已有功能**:
|
||||
- 三栏工作台:左栏大纲树(LessonPlanOutlineTree)+ 中栏富文本编辑器 + 右栏属性面板(id/grade/subject/duration/status/updatedAt/resources)
|
||||
- 工具栏:B/I/U/H1/H2/H3/列表/P
|
||||
- `useLessonPlan` + `useUpdateLessonPlan` MSW 兜底
|
||||
- 保存为 HTML
|
||||
- **缺失功能**:
|
||||
- ❌ **真正的 Tiptap 编辑器** — portal-shell 用 `contentEditable` + `document.execCommand`(**deprecated**),CICD 用 `LessonPlanEditor`(Tiptap)
|
||||
- ❌ **AI 集成** — CICD 包 `<AiClientProvider service={createCoreAiClientService()}>`,支持 AI 辅助生成/润色,portal-shell 无
|
||||
- ❌ **教材/章节上下文** — CICD Server Component 调 `getTextbookById` + `getChaptersByTextbookId` + `findChapterById`,把 textbookTitle/chapterTitle 传给编辑器工具栏显示,portal-shell 无
|
||||
- ❌ **LessonPlanProviderSetup** — CICD 有专门的 Provider 设置组件(注入编辑器所需上下文),portal-shell 无
|
||||
- ❌ **服务端初始数据预加载** — CICD Server Component 预加载 plan + teacherClasses + textbook + chapter,portal-shell 纯客户端 MSW
|
||||
- ❌ **班级关联** — CICD 加载 `getTeacherClasses({ teacherId })` 传给编辑器(教案可关联班级),portal-shell 无
|
||||
- ⚠️ **dangerouslySetInnerHTML** — 同 §3.4,违反 §4 安全规范
|
||||
- **技术差距**:
|
||||
- CICD:Server Component + Tiptap + AiClientProvider + LessonPlanProviderSetup + 4 个 data-access 查询
|
||||
- portal-shell 需补:Tiptap、AiClientProvider 接入、教材/章节加载、Provider 设置、班级关联、DOMPurify 清洗
|
||||
|
||||
### 3.10 grades - 成绩录入页 `/shell/teacher/grades/entry`
|
||||
|
||||
- **路径**:`/shell/teacher/grades/entry`
|
||||
- **portal-shell 实现**:`grades/entry/page.tsx` + `features/teacher/grades/grade-entry-client.tsx`
|
||||
- **CICD 实现**:`grades/entry/page.tsx` + `BatchGradeEntryByExam` 组件
|
||||
- **已有功能**:
|
||||
- **单学生单次录入**表单:classId/studentId/examId/homeworkId/score/totalScore/feedback
|
||||
- 内联校验、MSW 兜底 mutation `useCreateGrade`
|
||||
- **缺失功能**:
|
||||
- ❌ **批量录入** — CICD 用 `BatchGradeEntryByExam` 组件,按考试批量录入全班成绩(一次选 exam + class,列出所有学生,逐题/逐生录入),portal-shell 是单生单次
|
||||
- ❌ **考试下拉选择器** — CICD 调 `getExamsForGradeEntry(ctx.dataScope)` 拉取可录入成绩的考试列表,portal-shell 用 `<input type="text">` 手输 examId
|
||||
- ❌ **班级下拉选择器** — CICD 调 `getTeacherClasses()` + scope 过滤 + `getClassGradeIdsByClassIds` 构建 classGradeMap(用于按试卷年级过滤班级),portal-shell 手输 classId
|
||||
- ❌ **学生列表预加载** — CICD 调 `getClassStudentsForEntry(classId, ctx.dataScope)` 拉取班级学生,portal-shell 手输 studentId
|
||||
- ❌ **考试题目列表** — CICD 调 `getExamForGradeEntry(examId, ctx.dataScope)` 返回试卷详情含题目,支持按题录入
|
||||
- ❌ **DataScope 过滤** — CICD 用 `ctx.dataScope.type === "class_taught"` 过滤班级,portal-shell 无权限过滤
|
||||
- ❌ **EmptyState when no exams** — CICD 在 `exams.length === 0` 时显示 EmptyState
|
||||
- ❌ **按试卷年级过滤班级** — CICD 用 classGradeMap 客户端过滤
|
||||
- **技术差距**:
|
||||
- CICD:Server Component + 4 个 data-access 查询 + `BatchGradeEntryByExam` 客户端组件 + DataScope
|
||||
- portal-shell 需补:批量录入组件、考试/班级下拉、学生列表、题目列表、scope 过滤、EmptyState
|
||||
|
||||
### 3.11 attendance - 考勤点名表 `/shell/teacher/attendance/sheet`
|
||||
|
||||
- **路径**:`/shell/teacher/attendance/sheet`
|
||||
- **portal-shell 实现**:`attendance/sheet/page.tsx` + `features/teacher/attendance/attendance-sheet-client.tsx`
|
||||
- **CICD 实现**:`attendance/sheet/page.tsx` + `AttendanceSheet` 组件
|
||||
- **已有功能**:
|
||||
- classId(**text input**)+ date 选择
|
||||
- 学生表格(studentName/status 按钮组/remark)
|
||||
- 4 种状态:PRESENT/ABSENT/LATE/LEAVE,点击切换
|
||||
- MSW 兜底 `useAttendanceSheet` + `useSaveAttendanceSheet`
|
||||
- 保存后回列表
|
||||
- **缺失功能**:
|
||||
- ❌ **班级下拉选择器** — CICD Server Component 调 `getTeacherClasses()` 拉取班级,传给 `AttendanceSheet` 组件作下拉,portal-shell 用 `<input type="text">` 手输 classId
|
||||
- ❌ **服务端学生列表预加载** — CICD 调 `getClassStudentsForAttendance(defaultClassId)` 服务端预加载学生,portal-shell 完全依赖 MSW mock
|
||||
- ❌ **AttendanceSheet 组件** — CICD 有专门的客户端组件(含班级切换、日期选择、批量标记、统计汇总),portal-shell 是手写表格
|
||||
- **技术差距**:
|
||||
- CICD:Server Component + `getTeacherClasses` + `getClassStudentsForAttendance` + `AttendanceSheet` 客户端组件
|
||||
- portal-shell 需补:班级 select、服务端学生预加载、AttendanceSheet 组件
|
||||
|
||||
### 3.12 diagnostic - 班级诊断详情 `/shell/teacher/diagnostic/class/[classId]`
|
||||
|
||||
- **路径**:`/shell/teacher/diagnostic/class/[classId]`
|
||||
- **portal-shell 实现**:`diagnostic/class/[classId]/page.tsx` + `features/teacher/diagnostic/diagnostic-class-detail-client.tsx`
|
||||
- **CICD 实现**:`diagnostic/class/[classId]/page.tsx` + `ClassDiagnosticView` + `DiagnosticServiceProvider` + `DiagnosticMonitorProvider`
|
||||
- **已有功能**:
|
||||
- 基本信息区(title/reportType/status/className/studentCount/avgScore/summary/generatedAt)
|
||||
- 薄弱知识点表格(kpTitle/mastery/errorCount)
|
||||
- 教学建议列表(recommendations)
|
||||
- MSW 兜底 `useDiagnosticReport(classId)`
|
||||
- **缺失功能**:
|
||||
- ❌ **ClassDiagnosticView 富视图组件** — CICD 用专门的 `ClassDiagnosticView`(含掌握度雷达图、知识点 drill-down、学生分布等丰富交互),portal-shell 是基础详情页
|
||||
- ❌ **DiagnosticServiceProvider** — CICD 注入诊断服务上下文(支持客户端 drill-down 查询),portal-shell 无
|
||||
- ❌ **DiagnosticMonitorProvider + 监控埋点** — CICD 用 `createMonitoredDiagnosticService(defaultDiagnosticService, noopDiagnosticMonitor)` 包装服务,支持生产环境监控注入,portal-shell 无
|
||||
- ❌ **服务端数据预加载** — CICD Server Component 调 `getClassMasterySummary(classId)` 预加载,portal-shell 纯客户端 MSW
|
||||
- ❌ **DataScope 校验** — CICD 校验 `class_taught` scope(教师只能查所教班级),拒绝 `class_members`/`children` scope,portal-shell 无
|
||||
- ❌ **WidgetBoundary** — CICD 用 `WidgetBoundary` 包裹(局部降级),portal-shell 用 DetailPageShell
|
||||
- **技术差距**:
|
||||
- CICD:Server Component + `getClassMasterySummary` + `ClassDiagnosticView` + Diagnostic Service Provider/Monitor + DataScope
|
||||
- portal-shell 需补:ClassDiagnosticView 组件、DiagnosticServiceProvider/MonitorProvider、服务端预加载、DataScope 校验、WidgetBoundary
|
||||
|
||||
### 3.13 dashboard - 教师仪表盘 `/shell/teacher`(teacher/page.tsx)
|
||||
|
||||
- **路径**:`/shell/teacher`(根教师页)
|
||||
- **portal-shell 实现**:`shell/teacher/page.tsx`("use client")
|
||||
- **CICD 实现**:`dashboard/page.tsx`(Server Component)+ `TeacherDashboardView`
|
||||
- **已有功能**:
|
||||
- 4 StatCard(total_classes/total_students/class_avg_score/pending_homework_count)
|
||||
- 班级概况区(class_name/student_count/average_score)
|
||||
- 近期预警区(target_name/severity/warning_type/current_value/threshold)
|
||||
- ✅ 真实查询 `useTeacherDashboard`(data-ana 聚合查询)
|
||||
- loading/error 三态处理
|
||||
- **缺失功能**:
|
||||
- ⚠️ **i18n 硬编码** — portal-shell 标题/描述用硬编码中文(`"教师仪表盘"`、`"今日教学概览"`、`"班级总数"` 等),违反 §3.10 设计令牌规范的 i18n 要求,应改 `useTranslations("dashboard")`,CICD 用 `getTranslations("dashboard")`
|
||||
- ❌ **流式渲染** — CICD Server Component 用 `getTeacherDashboardAction()` 返回未解析 Promise + `<TeacherDashboardView dataPromise={...}>`,视图内 `use()` 消费 + Suspense 流式渲染,portal-shell 是客户端整体 loading
|
||||
- ❌ **TeacherDashboardView 富视图** — CICD 用专门的 `TeacherDashboardView` 组件(可能含更多 widget:课表/作业/考试/学生预警等),portal-shell 仅 4 StatCard + 2 简单列表
|
||||
- ❌ **更多 widget** — CICD 可能含课表、作业待批、考试安排、学生预警等 widget(需读 TeacherDashboardView 确认),portal-shell 仅基础展示
|
||||
- **技术差距**:
|
||||
- CICD:Server Component + Server Action + Suspense 流式 + `TeacherDashboardView` 组件
|
||||
- portal-shell 需补:i18n 化、TeacherDashboardView 组件、流式渲染、更多 widget(待确认)
|
||||
|
||||
### 3.14 classes - 班级列表页 `/shell/teacher/classes`(轻量不完整)
|
||||
|
||||
- **路径**:`/shell/teacher/classes`
|
||||
- **portal-shell 实现**:`classes/page.tsx` + `features/teacher/classes/classes-list-client.tsx`
|
||||
- **CICD 实现**:`classes/my/page.tsx` + `MyClassesGrid` 组件
|
||||
- **已有功能**:
|
||||
- ✅ 真实查询 `useClasses({ gradeId, subjectId, q })`(MSW 兜底)
|
||||
- 三筛选(q/gradeId/subjectId)、表格(name/grade/headTeacher/studentCount/subjectCount/description/updatedAt/actions)
|
||||
- EmptyState、ListPageShell
|
||||
- **缺失功能**:
|
||||
- ⚠️ **MyClassesGrid 卡片网格视图** — CICD 用 `MyClassesGrid` 组件(卡片式展示),portal-shell 用表格,视觉差异(功能等价,不算重大缺失)
|
||||
- ⚠️ **subjectOptions 预加载** — CICD 调 `getClassSubjects()` 拉取科目选项作下拉,portal-shell 用 text input
|
||||
- ⚠️ **SectionErrorBoundary** — CICD 用 `SectionErrorBoundary` 包裹,portal-shell 用 errorNode
|
||||
- **技术差距**:较小,主要是视觉/组件差异,功能基本等价
|
||||
|
||||
### 3.15 exams - 试卷组卷工作台 `/shell/teacher/exams/[id]/build`
|
||||
|
||||
- **路径**:`/shell/teacher/exams/[id]/build`
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\teacher\exams\[id]\build\page.tsx` + 同目录 `error.tsx` + `loading.tsx`
|
||||
- **功能描述**:试卷组卷工作台,CICD 为 Server Component 入口(`export const dynamic = "force-dynamic"`):
|
||||
- `requirePermission(Permissions.EXAM_READ)` 权限校验,拿到 `ctx.dataScope`
|
||||
- `getExamById(id, ctx.dataScope)` 拉取考试元数据(含 `questions` + `structure`),不存在则 `notFound()`
|
||||
- `Promise.all` 并行拉取题库前 20 条(`getQuestions({ pageSize: 20 })`)+ 已选题目详情(`getQuestions({ ids: selectedQuestionIds })`)
|
||||
- `questionOptionsById` Map 去重合并 bank + selected 题目为 `questionOptions`
|
||||
- `normalizeStructure(exam.structure)` 把 `exam.structure` 规范化为 `ExamNode[]` 树(支持嵌套分组节点)
|
||||
- structure 空但 `initialSelected` 非空时回退为扁平节点列表(用 `@paralleldrive/cuid2` `createId()` 生成节点 ID)
|
||||
- `createCoreAiClientService()` 创建 AI 服务,`<AiClientProvider>` 注入 AI 上下文
|
||||
- 渲染 `<ExamAssembly>` 富组件(位于 `modules/exams/components/exam-assembly`),透传 examId/title/subject/grade/difficulty/totalScore/durationMin + initialSelected + initialStructure + questionOptions
|
||||
- 配套 `error.tsx`(`useErrorReport` 错误上报 + `EmptyState` + retry 按钮)+ `loading.tsx`(3 栏 Skeleton,`lg:grid-cols-3` 2+1 布局)
|
||||
- **技术栈**:Next.js App Router Server Component(`force-dynamic`)+ next-intl `getTranslations("examHomework.exam.build")` + `requirePermission` + `Permissions.EXAM_READ` + `ctx.dataScope` 数据范围过滤 + Drizzle data-access(`getExamById` / `getQuestions`)+ `normalizeStructure` 转换层 + `@paralleldrive/cuid2` + AI 集成(`AiClientProvider` + `createCoreAiClientService`)+ `ExamAssembly` 客户端组件 + 专用 error/loading 边界
|
||||
- **ARCHITECTURE.md 契约**:❌(B2)— portal-shell `page.tsx` 注释明确 `@contract-pending`:`examBuild(examId)` / `questionsLibrary(filter)` / `saveExamBuild(input)` 三个根字段均不存在,全 MSW 兜底
|
||||
- **portal-shell 现状**:
|
||||
- `page.tsx` 仅 `<Suspense fallback={<WorkbenchPageSkeleton />}>` 包裹 `ExamBuildClient`,**无服务端预加载、无权限守卫、无 notFound**
|
||||
- `ExamBuildClient` 纯客户端,使用 `useExamBuild` / `useQuestionsLibrary` / `useSaveExamBuild` 三个 Apollo hook(全 MSW 兜底)
|
||||
- `WorkbenchPageShell` 三栏布局:左 `QuestionsLibraryPanel` / 中 `SelectedQuestionsPanel` / 右 `PreviewPanel`
|
||||
- 左栏:q 关键词 + type 下拉 + difficulty 下拉筛选 + 题目列表 + 添加按钮(`Plus` 图标)+ 总数显示
|
||||
- 中栏:已选题目列表,支持上移/下移(`↑`/`↓`)/编辑分值(`Input type="number"`)/移除(`Trash2`)
|
||||
- 右栏:总分(含 baseline 差值 ± 提示,amber/destructive 配色)+ 及格分 + 题型分布(`countByType`)
|
||||
- 本地 `useState<ExamBuildNode[] | null>` 管理 selected,`useEffect` 在 data 首次就绪时初始化(`sortBySortOrder`)
|
||||
- 保存 mutation `useSaveExamBuild` + `notify.success/error` 反馈
|
||||
- 三态合并到 `errorNode`(error + empty 共用降级节点)
|
||||
- **无专用 error.tsx / loading.tsx 文件**
|
||||
- **缺失功能**:
|
||||
- ❌ **Server Component 数据预加载** — CICD 在服务端并行 `Promise.all` 拉取 exam + bank questions + selected questions,portal-shell 完全依赖客户端 MSW
|
||||
- ❌ **DataScope 权限过滤** — CICD 用 `ctx.dataScope` 过滤考试可见性,portal-shell 无
|
||||
- ❌ **`requirePermission(Permissions.EXAM_READ)` 权限守卫** — portal-shell 无
|
||||
- ❌ **`notFound()` 404 处理** — CICD 考试不存在时调 `notFound()`,portal-shell 显示空态节点
|
||||
- ❌ **AI 集成** — CICD 包 `<AiClientProvider service={createCoreAiClientService()}>` 支持 AI 辅助组卷,portal-shell 无 AI 接入(与 §3.9 教案编辑同类型缺失,见 §六 共性技术债 6)
|
||||
- ❌ **`normalizeStructure` 转换层** — CICD 把 `exam.structure` 规范化为 `ExamNode[]` 树(支持嵌套分组节点),portal-shell 用扁平 `ExamBuildNode[]`,无结构化分组能力
|
||||
- ❌ **structure 空时回退逻辑** — CICD 在 structure 空但 `initialSelected` 非空时回退为扁平节点列表(cuid2 生成 ID),portal-shell 无此兼容
|
||||
- ❌ **`ExamAssembly` 富组件** — CICD 用专门的 `ExamAssembly` 组件(`modules/exams/components/exam-assembly`),portal-shell 是手写 3 个 Panel 函数
|
||||
- ❌ **questionOptions 去重合并** — CICD 把 bank + selected 题目通过 Map 去重合并为 `questionOptions` 传给组件,portal-shell 左右栏分别查询、无合并
|
||||
- ❌ **专用 error.tsx** — CICD 有 `error.tsx`(`useErrorReport` 上报 + `EmptyState` + retry 按钮),portal-shell 用 `WorkbenchPageShell.errorNode` 整页降级,无错误上报
|
||||
- ❌ **专用 loading.tsx** — CICD 有 3 栏 Skeleton(`lg:grid-cols-3` 2+1 布局),portal-shell 用通用 `WorkbenchPageSkeleton`
|
||||
- ❌ **`dynamic = "force-dynamic"`** — CICD 强制动态渲染(权限相关数据不能静态化),portal-shell 默认
|
||||
- ⚠️ **i18n 命名空间差异** — CICD 用 `examHomework.exam.build`,portal-shell 用 `exams`,需对齐
|
||||
- ⚠️ **exam 元数据透传** — CICD 把 subject/grade/difficulty/durationMin 传给 `ExamAssembly` 展示,portal-shell 不展示这些上下文
|
||||
- **建议**:
|
||||
1. **短期(契约未就绪)**:保留 MSW 兜底;补 `error.tsx`(`useErrorReport` + EmptyState + retry)+ `loading.tsx`(3 栏 Skeleton);i18n 命名空间与 CICD 对齐(或保留 `exams` 但与 ARCH §11 一致)
|
||||
2. **中期(契约就绪后)**:
|
||||
- 改造为 Server Component,并行预加载 exam + questions(bank + selected)
|
||||
- 引入 `requirePermission` + `ctx.dataScope` 过滤
|
||||
- 实现 `normalizeStructure` 转换层,支持嵌套 `ExamNode` 树(与 CICD 对齐)
|
||||
- 引入 `AiClientProvider` + `createCoreAiClientService`,接入 AI 辅助组卷
|
||||
- 抽取 `ExamAssembly` 富组件,统一 3 栏 UI 与 CICD 对齐
|
||||
- questionOptions 去重合并,减少客户端重复查询
|
||||
3. **长期**:与 §3.4(exams/[id]/edit 富文本)+ §3.9(lesson-plans edit)统一引入 Tiptap + AI 集成方案(见 §六 共性技术债 1/2/6)
|
||||
|
||||
---
|
||||
|
||||
## 四、按模块汇总
|
||||
|
||||
| 模块 | ARCH 规划 | portal-shell 已实现 | ✅ 完整 | 🟡 不完整 | ❌ 缺失 | 备注 |
|
||||
| ---------------- | --------- | ------------------- | -------------- | --------------------- | --------------- | ----------------------------------------------------------------------------------- |
|
||||
| dashboard | 1 | 1 | 0 | 1(§3.13) | 0 | i18n 硬编码 + 缺流式 + 缺富视图 |
|
||||
| exams | 7 | 6 | 1(analytics) | 4(§3.1/3.2/3.3/3.4) | 1(proctoring) | build 列入🟡但功能基本完整,缺 AI |
|
||||
| homework | 7 | 7 | 5 | 2(§3.7/3.8) | 0 | 详情缺分析卡片,新建缺考试关联 |
|
||||
| grades | 5 | 5 | 4 | 1(§3.10) | 0 | entry 缺批量录入 |
|
||||
| lesson-plans | 6 | 6 | 5 | 1(§3.9) | 0 | edit 缺 Tiptap + AI + 教材章节 |
|
||||
| questions | 1 | 1 | 1 | 0 | 0 | — |
|
||||
| textbooks | 2 | 2 | 2 | 0 | 0 | — |
|
||||
| attendance | 4 | 4 | 3 | 1(§3.11) | 0 | sheet 缺班级下拉 + 学生预加载 |
|
||||
| classes | 3 | 3 | 1(schedule) | 2(§3.5/3.14) | 0 | [id] 缺 5 个 widget,list 轻量差异 |
|
||||
| students | 1 | 1 | 0 | 1(§3.6) | 0 | 缺下拉 + 科目成绩 |
|
||||
| course-plans | 2 | 2 | 2 | 0 | 0 | — |
|
||||
| elective | 3 | 3 | 3 | 0 | 0 | — |
|
||||
| error-book | 1 | 1 | 1 | 0 | 0 | — |
|
||||
| diagnostic | 2 | 2 | 1(list) | 1(§3.12) | 0 | class/[classId] 缺富视图 + 服务上下文 |
|
||||
| analytics | 2 | 2 | 2 | 0 | 0 | ARCH 新建,MSW 兜底 |
|
||||
| ai | 3 | 3 | 3 | 0 | 0 | ARCH 新建 B2末,全 MSW |
|
||||
| knowledge-graph | 1 | 1 | 1 | 0 | 0 | ARCH 新建 B2末 |
|
||||
| practice | 1 | 1 | 1 | 0 | 0 | — |
|
||||
| schedule-changes | 1 | 1 | 1 | 0 | 0 | — |
|
||||
| leave | 1 | 1 | 1 | 0 | 0 | — |
|
||||
| notifications | 1(共享) | 0 | 0 | 0 | 1(§2.3) | B1 共享,schema ✅ |
|
||||
| settings | 1(共享) | 0 | 0 | 0 | 1(§2.4) | B1 共享 |
|
||||
| **合计** | **56** | **53** | **33** | **14** | **4** | 另:CICD 历史功能 `diagnostic/student/[studentId]` 未在 ARCH 规划,建议补做(§2.2) |
|
||||
|
||||
---
|
||||
|
||||
## 五、优先级建议
|
||||
|
||||
### P0(B1 共享,必须补,schema 已就绪)
|
||||
|
||||
1. `/shell/notifications` — B1 共享,`notifications(userId)` ✅
|
||||
2. `/shell/settings` — B1 共享
|
||||
|
||||
### P1(B2末 规划页,必须补)
|
||||
|
||||
3. `/shell/teacher/exams/[id]/proctoring` — B2末,WS 二期,需先定 WS 契约
|
||||
|
||||
### P2(CICD 历史功能,建议补,需同步更新 ARCH §9.1)
|
||||
|
||||
4. `/shell/teacher/diagnostic/student/[studentId]` — 学生诊断雷达图,CICD 已有完整实现
|
||||
|
||||
### P3(功能不完整页,按业务优先级补)
|
||||
|
||||
**高优先级(核心教学场景,差距大)**:5. `classes/[id]` 班级详情 — 缺 5 个 widget(概览/趋势/课表/作业/学生科目成绩),班级是教师核心工作台6. `homework/[id]` 作业详情 — 缺分析卡片 + 内容卡片,作业是高频场景 7. `grades/entry` 成绩录入 — 缺批量录入,单生录入效率太低 8. `lesson-plans/[planId]/edit` 教案编辑 — 缺 Tiptap + AI,contentEditable deprecated 不可长期维护
|
||||
|
||||
**中优先级(交互不完整,影响体验)**:9. `students` 学生列表 — 缺下拉 + 科目成绩 10. `homework/new` 布置作业 — 缺考试关联 + 班级下拉 11. `attendance/sheet` 考勤点名 — 缺班级下拉 + 学生预加载 12. `diagnostic/class/[classId]` 班级诊断 — 缺富视图 + 服务上下文 13. `exams/[id]/edit` 富文本编辑 — 缺 Tiptap + 题目结构(与 §3.9 教案编辑同类型问题,建议统一升级 Tiptap)14. `exams` 列表 — 缺筛选/计数/分页/DataTable
|
||||
|
||||
**低优先级(功能基本可用,细节差距)**:15. `exams/[id]` 详情 — 编辑按钮未接路由(小修)16. `exams/new` 新建考试 — 是否补富文本取决于产品决策 17. `classes` 列表 — 视觉差异,功能等价 18. `dashboard` 仪表盘 — i18n 化 + 流式渲染(i18n 应立即修,违反 §3.10)
|
||||
|
||||
---
|
||||
|
||||
## 六、共性技术债
|
||||
|
||||
1. **Tiptap 缺失**:`exams/[id]/edit`、`lesson-plans/[planId]/edit` 均用 `contentEditable` + `document.execCommand`(deprecated),CICD 用 Tiptap。建议统一引入 Tiptap(或 Lexical),编写 structure→EditorDoc 转换层。
|
||||
2. **dangerouslySetInnerHTML 违规**:上述两个富文本页直接 `dangerouslySetInnerHTML`,违反 §4 安全规范,需 DOMPurify 清洗。
|
||||
3. **下拉选择器缺失**:`students`/`homework/new`/`grades/entry`/`attendance/sheet` 等多处用 `<input type="text">` 替代 `<select>`,需补 data-access 查询 + select 组件。
|
||||
4. **DataScope 校验缺失**:portal-shell 普遍无 `ctx.dataScope` 权限过滤(CICD 在 Server Component 内做 scope 过滤),需在后端契约就绪后补。
|
||||
5. **Server Component 预加载缺失**:CICD 多个详情页在 Server Component 内并行预加载多个数据源,portal-shell 纯客户端 MSW,等契约就绪后需改 Server Component 预加载 + Suspense 流式。
|
||||
6. **AI 集成缺失**:`exams/[id]/build`、`lesson-plans/[planId]/edit` 在 CICD 有 `AiClientProvider` + `createCoreAiClientService`,portal-shell 无 AI 接入。
|
||||
7. **i18n 硬编码**:`dashboard` 用硬编码中文,应全面 `useTranslations`。
|
||||
8. **SectionErrorBoundary / WidgetBoundary 缺失**:CICD 多处用 `SectionErrorBoundary`/`WidgetBoundary` 做局部降级,portal-shell 用 errorNode 整页降级,粒度较粗。
|
||||
|
||||
---
|
||||
|
||||
## 七、参考文件索引
|
||||
|
||||
### CICD 参考实现
|
||||
|
||||
- `e:\desktop\CICD\src\app\(dashboard)\teacher\` — 教师域 53 页源
|
||||
- `e:\desktop\CICD\src\modules\exams\components\exam-rich-form.tsx` — 富文本试卷表单
|
||||
- `e:\desktop\CICD\src\modules\exams\components\exam-assembly.tsx` — 组卷工作台
|
||||
- `e:\desktop\CICD\src\modules\classes\components\class-detail\` — 班级详情 5 个 widget
|
||||
- `e:\desktop\CICD\src\modules\classes\components\my-classes-grid.tsx` — 班级网格
|
||||
- `e:\desktop\CICD\src\modules\classes\components\students-table.tsx` — 学生表
|
||||
- `e:\desktop\CICD\src\modules\homework\components\homework-assignment-question-error-overview-card.tsx` — 作业错误概览
|
||||
- `e:\desktop\CICD\src\modules\homework\components\homework-assignment-exam-content-card.tsx` — 作业内容卡片
|
||||
- `e:\desktop\CICD\src\modules\grades\components\batch-grade-entry.tsx` — 批量录入
|
||||
- `e:\desktop\CICD\src\modules\lesson-preparation\components\lesson-plan-editor.tsx` — 教案编辑器
|
||||
- `e:\desktop\CICD\src\modules\diagnostic\components\class-diagnostic-view.tsx` — 班级诊断视图
|
||||
- `e:\desktop\CICD\src\modules\diagnostic\components\student-diagnostic-view.tsx` — 学生诊断视图
|
||||
- `e:\desktop\CICD\src\modules\proctoring\components\proctoring-dashboard.tsx` — 监考面板
|
||||
- `e:\desktop\CICD\src\modules\dashboard\components\teacher-dashboard\teacher-dashboard-view.tsx` — 仪表盘视图
|
||||
|
||||
### portal-shell 当前实现
|
||||
|
||||
- `e:\Desktop\Edu\apps\portal-shell\src\app\shell\teacher\` — 教师域 53 页
|
||||
- `e:\Desktop\Edu\apps\portal-shell\src\features\teacher\` — 51 个 `*-client.tsx` + 辅助组件
|
||||
- `e:\Desktop\Edu\apps\portal-shell\src\lib\api\` — Apollo hooks(含 MSW 兜底)
|
||||
- `e:\Desktop\Edu\apps\portal-shell\src\shared\components\page-templates\` — ListPageShell/FormPageShell/DetailPageShell/WorkbenchPageShell
|
||||
- `e:\Desktop\Edu\apps\portal-shell\ARCHITECTURE.md` §9.1 — 教师域 56 页规划
|
||||
|
||||
### 契约工单
|
||||
|
||||
- `docs/architecture/issues/contracts/core-edu_contract.md` — exams/homework/grades/questions mutation 工单
|
||||
- `docs/architecture/issues/contracts/classes_contract.md` — classes/students/attendance 工单
|
||||
- `docs/architecture/issues/contracts/data-ana_contract.md` — diagnostic/analytics 工单
|
||||
|
||||
---
|
||||
|
||||
**分析完成。下一步建议按 §五 优先级逐项补做,每补一页同步更新 ARCH §9.1 状态 + 004 + arch.db。**
|
||||
Reference in New Issue
Block a user