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:
795
apps/portal-shell/docs/needtodo/student-NeedTodo.md
Normal file
795
apps/portal-shell/docs/needtodo/student-NeedTodo.md
Normal file
@@ -0,0 +1,795 @@
|
||||
# 学生域(Student)待完成功能分析
|
||||
|
||||
> 参考项目:`e:\desktop\CICD\src\app\(dashboard)\student\`
|
||||
> 当前项目:`e:\Desktop\Edu\apps\portal-shell\src\app\shell\student\`
|
||||
> 规划依据:`apps/portal-shell/ARCHITECTURE.md` §9.2(36 页,B3 批次)
|
||||
> 分析日期:2026-07-24
|
||||
> 任务范围:仅分析,不写代码
|
||||
|
||||
---
|
||||
|
||||
## 一、页面完成度总览
|
||||
|
||||
### 1.1 portal-shell 学生域现状
|
||||
|
||||
当前 `apps/portal-shell/src/app/shell/student/` 下**仅有 1 个页面**:
|
||||
|
||||
| 路径 | 状态 | 说明 |
|
||||
| ------------------------- | --------- | ------------------------------------------------ |
|
||||
| `/shell/student/page.tsx` | ✅ 已完成 | 学生仪表盘(仅基础版,缺 trend/weakness 详情页) |
|
||||
|
||||
### 1.2 完成度统计
|
||||
|
||||
| 状态 | 数量 | 说明 |
|
||||
| ------------ | ------ | ---------------------------------------------------------- |
|
||||
| ✅ 已完成 | 1 | `/shell/student/page.tsx`(仪表盘基础版,仍缺 2 个详情页) |
|
||||
| 🟡 部分完成 | 1 | dashboard 模块(基础页有,trend/weakness 详情页缺) |
|
||||
| ❌ 缺失 | 34 | 见下方模块清单 |
|
||||
| **规划总数** | **36** | ARCHITECTURE.md §9.2 B3 批次 |
|
||||
|
||||
### 1.3 portal-shell 仪表盘与 CICD 仪表盘的技术差异(关键架构差异)
|
||||
|
||||
| 维度 | CICD 仪表盘 | portal-shell 仪表盘 |
|
||||
| -------- | ---------------------------------------------------------------------- | --------------------------------------------------- |
|
||||
| 渲染模式 | Server Component(`async function`) | Client Component(`"use client"`) |
|
||||
| 数据获取 | Server Action `getStudentDashboardAction()` + Suspense 流式渲染 | `useStudentDashboard()` Hook(`@/lib/api`,走 BFF) |
|
||||
| 国际化 | `next-intl` `getTranslations` | 无(硬编码中文) |
|
||||
| 权限校验 | `requirePermission` + `getAuthContext` | 无 |
|
||||
| 视图组件 | `StudentDashboard` 视图模块(拆分到 `@/modules/dashboard/components`) | 直接内联在 page.tsx |
|
||||
| 数据来源 | 直查 DB(Drizzle) | 走 data-ana 微服务聚合 |
|
||||
|
||||
> **重要提示**:portal-shell 已转向微服务 + BFF 架构,迁移时**不能照搬 CICD 的 Server Action + Drizzle 直查模式**。学生页面应通过 `teacher-bff` / `data-ana` 等服务的 gRPC/HTTP API 获取数据,前端通过 hooks 消费。
|
||||
|
||||
---
|
||||
|
||||
## 二、缺失页面清单(按模块分组)
|
||||
|
||||
### 2.1 dashboard 模块(3 页规划,1 已完成,2 缺失)
|
||||
|
||||
#### 2.1.1 ✅ `/shell/student/page.tsx`(已完成)
|
||||
|
||||
- **portal-shell 实现**:基础仪表盘,显示平均分 / 班级排名 / 待交作业 + 薄弱知识点 + 近期成绩趋势
|
||||
- **技术栈**:Client Component + `useStudentDashboard()` Hook + `DashboardShell` / `StatCard` 共享组件
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\dashboard\page.tsx`
|
||||
- **CICD 技术栈**:Server Component + `getStudentDashboardAction()` Server Action + `StudentDashboard` 视图组件 + Suspense 流式渲染
|
||||
- **ARCHITECTURE.md 契约**:✅ `studentDashboard`
|
||||
|
||||
#### 2.1.2 ❌ `/shell/student/trend`(学习趋势详情页,缺失)
|
||||
|
||||
- **CICD 参考实现**:CICD 无独立 `/trend` 页面(融合在 dashboard 中以 `recent_trends` 字段呈现)
|
||||
- **功能描述**:学生学习趋势详情页,应展示更完整的历史成绩趋势、知识点掌握趋势、对比基线
|
||||
- **技术栈建议**:复用 `learningTrend` 契约 + 趋势图组件(Recharts/Echarts)
|
||||
- **ARCHITECTURE.md 契约**:✅ `learningTrend`
|
||||
- **CICD 关键代码片段**:dashboard 中仅以单条 `recent_trends: { date, score }` 呈现,需 portal-shell 自行扩展为详情页
|
||||
|
||||
#### 2.1.3 ❌ `/shell/student/weakness`(薄弱知识点详情页,缺失)
|
||||
|
||||
- **CICD 参考实现**:CICD 无独立 `/weakness` 页面(融合在 dashboard 中以 `weak_points: { title, mastery, error_count }` 字段呈现)
|
||||
- **功能描述**:学生薄弱知识点详情页,应展示完整的薄弱知识点列表、按学科分组、关联错题、推荐练习
|
||||
- **技术栈建议**:复用 `studentWeakness` 契约 + 错题本 / 练习模块联动跳转
|
||||
- **ARCHITECTURE.md 契约**:✅ `studentWeakness`
|
||||
- **CICD 关键代码片段**:dashboard 中仅以单条 `weak_points` 呈现,需 portal-shell 自行扩展
|
||||
|
||||
---
|
||||
|
||||
### 2.2 grades 模块(2 页规划,0 已完成,2 缺失)
|
||||
|
||||
#### 2.2.1 ❌ `/shell/student/grades`(我的成绩列表,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\grades\page.tsx`
|
||||
- **功能描述**:
|
||||
- 学生本人成绩汇总(姓名 + 记录数)
|
||||
- 学科 / 类型 / 学期 / 关键字 4 维过滤器
|
||||
- **成绩趋势卡片**(含班级平均对比线)
|
||||
- **排名趋势卡片**
|
||||
- **班级分布直方图**(隐私保护视图,仅展示本人位置标注)
|
||||
- **学生纵向成长档案**(跨学年/学期聚合)
|
||||
- 成绩汇总明细表
|
||||
- **技术栈**:
|
||||
- Server Component(`async function`)+ `force-dynamic`
|
||||
- Server Actions:`getStudentGradeSummary` / `getRankingTrend` / `getClassAverageTrend` / `getStudentPositionInClassDistribution` / `getStudentGrowthArchive` / `getSubjectOptions`
|
||||
- `requirePermission(Permissions.GRADE_RECORD_READ)` + `ctx.dataScope`
|
||||
- 组件:`StudentGradeSummary` / `StudentGradeFilters` / `GradeTrendCard` / `RankingTrendCard` / `GradeDistributionChart` / `GrowthArchiveChart` / `EmptyState`
|
||||
- searchParams 过滤(`q` / `subject` / `type` / `semester`)
|
||||
- **ARCHITECTURE.md 契约**:❌(列表,未定义)
|
||||
|
||||
#### 2.2.2 ❌ `/shell/student/grades/report-card`(成绩报告卡,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\grades\report-card\page.tsx`
|
||||
- **功能描述**:
|
||||
- 学年 / 学期可切换的成绩报告卡
|
||||
- 报告卡视图(学生本人维度聚合)
|
||||
- **打印操作**(`ReportCardPrintAction`)
|
||||
- 返回成绩列表的面包屑
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic`
|
||||
- Server Actions:`getReportCardData(ctx.userId, ctx.dataScope, { academicYearId, semester })` + `getAcademicYears()`
|
||||
- `requirePermission(Permissions.GRADE_RECORD_READ)`
|
||||
- 组件:`ReportCardView` / `ReportCardPrintAction` / `Button` / `EmptyState`
|
||||
- searchParams:`academicYearId` / `semester`
|
||||
- **ARCHITECTURE.md 契约**:❌(未单独定义)
|
||||
|
||||
---
|
||||
|
||||
### 2.3 exams 模块(3 页规划,0 已完成,3 缺失)⚠️ 重点
|
||||
|
||||
> **CICD 参考项目无 exams 模块学生页面**。学生考试相关功能需 portal-shell 从零设计。
|
||||
|
||||
#### 2.3.1 ❌ `/shell/student/exams`(我的考试列表,缺失)
|
||||
|
||||
- **CICD 参考实现**:❌ CICD 无对应源页面
|
||||
- **功能描述**:学生视角的考试列表,应展示:
|
||||
- 即将到来的考试(含倒计时、考场、座位号)
|
||||
- 已结束考试(含成绩、查看结果入口)
|
||||
- 按学科 / 状态过滤
|
||||
- **技术栈建议**:参考 CICD `learning/assignments/page.tsx` 的列表分组 + 状态徽章模式
|
||||
- **ARCHITECTURE.md 契约**:🟡(部分,需补充)
|
||||
|
||||
#### 2.3.2 ❌ `/shell/student/exams/[id]/result`(考试结果页,缺失)
|
||||
|
||||
- **CICD 参考实现**:❌ CICD 无对应源页面(可参考 `learning/assignments/[assignmentId]/result/page.tsx` 的同构模式)
|
||||
- **功能描述**:
|
||||
- 考试得分、排名、班级均分对比
|
||||
- 题目作答详情(每题对错、参考答案、学生答案)
|
||||
- 知识点掌握情况
|
||||
- 错题一键加入错题本
|
||||
- **技术栈建议**:参考 CICD `HomeworkSubmissionResult` 组件 + `getStudentSubmissionResult` 数据访问模式
|
||||
- **ARCHITECTURE.md 契约**:🟡(部分,需补充)
|
||||
|
||||
#### 2.3.3 ❌ `/shell/student/exams/[id]/take`(考试作答工作台,缺失)⚠️ 关键
|
||||
|
||||
- **CICD 参考实现**:❌ CICD 无对应源页面(可参考 `learning/assignments/[assignmentId]/page.tsx` 的 `HomeworkTakeView` 同构模式)
|
||||
- **功能描述**:考试作答工作台,应包含:
|
||||
- 题目导航栏(题号、未答/已答/标记状态)
|
||||
- 题目作答区(单选/多选/填空/简答)
|
||||
- 倒计时(自动提交)
|
||||
- 答案本地暂存(防刷新丢失)
|
||||
- 提交确认 + 二次确认
|
||||
- 中途断网恢复
|
||||
- **技术栈建议**:
|
||||
- 客户端组件(`HomeworkTakeView` 是 client component)
|
||||
- 答案本地存储(localStorage / IndexedDB)
|
||||
- 自动保存定时器
|
||||
- 提交走 Server Action / BFF API
|
||||
- **ARCHITECTURE.md 契约**:🟡(部分,需补充)
|
||||
|
||||
> ⚠️ **此页是学生域最复杂、最关键的页面**,需在 B3 中重点投入。CICD 的 `HomeworkTakeView` 是最近的同构参考,但其路由是 `learning/assignments/[assignmentId]` 而非 `exams/[id]/take`。
|
||||
|
||||
---
|
||||
|
||||
### 2.4 homework 模块(3 页规划,0 已完成,3 缺失)
|
||||
|
||||
> **CICD 实际路由是 `learning/assignments/*`**,ARCHITECTURE.md §9.2 计划将其提升到 `homework/*` 顶层。
|
||||
|
||||
#### 2.4.1 ❌ `/shell/student/homework`(我的作业列表,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\learning\assignments\page.tsx`
|
||||
- **功能描述**:
|
||||
- 作业列表,按**学科分组**展示
|
||||
- 每组内按"未答 / 已答"二分桶(PERF-05 单次遍历分桶)
|
||||
- 每张卡片:标题、状态徽章、截止时间、剩余尝试次数、最新得分、逾期提示
|
||||
- 学科 dot 颜色(hash 稳定映射)
|
||||
- 状态过滤(all/pending/submitted/graded)+ 关键字搜索
|
||||
- `AssignmentCard` 用 `React.memo` 优化高频渲染
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic`
|
||||
- Server Action:`getStudentHomeworkAssignments(student.id)`
|
||||
- 组件:`AssignmentFilters` / `StatusBadge` / `Card` / `EmptyState` / `memo(AssignmentCard)`
|
||||
- 工具:`formatDate` / `getParam` / `cn` / `STUDENT_HOMEWORK_PROGRESS_VARIANT`
|
||||
- **ARCHITECTURE.md 契约**:🟡(部分)
|
||||
|
||||
#### 2.4.2 ❌ `/shell/student/homework/[id]/submit`(作业作答/提交,缺失)⚠️ 关键
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\learning\assignments\[assignmentId]\page.tsx`
|
||||
- **功能描述**:
|
||||
- 根据 `submission.status` 分流:
|
||||
- `graded` / `submitted` → 进入 `HomeworkReviewView`(查看提交后/批改后视图)
|
||||
- `not_started` / `in_progress` → 进入 `HomeworkTakeView`(作答工作台)
|
||||
- 顶部展示作业标题、截止时间、最大尝试次数
|
||||
- **技术栈**:
|
||||
- Server Component(外壳)+ Client Component(`HomeworkTakeView` / `HomeworkReviewView`)
|
||||
- Server Action:`getStudentHomeworkTakeData(assignmentId, student.id)`
|
||||
- 组件:`HomeworkTakeView` / `HomeworkReviewView`
|
||||
- **ARCHITECTURE.md 契约**:🟡(部分)
|
||||
|
||||
#### 2.4.3 ❌ `/shell/student/homework/[id]/analysis`(作业分析/结果,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\learning\assignments\[assignmentId]\result\page.tsx`
|
||||
- **功能描述**:
|
||||
- 作业标题 + 提交结果详情
|
||||
- 通过 `HomeworkSubmissionResult` 组件展示分析(含每题得分、参考答案等)
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic`
|
||||
- Server Actions:`getHomeworkAssignmentById(assignmentId)` + `getStudentSubmissionResult(assignmentId, studentId)`
|
||||
- 通过 `getSession()` 获取 studentId(非 `requirePermission` 模式,需注意)
|
||||
- 组件:`HomeworkSubmissionResult`
|
||||
- **ARCHITECTURE.md 契约**:🟡(部分)
|
||||
|
||||
---
|
||||
|
||||
### 2.5 schedule 模块(1 页规划,0 已完成,1 缺失)
|
||||
|
||||
#### 2.5.1 ❌ `/shell/student/schedule`(学生课表,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\schedule\page.tsx`
|
||||
- **功能描述**:
|
||||
- 学生个人课表(按班级聚合)
|
||||
- 班级过滤器(`classId` searchParam,默认 `all`)
|
||||
- 顶部标题 + 班级筛选器
|
||||
- `StudentScheduleView` 渲染课表
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic` + `generateMetadata`
|
||||
- Server Actions:`getStudentClasses(student.id)` + `getStudentSchedule(student.id)`
|
||||
- `requirePermission(Permissions.CLASS_READ)` + `getCurrentStudentUser()`
|
||||
- 组件:`StudentScheduleFilters` / `StudentScheduleView` / `EmptyState`
|
||||
- searchParams:`classId`
|
||||
- **ARCHITECTURE.md 契约**:❌
|
||||
|
||||
---
|
||||
|
||||
### 2.6 attendance 模块(1 页规划,0 已完成,1 缺失)
|
||||
|
||||
#### 2.6.1 ❌ `/shell/student/attendance`(学生考勤,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\attendance\page.tsx`
|
||||
- **功能描述**:
|
||||
- 学生本人考勤汇总(出勤率、迟到/早退/请假次数)
|
||||
- 通过 `StudentAttendanceView` 渲染详细记录
|
||||
- 无数据时显示 `EmptyState`
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic`
|
||||
- Server Action:`getStudentAttendanceSummary(ctx.userId)`
|
||||
- `requirePermission(Permissions.ATTENDANCE_READ)` + `getAuthContext()`
|
||||
- 组件:`StudentAttendanceView` / `EmptyState`
|
||||
- **ARCHITECTURE.md 契约**:❌
|
||||
|
||||
---
|
||||
|
||||
### 2.7 classes 模块(1 页规划,0 已完成,1 缺失)
|
||||
|
||||
#### 2.7.1 ❌ `/shell/student/classes`(我的班级,缺失)
|
||||
|
||||
- **CICD 参考实现**:❌ CICD 学生端无独立 `/classes` 路由(班级信息融合在 `learning/courses/*` 中)
|
||||
- **功能描述**:
|
||||
- 学生所在的班级列表(含班主任、教室、学校、年级、活跃状态)
|
||||
- 区别于 courses(课程):classes 侧重"行政班/教学班"维度,courses 侧重"学科课程"维度
|
||||
- 可跳转到该班的课表、作业、同学(受权限限制)
|
||||
- **技术栈建议**:参考 CICD `learning/courses/page.tsx` 的列表 + 过滤模式
|
||||
- **ARCHITECTURE.md 契约**:❌ `myClasses`
|
||||
|
||||
---
|
||||
|
||||
### 2.8 courses 模块(2 页规划,0 已完成,2 缺失)
|
||||
|
||||
#### 2.8.1 ❌ `/shell/student/courses`(课程列表,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\learning\courses\page.tsx`
|
||||
- **功能描述**:
|
||||
- 学生报名的课程(班级)列表
|
||||
- 关键字搜索(名称 / 教师 / 学校 / 班主任)
|
||||
- 通过 `StudentCoursesView` 渲染
|
||||
- 仅有班级时才显示过滤器
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic` + `generateMetadata`
|
||||
- Server Action:`getStudentClasses(student.id)`
|
||||
- `requirePermission(Permissions.CLASS_READ)` + `getCurrentStudentUser()`
|
||||
- 组件:`CourseFilters` / `StudentCoursesView` / `EmptyState`
|
||||
- searchParams:`q`
|
||||
- **ARCHITECTURE.md 契约**:❌
|
||||
|
||||
#### 2.8.2 ❌ `/shell/student/courses/[id]`(课程详情,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\learning\courses\[classId]\page.tsx`
|
||||
- **功能描述**:
|
||||
- 班级(课程)详情页:名称、年级、班主任、教室、学校
|
||||
- **三列卡片**:教师信息(姓名 + 邮箱 mailto)/ 学校信息 / 教室信息
|
||||
- **本班课表**:按 weekday 排序的列表
|
||||
- 顶部按钮:跳转完整课表、跳转作业列表
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic` + `generateMetadata`
|
||||
- Server Actions:`getStudentClassById(student.id, classId)` + `getStudentSchedule(student.id)`
|
||||
- `requirePermission(Permissions.CLASS_READ)` + `getCurrentStudentUser()`
|
||||
- 组件:`Card` / `Badge` / `Button` / `EmptyState`
|
||||
- 路由参数:`classId`
|
||||
- **ARCHITECTURE.md 契约**:❌
|
||||
|
||||
---
|
||||
|
||||
### 2.9 course-plans 模块(2 页规划,0 已完成,2 缺失)
|
||||
|
||||
#### 2.9.1 ❌ `/shell/student/course-plans`(课程计划列表,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\course-plans\page.tsx`
|
||||
- **功能描述**:
|
||||
- 学生视角的课程计划列表(仅 `status: "active"`)
|
||||
- 通过 `class_members` scope 过滤可见的 classIds
|
||||
- `CoursePlanList` 渲染,detailBaseHref 指向 `/student/course-plans`
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic`
|
||||
- Server Action:`getCoursePlans({ status: "active" }, { userId, isAdmin: false, classIds })`
|
||||
- `requirePermission(Permissions.COURSE_PLAN_READ)`
|
||||
- 组件:`CoursePlanList`
|
||||
- **ARCHITECTURE.md 契约**:❌
|
||||
|
||||
#### 2.9.2 ❌ `/shell/student/course-plans/[id]`(课程计划详情,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\course-plans\[id]\page.tsx`
|
||||
- **功能描述**:
|
||||
- 课程计划详情视图(学生只读)
|
||||
- 通过 class_members scope 过滤
|
||||
- `CoursePlanDetail` 渲染,关联教材跳转 `/student/learning/textbooks`
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic`
|
||||
- Server Action:`getCoursePlanById(id, { userId, isAdmin: false, classIds })`
|
||||
- `requirePermission(Permissions.COURSE_PLAN_READ)`
|
||||
- 组件:`CoursePlanDetail`
|
||||
- 路由参数:`id`
|
||||
- `notFound()` 兜底
|
||||
- **ARCHITECTURE.md 契约**:❌
|
||||
|
||||
---
|
||||
|
||||
### 2.10 lesson-plans 模块(2 页规划,0 已完成,2 缺失)
|
||||
|
||||
#### 2.10.1 ❌ `/shell/student/lesson-plans`(教案列表,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\lesson-plans\page.tsx`
|
||||
- **功能描述**:
|
||||
- 学生视角的教案列表(仅 `status: "published"`)
|
||||
- `LessonPlanList` 学生视图模式(`viewMode="student"`)
|
||||
- `LessonPlanProviderSetup` 注入学生角色配置(让筛选生效)
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic`
|
||||
- Server Actions:`getLessonPlans({ status: "published" }, ctx.dataScope, ctx.userId)` + `getSubjectOptions()`
|
||||
- `requirePermission(Permissions.LESSON_PLAN_READ)`
|
||||
- 组件:`LessonPlanList` / `LessonPlanProviderSetup` / `STUDENT_ROLE_CONFIG` / `Skeleton` + `Suspense`
|
||||
- **ARCHITECTURE.md 契约**:❌
|
||||
|
||||
#### 2.10.2 ❌ `/shell/student/lesson-plans/[planId]/view`(教案只读查看,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\lesson-plans\[planId]\view\page.tsx`
|
||||
- **功能描述**:
|
||||
- 教案只读视图
|
||||
- **权限收敛**:学生仅可查看本年级已发布教案(`assertPlanInScope`),未发布显示提示
|
||||
- 拉取教材标题 + 章节标题(并行 `Promise.all`)
|
||||
- `LessonPlanReadonlyView` 渲染文档内容
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic`
|
||||
- Server Actions:`getLessonPlanById(planId, ctx.userId)` + `getTextbookById` + `getChaptersByTextbookId` + `findChapterById`
|
||||
- `requirePermission(Permissions.LESSON_PLAN_READ)` + `assertPlanInScope(plan, ctx)`
|
||||
- 组件:`LessonPlanReadonlyView` / `Skeleton` + `Suspense`
|
||||
- 路由参数:`planId`
|
||||
- **ARCHITECTURE.md 契约**:❌
|
||||
|
||||
---
|
||||
|
||||
### 2.11 textbooks 模块(2 页规划,0 已完成,2 缺失)
|
||||
|
||||
#### 2.11.1 ❌ `/shell/student/textbooks`(教材列表,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\learning\textbooks\page.tsx`
|
||||
- **功能描述**:
|
||||
- 学生视角的教材列表
|
||||
- **强制按学生所在年级过滤**(`getGradeNameById` 解析 gradeId 为年级名称)
|
||||
- 关键字 / 学科 / 年级 3 维过滤器
|
||||
- `TextbookCard` 网格(4 列响应式)
|
||||
- 学生端 `hideActions`(无编辑权限)
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic`
|
||||
- Server Actions:`getTextbooksWithScope(q, subject, grade, { grade: studentGradeName })` + `getGradeNameById`
|
||||
- `requirePermission(Permissions.TEXTBOOK_READ)` + `getCurrentStudentUser()`
|
||||
- 组件:`TextbookCard` / `TextbookFilters` / `EmptyState`
|
||||
- searchParams:`q` / `subject` / `grade`
|
||||
- **ARCHITECTURE.md 契约**:🟡
|
||||
|
||||
#### 2.11.2 ❌ `/shell/student/textbooks/[id]/chapters`(教材章节阅读器,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\learning\textbooks\[id]\page.tsx`
|
||||
- **功能描述**:
|
||||
- 教材阅读器(`TextbookReader`)
|
||||
- 顶部固定标题栏:教材标题 + 学科 Badge + 年级 Badge
|
||||
- 章节列表 + 阅读区
|
||||
- **年级校验**:教材年级与学生年级不匹配则 `notFound()`(防越权)
|
||||
- 学生端不传 `renderQuestionCreator`(无题目创建权限)
|
||||
- 高度自适应(`h-[calc(100vh-4rem-3rem)]`)
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic`
|
||||
- Server Actions:`getTextbookById(id)` + `getChaptersByTextbookId(id)` + `getGradeNameById`
|
||||
- `requirePermission(Permissions.TEXTBOOK_READ)` + `getCurrentStudentUser()`
|
||||
- 组件:`TextbookReader` / `Badge` / `EmptyState`
|
||||
- 路由参数:`id`
|
||||
- **ARCHITECTURE.md 契约**:🟡
|
||||
- **注**:ARCHITECTURE.md §9.2 路径为 `/[id]/chapters`,CICD 路径为 `/[id]`,迁移时需对齐
|
||||
|
||||
---
|
||||
|
||||
### 2.12 error-book 模块(1 页规划,0 已完成,1 缺失)
|
||||
|
||||
#### 2.12.1 ❌ `/shell/student/error-book`(错题本,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\error-book\page.tsx`
|
||||
- **功能描述**:
|
||||
- **5 列统计卡片**:总数 / 新增 / 学习中 / 已掌握(含掌握率%)/ 待复习(高亮 overdue)
|
||||
- **新增错题对话框**(`AddErrorBookDialogWithQuestions`,带题目选择器)
|
||||
- 筛选器:关键字 / 状态 / 来源 / 仅看待复习
|
||||
- 错题列表(客户端组件 `StudentErrorBookListClient`)
|
||||
- **AI 上下文注入**:`AiClientProvider` + `createCoreAiClientService`
|
||||
- `WidgetBoundary` 包裹关键 widget(降级容错)
|
||||
- `Suspense` 流式渲染过滤器 + 结果列表
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic`
|
||||
- Server Actions:`getErrorBookItems({ studentId, q, status, sourceType, dueOnly, pageSize: 50 })` + `getErrorBookStats(ctx.userId)`
|
||||
- `requirePermission(Permissions.ERROR_BOOK_READ)`
|
||||
- 组件:`StatsGrid` / `AddErrorBookDialogWithQuestions` / `ErrorBookFilters` / `StudentErrorBookListClient` / `WidgetBoundary` / `AiClientProvider`
|
||||
- 状态枚举守卫:`isErrorBookStatus` / `isErrorBookSource`(类型守卫)
|
||||
- **ARCHITECTURE.md 契约**:✅
|
||||
|
||||
---
|
||||
|
||||
### 2.13 learning 模块(2 页规划,0 已完成,2 缺失)
|
||||
|
||||
#### 2.13.1 ❌ `/shell/student/learning`(学习中心首页,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\learning\page.tsx`
|
||||
- **功能描述**:
|
||||
- 学习中心首页,3 张导航卡片:
|
||||
1. **课程**(已报名班级数)
|
||||
2. **作业**(待交数 + 即将到期数,7 天内)
|
||||
3. **教材**(可用数)
|
||||
- 每张卡片含图标 / 标题 / 描述 / 统计 / 箭头
|
||||
- 学生身份校验(`getCurrentStudentUser`),无则显示 `EmptyState`
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic` + `generateMetadata`
|
||||
- Server Actions:`getStudentClasses` + `getStudentHomeworkAssignments` + `getTextbooks`
|
||||
- `requirePermission(Permissions.CLASS_READ)`
|
||||
- 组件:`Card` / `EmptyState`
|
||||
- 业务逻辑:`pendingCount`(未提交+未批改)/ `dueSoonCount`(7 天内到期)计算
|
||||
- **ARCHITECTURE.md 契约**:❌
|
||||
|
||||
#### 2.13.2 ❌ `/shell/student/learning-path`(AI 学习路径,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\learning\study-path\page.tsx`
|
||||
- **功能描述**:
|
||||
- AI 生成的个性化学习路径
|
||||
- `AiStudyPath` 客户端组件,由 dashboard layout 注入 `AiClientProvider`
|
||||
- 学生身份校验
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic` + `generateMetadata`
|
||||
- `requirePermission(Permissions.AI_CHAT)`(与 AI_CHAT 权限点一致,防止学生角色被关闭后页面仍可访问)
|
||||
- `getCurrentStudentUser()`
|
||||
- 组件:`AiStudyPath`(client component)/ `EmptyState`
|
||||
- **ARCHITECTURE.md 契约**:❌
|
||||
- **注**:ARCHITECTURE.md §9.2 路径为 `/learning-path`(顶层),CICD 路径为 `/learning/study-path`,迁移时需对齐
|
||||
|
||||
---
|
||||
|
||||
### 2.14 practice 模块(2 页规划,0 已完成,2 缺失)
|
||||
|
||||
#### 2.14.1 ❌ `/shell/student/practice`(自适应练习首页,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\practice\page.tsx`
|
||||
- **功能描述**:
|
||||
- **4 列统计卡片**:总练习次数 / 已完成 / 总答题数 / 正确率
|
||||
- 左侧:`PracticeStarterWithNav`(练习启动器 + 知识点选择 + 导航)
|
||||
- 右侧:`PracticeHistory`(历史会话列表)
|
||||
- `PracticeServiceProvider` 包裹(注入练习服务)
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic`
|
||||
- Server Actions:`getPracticeStats(ctx.userId)` + `getPracticeSessions(ctx.userId, { pageSize: 20 })` + `getKnowledgePointOptions()`
|
||||
- `requirePermission(Permissions.ADAPTIVE_PRACTICE_READ)`
|
||||
- 组件:`StatsGrid` / `PracticeStarterWithNav` / `PracticeHistory` / `PracticeServiceProvider`
|
||||
- **ARCHITECTURE.md 契约**:❌
|
||||
|
||||
#### 2.14.2 ❌ `/shell/student/practice/[sessionId]`(练习会话页,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\practice\[sessionId]\page.tsx`
|
||||
- **功能描述**:
|
||||
- 单个练习会话详情
|
||||
- `PracticeSessionView` 渲染(题目作答 + 即时反馈 + 进度)
|
||||
- 学生身份校验(防止跨用户访问)
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic`
|
||||
- Server Action:`getPracticeSessionById(sessionId, ctx.userId)`
|
||||
- `requirePermission(Permissions.ADAPTIVE_PRACTICE_READ)`
|
||||
- 组件:`PracticeSessionView` / `PracticeServiceProvider`
|
||||
- 路由参数:`sessionId`
|
||||
- `notFound()` 兜底
|
||||
- **ARCHITECTURE.md 契约**:❌
|
||||
|
||||
---
|
||||
|
||||
### 2.15 elective 模块(2 页规划,0 已完成,2 缺失)
|
||||
|
||||
#### 2.15.1 ❌ `/shell/student/elective`(选课列表,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\elective\page.tsx`
|
||||
- **功能描述**:
|
||||
- 上下两段式布局:
|
||||
1. **我的选课**(`MySelectionsLoader`,Suspense 流式加载)
|
||||
2. **可选课程**(`AvailableCoursesLoader`,Suspense 流式加载 + searchParams 过滤)
|
||||
- 学生身份校验
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic`
|
||||
- `requirePermission(Permissions.ELECTIVE_READ)`
|
||||
- 子组件:`MySelectionsLoader` / `AvailableCoursesLoader` / `MySelectionsSkeleton` / `AvailableCoursesSkeleton`(均在 `_components/` 下)
|
||||
- `Suspense` 双段流式渲染
|
||||
- searchParams 透传到 `AvailableCoursesLoader`
|
||||
- **ARCHITECTURE.md 契约**:❌
|
||||
|
||||
#### 2.15.2 ❌ `/shell/student/elective/[id]`(选课详情,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\elective\[id]\page.tsx`
|
||||
- **功能描述**:
|
||||
- 选修课程详情视图
|
||||
- **学生视角隐私保护**:只展示课程信息,**不展示选课名单**(`selections=[]`),`showEditButton=false`
|
||||
- 通过 `ElectivePageLayout` + `ElectiveCourseDetail` 组合渲染
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic`
|
||||
- Server Action:`getElectiveCourseById(id)`
|
||||
- `requirePermission(Permissions.ELECTIVE_READ)`
|
||||
- 组件:`ElectiveCourseDetail` / `ElectivePageLayout`
|
||||
- 路由参数:`id`
|
||||
- `notFound()` 兜底
|
||||
- **ARCHITECTURE.md 契约**:❌
|
||||
|
||||
---
|
||||
|
||||
### 2.16 ai-tutor 模块(1 页规划,0 已完成,1 缺失)
|
||||
|
||||
#### 2.16.1 ❌ `/shell/student/ai-tutor`(AI 辅导,缺失)⚠️ B3 末
|
||||
|
||||
- **CICD 参考实现**:❌ CICD 无对应源页面
|
||||
- **功能描述**:
|
||||
- 学生专属 AI 辅导对话(区别于通用 AI 聊天)
|
||||
- 应基于学生学情(薄弱点、近期错题、当前进度)提供个性化辅导
|
||||
- 可能的形态:聊天对话框 + 上下文卡片(学情摘要)
|
||||
- **技术栈建议**:参考 CICD `learning/study-path/page.tsx` 的 `AiStudyPath` + `AiClientProvider` 模式 + `requirePermission(Permissions.AI_CHAT)`
|
||||
- **ARCHITECTURE.md 契约**:❌
|
||||
- **批次**:B3 末
|
||||
|
||||
---
|
||||
|
||||
### 2.17 announcements 模块(共享 2 页规划,0 已完成,2 缺失)
|
||||
|
||||
#### 2.17.1 ❌ `/shell/announcements`(公告列表,缺失,共享)
|
||||
|
||||
- **CICD 参考实现**:❌ CICD `student/` 下无对应源页面(应在 `(dashboard)/` 顶层共享路由中,但本次未读取)
|
||||
- **功能描述**:公告列表(学生可见范围)
|
||||
- **ARCHITECTURE.md 契约**:❌(列表未定义)
|
||||
- **批次**:B3,共享路由
|
||||
|
||||
#### 2.17.2 ❌ `/shell/announcements/[id]`(公告详情,缺失,共享)
|
||||
|
||||
- **CICD 参考实现**:❌ 同上
|
||||
- **功能描述**:单条公告详情
|
||||
- **ARCHITECTURE.md 契约**:❌
|
||||
- **批次**:B3,共享路由
|
||||
|
||||
> **注**:portal-shell 当前 `/shell/announcements/*` 路由不存在。需在共享层(非 student/ 下)创建。
|
||||
|
||||
---
|
||||
|
||||
### 2.18 messages 模块(共享 1 页规划,0 已完成,1 缺失)
|
||||
|
||||
#### 2.18.1 ❌ `/shell/messages`(消息中心,缺失,共享)⚠️ B3 末
|
||||
|
||||
- **CICD 参考实现**:❌ CICD `student/` 下无对应源页面
|
||||
- **功能描述**:站内消息中心(学生收件箱)
|
||||
- **ARCHITECTURE.md 契约**:❌
|
||||
- **批次**:B3 末,共享路由
|
||||
|
||||
> **注**:portal-shell 当前 `/shell/messages` 路由不存在。
|
||||
|
||||
---
|
||||
|
||||
### 2.19 leave 模块(1 页规划,0 已完成,1 缺失)
|
||||
|
||||
#### 2.19.1 ❌ `/shell/student/leave`(学生在线请假,缺失)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\leave\page.tsx`
|
||||
- **功能描述**:
|
||||
- 顶部:在线请假表单(`LeaveRequestForm`,`defaultStudentId` + `defaultClassId` 自动填入当前活跃班级)
|
||||
- 底部:本人提交的请假申请列表(`LeaveRequestList`)
|
||||
- 返回仪表盘的面包屑
|
||||
- 无活跃班级时显示提示卡片
|
||||
- **技术栈**:
|
||||
- Server Component + `force-dynamic`
|
||||
- Server Actions:`getStudentActiveClass(ctx.userId)` + `getLeaveRequests({ scope, currentUserId, page: 1, pageSize: 50 })`
|
||||
- `getAuthContext()`(注意:未用 `requirePermission`,直接取 ctx)
|
||||
- 组件:`LeaveRequestForm` / `LeaveRequestList` / `Card` / `Button`
|
||||
- **scope 处理**:学生 scope 为 `class_members`,`buildScopeFilter` 返回 `1=0`,但通过 `currentUserId = requesterId` 过滤本人记录
|
||||
- **ARCHITECTURE.md 契约**:❌
|
||||
|
||||
---
|
||||
|
||||
### 2.20 diagnostic 模块(CICD 额外页面,ARCHITECTURE.md 未规划)
|
||||
|
||||
#### 2.20.1 ⚠️ CICD `diagnostic/page.tsx`(学生诊断报告,ARCHITECTURE.md 未列入 36 页)
|
||||
|
||||
- **CICD 参考实现**:`e:\desktop\CICD\src\app\(dashboard)\student\diagnostic\page.tsx`
|
||||
- **功能描述**:
|
||||
- 学生诊断学情(`getStudentMasterySummary`)+ 已发布诊断报告列表(`getDiagnosticReports`)
|
||||
- `StudentDiagnosticView` 渲染
|
||||
- 学生仅可见 `status: "published"` 报告(防草稿泄露)
|
||||
- **技术栈**:Server Component + `requirePermission(Permissions.DIAGNOSTIC_READ)`
|
||||
- **ARCHITECTURE.md 契约**:❌ 未列入 §9.2 36 页清单
|
||||
- **建议**:若产品确认学生端诊断报告功能保留,需补充到 ARCHITECTURE.md §9.2;否则可在 dashboard/weakness 中替代承载
|
||||
|
||||
---
|
||||
|
||||
## 三、按模块汇总
|
||||
|
||||
| 模块 | 规划页数 | 已完成 | 缺失 | 备注 |
|
||||
| --------------------- | -------- | ------ | ------ | -------------------------------------------------------------- |
|
||||
| dashboard | 3 | 1 | 2 | 仪表盘基础页有,trend/weakness 详情页缺 |
|
||||
| grades | 2 | 0 | 2 | 列表 + 报告卡 |
|
||||
| exams | 3 | 0 | 3 | ⚠️ CICD 无源页面,take 工作台最关键 |
|
||||
| homework | 3 | 0 | 3 | ⚠️ CICD 路由为 `learning/assignments/*`,需迁移到 `homework/*` |
|
||||
| schedule | 1 | 0 | 1 | |
|
||||
| attendance | 1 | 0 | 1 | |
|
||||
| classes | 1 | 0 | 1 | CICD 无独立路由(融合在 courses) |
|
||||
| courses | 2 | 0 | 2 | CICD 路由为 `learning/courses/*` |
|
||||
| course-plans | 2 | 0 | 2 | |
|
||||
| lesson-plans | 2 | 0 | 2 | |
|
||||
| textbooks | 2 | 0 | 2 | CICD 路由为 `learning/textbooks/*`,需对齐 `/[id]/chapters` |
|
||||
| error-book | 1 | 0 | 1 | 含 AI 上下文 + 客户端列表 |
|
||||
| learning | 2 | 0 | 2 | 学习中心首页 + AI 学习路径 |
|
||||
| practice | 2 | 0 | 2 | 自适应练习 |
|
||||
| elective | 2 | 0 | 2 | 含 Suspense 双段流式渲染 |
|
||||
| ai-tutor | 1 | 0 | 1 | ⚠️ B3 末,CICD 无源页面 |
|
||||
| announcements(共享) | 2 | 0 | 2 | 共享路由,非 student/ 下 |
|
||||
| messages(共享) | 1 | 0 | 1 | ⚠️ B3 末,共享路由 |
|
||||
| leave | 1 | 0 | 1 | |
|
||||
| **合计** | **34** | **1** | **33** | 不含 notifications/settings 共享路由 |
|
||||
|
||||
> **加上 diagnostic(CICD 额外页)共 35**;ARCHITECTURE.md §9.2 规划 36 页(含 notifications/settings 共享路由)。
|
||||
|
||||
---
|
||||
|
||||
## 四、关键技术差异 & 迁移注意事项
|
||||
|
||||
### 4.1 架构模式差异(最重要)
|
||||
|
||||
| 维度 | CICD(参考) | portal-shell(目标) |
|
||||
| -------- | -------------------------------------- | ------------------------------------------------------------------- |
|
||||
| 渲染模式 | Server Component 为主 | 当前仪表盘是 Client Component,需确定后续页面模式 |
|
||||
| 数据获取 | Server Action + Drizzle 直查 DB | **必须改为** BFF / 微服务 API(`teacher-bff` / `data-ana` 等) |
|
||||
| 权限校验 | `requirePermission` + `getAuthContext` | 需通过 Gateway + BFF 鉴权,前端用 `usePermission().hasPermission()` |
|
||||
| 国际化 | `next-intl` `getTranslations` | portal-shell 当前仪表盘硬编码中文,需统一策略 |
|
||||
| 共享 UI | `@/shared/components/ui/*` | `@/shared/components/ui/*`(已迁移部分) |
|
||||
| 模块组件 | `@/modules/<domain>/components/*` | 需在 portal-shell 重建或下沉到 BFF |
|
||||
|
||||
### 4.2 路由路径对齐
|
||||
|
||||
| CICD 路径 | ARCHITECTURE.md §9.2 目标路径 | 备注 |
|
||||
| -------------------------------------------- | ----------------------------- | --------------------------- |
|
||||
| `learning/assignments` | `homework` | 提升到顶层 |
|
||||
| `learning/assignments/[assignmentId]` | `homework/[id]/submit` | 路径参数改名 |
|
||||
| `learning/assignments/[assignmentId]/result` | `homework/[id]/analysis` | 子路径改名 |
|
||||
| `learning/courses` | `courses` | 提升到顶层 |
|
||||
| `learning/courses/[classId]` | `courses/[id]` | 参数名 `classId` → `id` |
|
||||
| `learning/textbooks` | `textbooks` | 提升到顶层 |
|
||||
| `learning/textbooks/[id]` | `textbooks/[id]/chapters` | 增加子路径 `chapters` |
|
||||
| `learning/study-path` | `learning-path` | 提升到顶层 |
|
||||
| `(无)` | `exams/*` | 全新设计 |
|
||||
| `(无)` | `ai-tutor` | 全新设计 |
|
||||
| `(无)` | `classes` | 全新设计(与 courses 区分) |
|
||||
|
||||
### 4.3 权限点映射
|
||||
|
||||
CICD 中学生页面用到的权限点(迁移时需在 portal-shell `Permissions` 常量中对应):
|
||||
|
||||
- `GRADE_RECORD_READ`(grades / report-card)
|
||||
- `CLASS_READ`(schedule / courses)
|
||||
- `ATTENDANCE_READ`(attendance)
|
||||
- `COURSE_PLAN_READ`(course-plans)
|
||||
- `LESSON_PLAN_READ`(lesson-plans)
|
||||
- `TEXTBOOK_READ`(textbooks)
|
||||
- `ERROR_BOOK_READ`(error-book)
|
||||
- `AI_CHAT`(study-path / ai-tutor)
|
||||
- `ADAPTIVE_PRACTICE_READ`(practice)
|
||||
- `ELECTIVE_READ`(elective)
|
||||
- `DIAGNOSTIC_READ`(diagnostic,CICD 额外)
|
||||
- leave 用 `getAuthContext` 而非 `requirePermission`(需统一)
|
||||
|
||||
### 4.4 共享组件清单(需在 portal-shell 补齐或确认已有)
|
||||
|
||||
- `DashboardShell` / `DashboardSection` / `StatCard`(仪表盘已有)
|
||||
- `Card` / `CardContent` / `CardHeader` / `CardTitle`(基础)
|
||||
- `Button` / `Badge` / `EmptyState` / `Skeleton`(基础)
|
||||
- `StatsGrid`(多列统计,error-book/practice 用)
|
||||
- `WidgetBoundary`(widget 降级容错)
|
||||
- `StatusBadge` + `variantMap`(作业状态徽章)
|
||||
- `TextbookReader` / `TextbookCard` / `TextbookFilters`(教材相关)
|
||||
- `LessonPlanReadonlyView` / `LessonPlanList`(教案相关)
|
||||
- `CoursePlanList` / `CoursePlanDetail`(课程计划)
|
||||
- `StudentScheduleView` / `StudentScheduleFilters`(课表)
|
||||
- `StudentCoursesView` / `CourseFilters`(课程)
|
||||
- `StudentAttendanceView`(考勤)
|
||||
- `StudentGradeSummary` / `GradeTrendCard` / `RankingTrendCard` / `GradeDistributionChart` / `GrowthArchiveChart` / `ReportCardView` / `ReportCardPrintAction` / `StudentGradeFilters`(成绩,组件最多)
|
||||
- `HomeworkTakeView` / `HomeworkReviewView` / `HomeworkSubmissionResult` / `AssignmentFilters`(作业,⚠️ take 是最复杂)
|
||||
- `PracticeStarterWithNav` / `PracticeHistory` / `PracticeSessionView` / `PracticeServiceProvider`(练习)
|
||||
- `ElectiveCourseDetail` / `ElectivePageLayout` / `MySelectionsLoader` / `AvailableCoursesLoader`(选课)
|
||||
- `LeaveRequestForm` / `LeaveRequestList`(请假)
|
||||
- `StudentErrorBookListClient` / `AddErrorBookDialogWithQuestions` / `ErrorBookFilters`(错题本)
|
||||
- `AiStudyPath` / `AiClientProvider` / `createCoreAiClientService`(AI)
|
||||
|
||||
### 4.5 B3 实施优先级建议
|
||||
|
||||
按用户价值 + 实现复杂度排序:
|
||||
|
||||
1. **P0(必做,核心学习闭环)**:homework 列表 + submit 工作台 + analysis、exams 列表 + take 工作台 + result
|
||||
2. **P1(高频查看)**:grades 列表 + report-card、schedule、attendance、error-book
|
||||
3. **P2(学习资源)**:learning 首页、courses 列表 + 详情、textbooks 列表 + chapters、course-plans + 详情、lesson-plans + view
|
||||
4. **P3(辅助功能)**:classes、practice + session、elective + 详情、leave
|
||||
5. **P4(增强)**:dashboard trend/weakness 详情页、learning-path
|
||||
6. **P5(B3 末)**:ai-tutor、messages
|
||||
7. **共享**:announcements 列表 + 详情
|
||||
|
||||
---
|
||||
|
||||
## 五、CICD 与 ARCHITECTURE.md §9.2 对照表
|
||||
|
||||
| ARCH §9.2 源路由 | ARCH §9.2 目标路由 | CICD 是否有源页面 | portal-shell 是否已有 | 契约状态 | 备注 |
|
||||
| --------------------------- | ------------------------------------------- | -------------------------------------- | --------------------- | --------------------- | -------------------------------- |
|
||||
| `dashboard` | `/shell/student` | ✅ | ✅ | ✅ `studentDashboard` | 已完成基础版 |
|
||||
| `/trend` | `/shell/student/trend` | ❌(融合在 dashboard) | ❌ | ✅ `learningTrend` | 需新建详情页 |
|
||||
| `/weakness` | `/shell/student/weakness` | ❌(融合在 dashboard) | ❌ | ✅ `studentWeakness` | 需新建详情页 |
|
||||
| `my-grades` | `/shell/student/grades` | ✅ | ❌ | ❌ | |
|
||||
| `/report-card` | `/shell/student/grades/report-card` | ✅ | ❌ | ❌ | |
|
||||
| `my-exams` | `/shell/student/exams` | ❌ | ❌ | 🟡 | CICD 无,全新设计 |
|
||||
| `/[id]/result` | `/shell/student/exams/[id]/result` | ❌ | ❌ | 🟡 | 参考作业 result |
|
||||
| `/[id]/take` | `/shell/student/exams/[id]/take` | ❌ | ❌ | 🟡 | ⚠️ 最关键,参考 HomeworkTakeView |
|
||||
| `my-homework` | `/shell/student/homework` | ✅(learning/assignments) | ❌ | 🟡 | 路径迁移 |
|
||||
| `/[id]/submit` | `/shell/student/homework/[id]/submit` | ✅(learning/assignments/[id]) | ❌ | 🟡 | ⚠️ take 工作台 |
|
||||
| `/[id]/analysis` | `/shell/student/homework/[id]/analysis` | ✅(learning/assignments/[id]/result) | ❌ | 🟡 | |
|
||||
| `schedule` | `/shell/student/schedule` | ✅ | ❌ | ❌ | |
|
||||
| `my-attendance` | `/shell/student/attendance` | ✅ | ❌ | ❌ | |
|
||||
| `my-classes` | `/shell/student/classes` | ❌(融合在 courses) | ❌ | ❌ `myClasses` | 全新设计 |
|
||||
| `courses` | `/shell/student/courses` | ✅(learning/courses) | ❌ | ❌ | 路径迁移 |
|
||||
| `/[id]` | `/shell/student/courses/[id]` | ✅(learning/courses/[classId]) | ❌ | ❌ | 参数名 classId→id |
|
||||
| `course-plans` | `/shell/student/course-plans` | ✅ | ❌ | ❌ | |
|
||||
| `/[id]` | `/shell/student/course-plans/[id]` | ✅ | ❌ | ❌ | |
|
||||
| `lesson-plans` | `/shell/student/lesson-plans` | ✅ | ❌ | ❌ | |
|
||||
| `/[id]/view` | `/shell/student/lesson-plans/[planId]/view` | ✅ | ❌ | ❌ | |
|
||||
| `textbooks` | `/shell/student/textbooks` | ✅(learning/textbooks) | ❌ | 🟡 | 路径迁移 |
|
||||
| `/[id]/chapters` | `/shell/student/textbooks/[id]/chapters` | ✅(learning/textbooks/[id]) | ❌ | 🟡 | 增加子路径 |
|
||||
| `error-book` | `/shell/student/error-book` | ✅ | ❌ | ✅ | 含 AI 上下文 |
|
||||
| `learning` | `/shell/student/learning` | ✅ | ❌ | ❌ | |
|
||||
| `learning-path` | `/shell/student/learning-path` | ✅(learning/study-path) | ❌ | ❌ | 路径迁移 |
|
||||
| `practice` | `/shell/student/practice` | ✅ | ❌ | ❌ | |
|
||||
| `/[sessionId]` | `/shell/student/practice/[sessionId]` | ✅ | ❌ | ❌ | |
|
||||
| `elective` | `/shell/student/elective` | ✅ | ❌ | ❌ | |
|
||||
| `/[id]` | `/shell/student/elective/[id]` | ✅ | ❌ | ❌ | |
|
||||
| `ai-tutor` | `/shell/student/ai-tutor` | ❌ | ❌ | ❌ | B3 末,全新设计 |
|
||||
| `announcements` | `/shell/announcements`(共享) | ❌(不在 student/ 下) | ❌ | ❌ | 共享路由 |
|
||||
| `/[id]` | `/shell/announcements/[id]`(共享) | ❌ | ❌ | ❌ | 共享路由 |
|
||||
| `messages` | `/shell/messages`(共享) | ❌ | ❌ | ❌ | B3 末,共享路由 |
|
||||
| `leave` | `/shell/student/leave` | ✅ | ❌ | ❌ | |
|
||||
| `notifications`、`settings` | 共享路由 | — | ❌ | ✅ | B1/B3,不在 36 页内 |
|
||||
| `diagnostic`(CICD 额外) | —(未列入 §9.2) | ✅ | ❌ | — | 需产品决策是否保留 |
|
||||
|
||||
---
|
||||
|
||||
## 六、风险与建议
|
||||
|
||||
### 6.1 高风险点
|
||||
|
||||
1. **exams/[id]/take 作答工作台**:CICD 完全无源可参考(仅有 `HomeworkTakeView` 同构参考),需从零设计考试特性(倒计时、断网恢复、批量提交、防作弊等)
|
||||
2. **路由路径大调整**:6 类路径需迁移(learning/* → 顶层),需同步更新导航、面包屑、内链
|
||||
3. **架构模式转变**:portal-shell 已转向 BFF + 微服务,**不能照搬 CICD 的 Server Action + Drizzle 直查模式**,每个页面都需重新设计数据获取链路(BFF → data-ana / core-edu 等服务)
|
||||
4. **国际化缺失**:当前仪表盘硬编码中文,36 页全部完成后需补 i18n,建议从一开始就用 `next-intl`
|
||||
5. **权限校验缺失**:当前仪表盘无 `requirePermission`,需建立 portal-shell 学生域权限校验中间件/装饰器
|
||||
|
||||
### 6.2 建议
|
||||
|
||||
1. **先建契约**:开工前先在 `shared-proto` 中补齐 §9.2 标 ❌ / 🟡 的契约(特别是 exams 系列、my-classes、homework 等)
|
||||
2. **统一渲染模式**:建议学生页面统一采用 Server Component + BFF 数据获取(与 CICD 一致),避免当前仪表盘的 Client Component 模式
|
||||
3. **统一权限模型**:建立 portal-shell 学生域 `RequirePermission` 装饰器/中间件,覆盖所有页面
|
||||
4. **共享组件下沉**:CICD 中 `@/modules/<domain>/components/*` 的视图组件需评估是下沉到 BFF 返回结构化数据,还是在 portal-shell 重建
|
||||
5. **CICD diagnostic 决策**:产品需确认是否保留学生端诊断报告功能,若保留需补充 ARCHITECTURE.md §9.2
|
||||
6. **分批推进**:按本报告 §4.5 的 P0→P5 优先级分批实施,每批完成后跑 `pnpm run arch:scan` 同步 arch.db
|
||||
|
||||
---
|
||||
|
||||
**分析完成。共发现 35 个待完成页面(含 CICD 额外的 diagnostic 1 页),其中 33 个完全缺失、2 个为 dashboard 详情页缺失。最关键的 exams/[id]/take 作答工作台在 CICD 中无源页面,需重点设计。**
|
||||
Reference in New Issue
Block a user