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:
332
apps/portal-shell/docs/needtodo/management-grade-NeedTodo.md
Normal file
332
apps/portal-shell/docs/needtodo/management-grade-NeedTodo.md
Normal file
@@ -0,0 +1,332 @@
|
||||
# 年级组域(Management/Grade)待完成功能分析
|
||||
|
||||
> 参考项目:`e:\desktop\CICD\src\app\(dashboard)\management\grade\`(5 个 page.tsx)
|
||||
> 当前项目:`e:\Desktop\Edu\apps\portal-shell\`(**无对应页面,全部缺失**)
|
||||
> 规划依据:`apps\portal-shell\ARCHITECTURE.md` §9.5 缺口新增(5 页,B2/B5 末 N)
|
||||
> 分析日期:2026-07-24
|
||||
> 分析方式:逐页面读取 CICD page.tsx 源码 + 检查 portal-shell 对应路由是否存在
|
||||
|
||||
---
|
||||
|
||||
## 〇、方法论与对比基线
|
||||
|
||||
1. CICD 单体(Next.js App Router + Server Actions + Drizzle)作为**功能基线**,反映"老版单体已实现"的年级组功能完整态。
|
||||
2. portal-shell 作为**目标态**,遵循 ARCH §9.5 的"缺口新增"规划(B2/B5 末,N=新建)。
|
||||
3. CICD 的 5 个页面位于 `(dashboard)/management/grade/` 顶级路由组下,**不属于 /teacher 也不属于 /admin**,是独立的"年级组管理"维度,按 `GRADE_MANAGE` / `GRADE_RECORD_READ` / `ADAPTIVE_PRACTICE_READ` 三类权限放行。
|
||||
4. CICD 的 `navigation.ts` 显示该菜单组同时出现在 `teacher` 与 `grade_head` 两个角色的导航中(permission 均为 `Permissions.GRADE_MANAGE`),即"年级组长"既可以是带 `grade_head` 角色的独立账号,也可以是普通教师被授予 `GRADE_MANAGE` 权限。
|
||||
5. portal-shell 现有目录结构仅含 `/shell/{teacher|admin|student|parent|dev|forbidden}/*`,**未规划 `/shell/management/*` 独立段**,且 `route-permissions.ts` 中无任何 `management/grade` 条目。
|
||||
6. ARCH §9.5 表格仅以"缺口新增"一行汇总 10 页(5 grade + 5 register/onboarding/privacy/terms),未细化每页的目标路由与契约;本文档补充细化。
|
||||
|
||||
---
|
||||
|
||||
## 一、页面完成度总览
|
||||
|
||||
| 状态 | 数量 | 说明 |
|
||||
| ------- | ---- | -------------------------------------- |
|
||||
| ❌ 缺失 | 5 | 5 个页面在 portal-shell 中均无对应实现 |
|
||||
| 🟡 部分 | 0 | — |
|
||||
| ✅ 完成 | 0 | — |
|
||||
|
||||
> portal-shell 路径检查:`apps/portal-shell/src/app/shell/**/management/**` 与 `apps/portal-shell/src/app/shell/**/grade/**` Glob 均返回 "No file found"。`route-permissions.ts` 亦无 `management` / `grade` 关键字命中。
|
||||
|
||||
---
|
||||
|
||||
## 二、缺失页面清单
|
||||
|
||||
### 2.1 年级组入口重定向(page.tsx)
|
||||
|
||||
- **CICD 路径**:`e:\desktop\CICD\src\app\(dashboard)\management\grade\page.tsx`
|
||||
- **建议目标路由**:`/shell/teacher/management/grade`(见 §三角色归属分析)
|
||||
- **功能描述**:空页面入口,仅做权限校验与重定向:
|
||||
- `await requirePermission(Permissions.GRADE_MANAGE)` — 校验年级管理权限
|
||||
- `redirect("/management/grade/classes")` — 重定向到班级列表页
|
||||
- **技术栈**:
|
||||
- Next.js `redirect` (from `next/navigation`)
|
||||
- `requirePermission` 共享鉴权工具(`@/shared/lib/auth-guard`)
|
||||
- `Permissions.GRADE_MANAGE` 权限位(`grade:manage`)
|
||||
- `export const dynamic = "force-dynamic"` — 强制动态渲染(避免静态缓存鉴权信息)
|
||||
- **权限**:`GRADE_MANAGE`(`grade:manage`)— 年级组长专属权限
|
||||
- **ARCHITECTURE.md 契约**:❌(§9.5 缺口新增,无 GraphQL schema)
|
||||
- **批次**:B2/B5 末(N)
|
||||
|
||||
### 2.2 年级组仪表盘(dashboard)
|
||||
|
||||
- **CICD 路径**:`e:\desktop\CICD\src\app\(dashboard)\management\grade\dashboard\page.tsx`
|
||||
- **建议目标路由**:`/shell/teacher/management/grade/dashboard`
|
||||
- **功能描述**:年级组长仪表盘,包含 4 个 Tab 切换的概览面板:
|
||||
- **年级筛选器**(FilterBar + ChipNav):拉取 `getGradesForStaff(teacherId)` 得到该教师可见年级列表,URL `?gradeId=xxx` 即时切换,无整页刷新
|
||||
- **Tab distribution(成绩分布)**:调用 `getGradeDistributionByGradeId({ gradeId, scope: ctx.dataScope })`,渲染 `GradeDistributionPanel`
|
||||
- **Tab homework(作业洞察)**:调用 `getGradeHomeworkInsights({ gradeId, limit: 50 })`,渲染 `GradeHomeworkPanel`
|
||||
- **Tab exams(考试列表)**:调用 `getExamsByGradeId({ gradeId, scope: ctx.dataScope })`,渲染 `GradeExamsPanel`
|
||||
- **Tab progress(课程计划进度)**:调用 `getGradeCoursePlanProgress({ gradeId })`,渲染 `GradeProgressPanel`
|
||||
- **懒加载策略**:仅渲染当前激活 Tab 的数据(按 `tab` 参数选择性 fetch),其他 Tab 不预取
|
||||
- **空状态**:无可见年级 / 未选年级 / 数据为 null 三种 EmptyState 兜底
|
||||
- **错误边界**:`SectionErrorBoundary` 包裹面板区域(namespace="school")
|
||||
- **技术栈**:
|
||||
- Server Component(`force-dynamic`)+ `generateMetadata` 动态标题(i18n `school.grades.gradeDashboard.*`)
|
||||
- `next-intl/server` 的 `getTranslations`
|
||||
- `getParam` / `SearchParams` 工具(`@/shared/lib/search-params`)
|
||||
- 跨模块数据访问:`classes` / `school` / `grades` / `exams` / `course-plans` 5 个模块的 `data-access`
|
||||
- 共享 UI:`FilterBar`、`ChipNav`、`EmptyState`、`SectionErrorBoundary`
|
||||
- 业务组件:`modules/school/components/grade-dashboard/grade-{distribution,homework,exams,progress}-panel`
|
||||
- DataScope 二次过滤:`ctx.dataScope` 传入查询,按教师可见范围过滤
|
||||
- **权限**:`GRADE_RECORD_READ`(`grade_record:read`)— 比入口权限宽松,允许只读查看成绩的教师访问
|
||||
- **ARCHITECTURE.md 契约**:❌(5 个 data-access 全部走 Drizzle 直查 DB,未走 GraphQL schema)
|
||||
- **批次**:B2/B5 末(N)
|
||||
|
||||
### 2.3 年级组班级列表(classes)
|
||||
|
||||
- **CICD 路径**:`e:\desktop\CICD\src\app\(dashboard)\management\grade\classes\page.tsx`
|
||||
- **建议目标路由**:`/shell/teacher/management/grade/classes`
|
||||
- **功能描述**:年级组长管辖的班级管理页,并行拉取三组数据:
|
||||
- `getGradeManagedClasses(userId)` — 该用户作为年级组长管辖的班级列表
|
||||
- `getTeacherOptions()` — 教师下拉选项(用于班主任分配)
|
||||
- `getManagedGrades(userId)` — 该用户管辖的年级列表
|
||||
- 渲染 `GradeClassesClient` 客户端组件,承载班级 CRUD(建/删/改)交互
|
||||
- **技术栈**:
|
||||
- Server Component(`force-dynamic`)+ `generateMetadata`(i18n `school.classManagement.grade.*`)
|
||||
- `Promise.all` 并行数据获取
|
||||
- 客户端组件 `GradeClassesClient`(`modules/classes/components/grade-classes-view.tsx`)
|
||||
- 客户端组件依赖:
|
||||
- `createGradeClassAction` / `deleteGradeClassAction` / `updateGradeClassAction`(Server Actions,`modules/classes/actions.ts`)
|
||||
- `useClassData` Hook(`modules/classes/hooks/use-class-data.ts`)
|
||||
- `ClassDeleteDialog` / `ClassFormDialog` / `ClassListTable` / `ClassListToolbar`(4 个子组件)
|
||||
- `ctx.userId` 用于 owner 维度过滤
|
||||
- **权限**:`GRADE_MANAGE`(`grade:manage`)— 年级组长写权限
|
||||
- **ARCHITECTURE.md 契约**:❌(5 个 data-access 全走 Drizzle,无 GraphQL)
|
||||
- **批次**:B2/B5 末(N)
|
||||
- **迁移注意**:portal-shell 现有 `/shell/teacher/classes` 是普通教师班级列表(教师授课班级),与年级组长管辖的班级列表**语义不同**(前者按 `teacherId` 关联 `class_teachers`,后者按年级组管辖范围 `grade_head`)。**不可合并**。
|
||||
|
||||
### 2.4 年级组作业洞察(insights)
|
||||
|
||||
- **CICD 路径**:`e:\desktop\CICD\src\app\(dashboard)\management\grade\insights\page.tsx`
|
||||
- **建议目标路由**:`/shell/teacher/management/grade/insights`
|
||||
- **功能描述**:年级组作业洞察页,单年级作业统计与班级排名:
|
||||
- **年级筛选器**(FilterBar + ChipNav):`getGradesForStaff(teacherId)` + `?gradeId=xxx` 切换
|
||||
- **4 个统计卡(StatCard)**:
|
||||
- 班级数(`insights.classCount`)
|
||||
- 学生数(`studentCounts.total` / `active` / `inactive`)
|
||||
- 整体平均分(`overallScores.avg`)
|
||||
- 最近作业平均分(`insights.latest.scoreStats.avg` + 作业标题)
|
||||
- **作业时间线表(Table)**:每个作业一行,列含:作业名 / 状态 / 创建时间 / 应交 / 已交 / 已批 / 平均分 / 中位数分
|
||||
- **班级排名表(Table)**:每个班一行,列含:班级名(含班主任)/ 学生数 / 最近作业平均 / 上次平均 / 涨跌 / 整体平均
|
||||
- **三段空状态**:无年级 / 未选 / 数据为空 / 无 insights 各自 EmptyState
|
||||
- **移动端适配**:`overflow-x-auto` 包裹两个 Table(v4-P1-11)
|
||||
- **技术栈**:
|
||||
- Server Component(`force-dynamic`)+ `generateMetadata`(i18n `school.grades.gradeInsights.*`)
|
||||
- `formatDate` / `formatNumber` 工具(`@/shared/lib/utils`)
|
||||
- 共享 UI:`FilterBar` / `ChipNav` / `EmptyState` / `StatCard` / `Card` / `Badge` / `Table` 全套
|
||||
- 数据访问:`getGradeHomeworkInsights({ gradeId, limit: 50 })`(`modules/classes/data-access`,limit=50)
|
||||
- 辅助查询:`getTeacherIdForMutations` + `getGradesForStaff`
|
||||
- 图标:`BarChart3`(lucide-react)
|
||||
- **权限**:`GRADE_RECORD_READ`(`grade_record:read`)— 只读权限
|
||||
- **ARCHITECTURE.md 契约**:❌(Drizzle 直查,无 GraphQL)
|
||||
- **批次**:B2/B5 末(N)
|
||||
|
||||
### 2.5 年级组练习概览(practice)
|
||||
|
||||
- **CICD 路径**:`e:\desktop\CICD\src\app\(dashboard)\management\grade\practice\page.tsx`
|
||||
- **建议目标路由**:`/shell/teacher/management/grade/practice`
|
||||
- **功能描述**:年级组自适应练习概览页,三段式数据可视化:
|
||||
- **年级筛选器**(FilterBar + ChipNav):`getGradesForStaff(teacherId)` + `?gradeId=xxx` 切换
|
||||
- **5 个统计卡(StatsGrid)**:
|
||||
- 班级总数(`overview.totalClasses`,BookOpen 图标)
|
||||
- 练习会话总数(`overview.totalSessions`,Activity 图标)
|
||||
- 答题总数(`overview.totalQuestionsAnswered`,Target 图标)
|
||||
- 平均正确率(`overview.averageAccuracy * 100`%,CheckCircle2 图标)
|
||||
- 参与率(`overview.participationRate * 100`%,Users 图标)
|
||||
- **班级练习对比表**:`ClassPracticeComparisonTable`(`modules/adaptive-practice/components`)渲染 `classComparison`
|
||||
- **练习类型分布图**:`PracticeTypeBreakdownChart`(同模块)渲染 `typeBreakdown`
|
||||
- **懒加载**:仅 `selected` 存在时执行 `Promise.all` 并行 3 查询
|
||||
- **三段空状态**:无年级 / 未选 / 数据为 null 各自 EmptyState
|
||||
- **技术栈**:
|
||||
- Server Component(`force-dynamic`)+ `generateMetadata`(i18n `practice.grade.*`)
|
||||
- 双 i18n namespace:`practice`(主)+ `school`(年级筛选器复用 `grades.gradeInsights.selectGrade`)
|
||||
- 数据访问:`modules/adaptive-practice/data-access-analytics` 的 3 个查询:
|
||||
- `getGradePracticeOverview(gradeId)`
|
||||
- `getGradeClassPracticeComparison(gradeId)`
|
||||
- `getPracticeTypeBreakdown(studentIds)` — 需要先调 `getUserIdsByGradeId(gradeId)` 取学生 ID 列表
|
||||
- 共享 UI:`StatsGrid`(5 列)、`FilterBar`、`ChipNav`、`EmptyState`
|
||||
- 业务组件:`ClassPracticeComparisonTable` + `PracticeTypeBreakdownChart`
|
||||
- 6 个 lucide-react 图标:`Activity` / `BarChart3` / `BookOpen` / `CheckCircle2` / `Target` / `Users`
|
||||
- **权限**:`ADAPTIVE_PRACTICE_READ`(`adaptive_practice:read`)— 自适应练习读权限
|
||||
- **ARCHITECTURE.md 契约**:❌(Drizzle 直查,无 GraphQL)
|
||||
- **批次**:B2/B5 末(N)
|
||||
- **迁移注意**:CICD 的 `navigation.ts` 中 `teacher.gradeManagement` 菜单组**只列了 classes/dashboard/insights 3 项**,未列 practice 子菜单。但 page.tsx 实际存在,应作为隐藏/直接 URL 访问入口保留。
|
||||
|
||||
---
|
||||
|
||||
## 三、角色归属分析
|
||||
|
||||
### 3.1 CICD 中的权限校验
|
||||
|
||||
| 页面 | requirePermission | 权限语义 |
|
||||
| --------------- | ------------------------------------ | ---------------- |
|
||||
| page.tsx (入口) | `Permissions.GRADE_MANAGE` | 年级组管理(写) |
|
||||
| classes | `Permissions.GRADE_MANAGE` | 年级组管理(写) |
|
||||
| dashboard | `Permissions.GRADE_RECORD_READ` | 成绩记录读 |
|
||||
| insights | `Permissions.GRADE_RECORD_READ` | 成绩记录读 |
|
||||
| practice | `Permissions.ADAPTIVE_PRACTICE_READ` | 自适应练习读 |
|
||||
|
||||
> 5 个页面共用 3 类权限,无 `admin:*` 权限校验。**年级组页面是"年级组长"维度,不属于"管理员"维度**。
|
||||
|
||||
### 3.2 CICD 导航归属
|
||||
|
||||
`e:\desktop\CICD\src\modules\layout\config\navigation.ts` 中:
|
||||
|
||||
- `teacher` 角色菜单组:包含 `teacher.gradeManagement`(permission=`GRADE_MANAGE`),子项含 classes/dashboard/insights
|
||||
- `grade_head` 角色菜单组:同样包含 `teacher.gradeManagement`,子项相同
|
||||
- 两个角色都把年级组放在**与"teacher.grades"(成绩录入)平级**的位置,不在 `admin.*` 之下
|
||||
|
||||
### 3.3 portal-shell 角色与目录约定
|
||||
|
||||
- `apps\portal-shell\ARCHITECTURE.md` §9.1 教师域规划到 `/shell/teacher/*`,§9.4 管理域规划到 `/shell/admin/*`
|
||||
- portal-shell 现有目录仅 `/shell/{teacher|admin|student|parent|dev|forbidden}/*`,无独立 `grade-head` 段
|
||||
- `src/middleware.ts` 默认合成身份为 `role: "teacher"`,未对 `grade_head` 角色做特殊路由分发
|
||||
- `src/shared/lib/route-permissions.ts` 中无 `management` / `grade` 路由条目(需新增)
|
||||
|
||||
### 3.4 建议归属
|
||||
|
||||
**推荐方案:归入教师域子路径** `/shell/teacher/management/grade/*`
|
||||
|
||||
理由:
|
||||
|
||||
1. CICD 在 `teacher` 与 `grade_head` 两角色菜单中都把"年级组管理"挂在教师主菜单下,语义上是"教师的扩展职责"
|
||||
2. portal-shell 已有 `/shell/teacher/*` 体系,复用其布局壳、middleware 身份合成、route-permissions 表
|
||||
3. 避免新建 `/shell/grade-head/*` 顶层段(会带来 sidebar 配置、middleware 分发、layout 重复实现等成本)
|
||||
4. 路由权限按 `GRADE_MANAGE` / `GRADE_RECORD_READ` / `ADAPTIVE_PRACTICE_READ` 精确声明,与角色解耦——拥有这些权限位的教师(无论 role 字段是 `teacher` 还是 `grade_head`)都可访问
|
||||
|
||||
**备选方案**:若后续 portal-shell 引入 `grade_head` 独立角色段,可平滑迁移到 `/shell/grade-head/*`(page.tsx 实现完全可复用,仅需调整路由前缀)。
|
||||
|
||||
**目标路由建议**:
|
||||
|
||||
| CICD 源路径 | 建议目标路由 | 权限 |
|
||||
| ----------------------------- | ------------------------------------------- | ------------------------ |
|
||||
| `/management/grade` | `/shell/teacher/management/grade` | `GRADE_MANAGE` |
|
||||
| `/management/grade/classes` | `/shell/teacher/management/grade/classes` | `GRADE_MANAGE` |
|
||||
| `/management/grade/dashboard` | `/shell/teacher/management/grade/dashboard` | `GRADE_RECORD_READ` |
|
||||
| `/management/grade/insights` | `/shell/teacher/management/grade/insights` | `GRADE_RECORD_READ` |
|
||||
| `/management/grade/practice` | `/shell/teacher/management/grade/practice` | `ADAPTIVE_PRACTICE_READ` |
|
||||
|
||||
---
|
||||
|
||||
## 四、迁移注意事项
|
||||
|
||||
### 4.1 契约缺口(5 页全部 ❌)
|
||||
|
||||
5 个页面的数据访问在 CICD 中**全部走 Drizzle ORM 直查 DB**,未通过 GraphQL schema。迁移到 portal-shell 时按 ARCH §9.5 "节奏原则"处理:
|
||||
|
||||
- **MSW 先行**:用 Mock Service Worker 提供假数据,先把 5 个页面的 UI 跑起来
|
||||
- **契约工单**:向后端开 5 类查询的 GraphQL schema 工单
|
||||
- `gradeManagedClasses(userId)` + `managedGrades(userId)` + `teacherOptions()`
|
||||
- `gradesForStaff(teacherId)`(年级列表)
|
||||
- `gradeDistributionByGradeId(gradeId, scope)` + `gradeHomeworkInsights(gradeId, limit)` + `examsByGradeId(gradeId, scope)` + `gradeCoursePlanProgress(gradeId)`
|
||||
- `gradePracticeOverview(gradeId)` + `gradeClassPracticeComparison(gradeId)` + `practiceTypeBreakdown(studentIds)` + `userIdsByGradeId(gradeId)`
|
||||
- **切换策略**:契约就绪后,只改 hook 的 fetcher 指向(从 MSW 切到 Apollo Client),页面不动
|
||||
|
||||
### 4.2 跨模块依赖(5 个领域模块)
|
||||
|
||||
年级组页面是**跨模块聚合页**,依赖 5 个领域模块的 data-access:
|
||||
|
||||
| 依赖模块 | 用到的查询 |
|
||||
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `classes` | `getGradeManagedClasses` / `getManagedGrades` / `getTeacherIdForMutations` / `getGradeHomeworkInsights` / `getTeacherOptions` |
|
||||
| `school` | `getGradesForStaff` |
|
||||
| `grades` | `getGradeDistributionByGradeId` |
|
||||
| `exams` | `getExamsByGradeId` |
|
||||
| `course-plans` | `getGradeCoursePlanProgress` |
|
||||
| `adaptive-practice` | `getGradePracticeOverview` / `getGradeClassPracticeComparison` / `getPracticeTypeBreakdown` |
|
||||
| `users` | `getUserIdsByGradeId` |
|
||||
|
||||
迁移时需确保 portal-shell 对应的 7 个领域模块契约齐备或 MSW 兜底覆盖。
|
||||
|
||||
### 4.3 DataScope 二次过滤
|
||||
|
||||
CICD 的 `requirePermission` 返回 `ctx.dataScope`,传入 `getGradeDistributionByGradeId` 和 `getExamsByGradeId` 进行**数据范围二次过滤**(按教师可见的年级/班级范围裁剪结果)。
|
||||
|
||||
portal-shell 中需在 hook 层保留 dataScope 参数,避免越权读取非管辖年级数据。
|
||||
|
||||
### 4.4 i18n 命名空间
|
||||
|
||||
5 个页面用到 3 个 i18n namespace:
|
||||
|
||||
- `school`(dashboard / classes / insights 主命名空间)
|
||||
- `practice`(practice 页主命名空间)
|
||||
- `school.grades.gradeInsights.selectGrade`(practice 页复用)
|
||||
|
||||
迁移时需将 CICD 的 `messages/zh-CN/school.json` / `practice.json` 中相关键同步到 portal-shell 的 i18n 资源。
|
||||
|
||||
### 4.5 业务组件迁移
|
||||
|
||||
以下业务组件需要从 CICD 迁移到 portal-shell(按页面分组):
|
||||
|
||||
| 页面 | 组件 | 来源模块 |
|
||||
| --------- | -------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
|
||||
| dashboard | `GradeDistributionPanel` / `GradeHomeworkPanel` / `GradeExamsPanel` / `GradeProgressPanel` | `modules/school/components/grade-dashboard` |
|
||||
| classes | `GradeClassesClient` + 4 个子组件(`ClassDeleteDialog` / `ClassFormDialog` / `ClassListTable` / `ClassListToolbar`) | `modules/classes/components` |
|
||||
| practice | `ClassPracticeComparisonTable` / `PracticeTypeBreakdownChart` | `modules/adaptive-practice/components` |
|
||||
| insights | 仅用共享 UI(StatCard / Card / Table),无业务组件 | — |
|
||||
|
||||
### 4.6 route-permissions.ts 同步
|
||||
|
||||
迁移完成后需在 `apps/portal-shell/src/shared/lib/route-permissions.ts` 新增 5 条路由权限声明:
|
||||
|
||||
```ts
|
||||
// 示例(实际实现时按真实 schema 编写)
|
||||
"/shell/teacher/management/grade": { permission: "grade:manage", ... },
|
||||
"/shell/teacher/management/grade/classes": { permission: "grade:manage", ... },
|
||||
"/shell/teacher/management/grade/dashboard": { permission: "grade_record:read", ... },
|
||||
"/shell/teacher/management/grade/insights": { permission: "grade_record:read", ... },
|
||||
"/shell/teacher/management/grade/practice": { permission: "adaptive_practice:read", ... },
|
||||
```
|
||||
|
||||
### 4.7 ARCHITECTURE.md 与 arch.db 同步
|
||||
|
||||
按 `e:\Desktop\Edu\.trae\rules\project_rules.md` §1.3「改码必同步图」要求:
|
||||
|
||||
- 完成 5 页迁移后运行 `pnpm run arch:scan` 更新 arch.db
|
||||
- 在 `apps/portal-shell/ARCHITECTURE.md` §9.5 表格中将"缺口新增"行的"契约已就绪"列从 `0` 更新为实际就绪数(按契约工单进度)
|
||||
- 在 `docs/troubleshooting/known-issues.md` 对应模块分区追加"场景→技术"映射(索引式一行,不标 AI 身份)
|
||||
|
||||
### 4.8 批次与顺序
|
||||
|
||||
按 ARCH §9.5 规划,5 页归入 **B2/B5 末** 批次:
|
||||
|
||||
- **B2 末**(教师域二期,与教师主功能一起补齐):classes / dashboard / insights — 因 CICD navigation 中挂在 `teacher.gradeManagement` 菜单下
|
||||
- **B5 末**(管理域,与管理员功能一起补齐):practice — 因 CICD navigation 未列 practice 子项,按独立入口处理
|
||||
|
||||
**推荐实施顺序**(依赖从轻到重):
|
||||
|
||||
1. `page.tsx`(入口重定向,最简单,0 数据访问)
|
||||
2. `insights`(仅查 1 个 data-access + 共享 UI)
|
||||
3. `classes`(3 个 data-access + 1 客户端组件 + 4 子组件)
|
||||
4. `dashboard`(4 个 data-access + 4 业务面板组件)
|
||||
5. `practice`(3 个 data-access + 2 业务组件 + 1 辅助查询)
|
||||
|
||||
---
|
||||
|
||||
## 五、附录:CICD 文件清单
|
||||
|
||||
```
|
||||
e:\desktop\CICD\src\app\(dashboard)\management\grade\
|
||||
├─ page.tsx # 入口重定向 → /classes
|
||||
├─ error.tsx # 错误边界
|
||||
├─ loading.tsx # 加载骨架
|
||||
├─ classes\
|
||||
│ ├─ page.tsx # 年级组班级列表
|
||||
│ ├─ error.tsx
|
||||
│ └─ loading.tsx
|
||||
├─ dashboard\
|
||||
│ ├─ page.tsx # 年级组仪表盘(4 Tab)
|
||||
│ └─ loading.tsx
|
||||
├─ insights\
|
||||
│ ├─ page.tsx # 年级组作业洞察
|
||||
│ ├─ error.tsx
|
||||
│ └─ loading.tsx
|
||||
└─ practice\
|
||||
├─ page.tsx # 年级组练习概览
|
||||
├─ error.tsx
|
||||
└─ loading.tsx
|
||||
```
|
||||
|
||||
> portal-shell 已有统一的 `loading.tsx` / `error.tsx` 模板(见 `apps/portal-shell/src/app/shell/teacher/*` 各目录),迁移时复用模板即可,无需单独迁 error/loading。
|
||||
Reference in New Issue
Block a user