Files
Edu/apps/portal-shell/docs/needtodo/parent-NeedTodo.md
SpecialX 04b7a40bdc feat(portal-shell): 学生域全页面迁移与规范合规修复
- 学生域 32 页全量迁移(含作答/自动保存/提交/诊断)

- 补齐 4 个 MSW mock 缺口,修 diagnostic case 名

- 修 4 处 Tailwind 任意值;新增共享组件与路由
2026-08-31 11:25:21 +08:00

769 lines
54 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 家长域Parent实现完整性核查报告
> 参考项目:`e:\Desktop\CICD\src\app\(dashboard)\parent\`
> 当前项目:`e:\Desktop\Edu\apps\portal-shell\src\app\shell\parent\`
> 规划依据:`apps/portal-shell/ARCHITECTURE.md` §9.324 页B4 批次)
> 核查日期2026-08-04
> 任务范围:仅核查与文档更新,不修改源代码
---
## 一、页面完成度总览
### 1.1 portal-shell 家长域现状
当前 `apps/portal-shell/src/app/shell/parent/` 下**仅有 1 个页面**
| 路径 | 状态 | 说明 |
| ------------------------ | --------- | ------------------------------------------------ |
| `/shell/parent/page.tsx` | ✅ 已完成 | 家长仪表盘(仅基础版,缺 trend/weakness 详情页) |
### 1.2 完成度统计
| 状态 | 数量 | 说明 |
| ------------ | ------ | ----------------------------------------------------------------------- |
| ✅ 已完成 | 1 | `/shell/parent/page.tsx`(仪表盘基础版,仍缺 2 个详情页) |
| 🟡 部分完成 | 1 | dashboard 模块基础页有trend/weakness 详情页缺) |
| ❌ 缺失 | 22 | 见下方模块清单 |
| **规划总数** | **24** | ARCHITECTURE.md §9.3 B4 批次(含 notifications/settings 共享路由 2 页) |
### 1.3 portal-shell 仪表盘与 CICD 仪表盘的技术差异(关键架构差异)
| 维度 | CICD 仪表盘 | portal-shell 仪表盘 |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
| 渲染模式 | Server Component`async function` | Client Component`"use client"` |
| 数据获取 | Server Action `getParentDashboardAction()` + React `use()` 流式渲染 | `useParentDashboard()` Hook`@/lib/api`,走 BFF |
| 国际化 | `next-intl` `getTranslations` | 无(硬编码中文) |
| 权限校验 | `getAuthContext` + dataScope 类型守卫 | 无 |
| 视图组件 | `ParentDashboard` / `ChildCard` / `ParentAttentionBanner` / `AiChildSummary`(拆分到 `@/modules/dashboard/components` / `@/modules/parent/components` / `@/modules/ai/components` | 直接内联在 page.tsx |
| 数据来源 | 直查 DBDrizzle | 走 data-ana 微服务聚合(`parentDashboard` 契约) |
| 多子女支持 | ✅ 子女卡片网格 + AI 学情摘要(每子女一张) | ❌ 仅展示 `child_avg_score` / `child_class_rank` 等单值字段 |
> **重要提示**portal-shell 已转向微服务 + BFF 架构,迁移时**不能照搬 CICD 的 Server Action + Drizzle 直查模式**。家长页面应通过 `teacher-bff` / `data-ana` 等服务的 gRPC/HTTP API 获取数据,前端通过 hooks 消费。家长域多为**只读视图**,重点在 `myChildren` 契约 + `child-overview` 聚合。
### 1.4 portal-shell 家长域资产核查features / lib/api / mocks已实际读取源码确认
#### 1.4.1 features/parent/ client 组件
**`src/features/parent/` 目录不存在**。当前 `src/features/` 下仅有:`admin` / `notifications` / `settings` / `shared` / `student` / `teacher`
> **结论**:家长域**完全没有 features 层 client 组件**。CICD 中家长域依赖的模块组件(`ParentDashboard` / `ChildCard` / `ParentChildrenDataPage` / `ParentNoChildrenPage` / `ChildDetailHeader` / `SiblingSwitcher` / `StudentGradeSummary` / `GradeTrendCard` / `ReportCardView` / `ParentAttendanceCalendar` / `CoursePlanList` / `LessonPlanReadonlyView` / `StudentDiagnosticView` / `PracticeHistory` / `ParentSelectionView` / `LeaveRequestForm` 等)在 portal-shell 中**均未建立**,需在 B4 批次逐模块重建或下沉。
#### 1.4.2 lib/api/ 家长相关 API hooks
家长相关 hooks 分布在 2 个文件,共 **5 个 hooks**
**`src/lib/api/dashboard.ts`1 个 hook**
- `useParentDashboard()`:查询 `parentDashboard` 根字段,返回 `ParentDashboard | null`。operation`GET_PARENT_DASHBOARD_DOC`,类型 `ParentDashboard` 字段 snake_case 对齐 data-ana 子图。
**`src/lib/api/parent.ts`4 个 hooks + 领域模型)**
- `useParentChildren()`:查询 `myChildren``GET_MY_CHILDREN_OVERVIEW_DOC`),返回 `ChildSummary[]`(含 `recentGrades` / `attendance` / `homeworkCompletion`
- `useLeaveRequests(childId, status)`:查询 `leaveRequests``GET_LEAVE_REQUESTS_DOC`),按孩子 ID 与状态筛选
- `useApproveLeave()``APPROVE_LEAVE_DOC` mutation失败抛 `ApiError`
- `useRejectLeave()``REJECT_LEAVE_DOC` mutation需 reason失败抛 `ApiError`
领域模型类型:`ChildSummary` / `ChildGrade` / `ChildAttendance` / `ChildHomeworkCompletion` / `LeaveRequest` / `LeaveType` / `LeaveStatus`
operations 文件:`src/lib/api/operations/parent.graphql.ts`4 个 document。导出`src/lib/api/index.ts` 第 36 行 `export * from "./parent";`
> **结论**lib/api 层家长 hooks 已就绪 5 个(仪表盘 + 子女概览 + 请假审批链路。§9.3 其余 18+ 页面所需 hooksgrades / report-card / exams / homework / attendance / classes / course-plans / lesson-plans / error-book / diagnostic / learning-path / practice / elective / preferences 等)**均未建立**。注:`lib/api/` 下虽有 `grades.ts` / `attendance.ts` 等同名文件,但属学生域 / 通用域 hooks家长域多子女聚合 + 只读过滤尚未单独建模。
#### 1.4.3 src/mocks/graphql-data.ts 家长相关 mock 数据
| Mock 资产 | 位置 | 状态 | 服务对象 |
| -------------------------------- | ---------------------- | ----------------- | ----------------------------------------------------------------------------------------- |
| `mockParentDashboard` | `graphql-data.ts:84` | ✅ 存在 | `GetParentDashboard` 查询(仪表盘页) |
| `GetParentDashboard` case 分支 | `graphql-data.ts:5577` | ✅ 存在 | 仪表盘 hook 兜底 |
| `mockLeaveRequests` | `graphql-data.ts:4143` | 🟡 存在但属教师域 | `GetTeacherLeaveRequests`(教师域 B2 |
| `GetMyChildrenOverview` mock | — | ❌ **缺失** | `useParentChildren` 无兜底 |
| `GetLeaveRequests`家长版mock | — | ❌ **缺失** | `useLeaveRequests` 无兜底(教师版结构 `{ items, total }` 与家长版 `LeaveRequest[]` 不同) |
| `ApproveLeave` mock | — | ❌ **缺失** | `useApproveLeave` 无兜底 |
| `RejectLeave` mock | — | ❌ **缺失** | `useRejectLeave` 无兜底 |
> **结论**:家长域 mock **仅仪表盘 1 项就绪**`useParentChildren` / `useLeaveRequests`(家长版)/ `useApproveLeave` / `useRejectLeave` 4 个 hook 在 dev 环境**无 MSW 兜底**(会触发 Apollo 错误或空态)。需在 B4 补齐 4 个 mock否则 dev 环境无法演示。
---
## 二、缺失页面清单(按模块分组)
### 2.1 dashboard 模块3 页规划1 已完成2 缺失)
#### 2.1.1 ✅ `/shell/parent/page.tsx`(已完成)
- **portal-shell 实现**:基础仪表盘,显示孩子平均分 / 班级排名 / 薄弱知识点 / 预警通知
- **技术栈**Client Component + `useParentDashboard()` Hook + `DashboardShell` / `StatCard` 共享组件
- **CICD 参考实现**`e:\Desktop\CICD\src\app\(dashboard)\parent\dashboard\page.tsx`
- **CICD 技术栈**Server Component + `getParentDashboardAction()` Server Action + `ParentDashboard` 视图组件 + React `use()` 流式渲染 + `generateMetadata`
- **CICD 关键功能**
- 无子女时显示 `ParentNoChildrenPage` 空态
- 子女卡片列表(移动端水平滑动 + 桌面端网格,响应式)
- AI 学情摘要区域(`AiChildSummary`,每子女一张,客户端组件,由 `AiClientProvider` 注入数据服务)
- 家长关注横幅(`ParentAttentionBanner`
- 传入 `homeworkCompletionRate` 等"已知安全字段"给 AI
- **ARCHITECTURE.md 契约**:✅ `parentDashboard`
#### 2.1.2 ❌ `/shell/parent/trend`(学习趋势详情页,缺失)
- **CICD 参考实现**CICD 无独立 `/trend` 页面(融合在 dashboard 与 grades 中以趋势卡片呈现)
- **功能描述**:家长视角的学习趋势详情页,应展示:
- 多子女学习趋势对比
- 历史成绩趋势、知识点掌握趋势、对比基线
- 跨学年/学期聚合
- **技术栈建议**:复用 `parentDashboard` 契约扩展字段 + 趋势图组件Recharts/Echarts多子女对比布局参考 `ParentChildrenDataPage`
- **ARCHITECTURE.md 契约**:✅ `parentDashboard`(需扩展 trend 子契约)
- **CICD 关键代码片段**dashboard 中仅有 `ParentAttentionBanner`grades 页面中 `GradeTrendCard` + `GrowthArchiveChart` 是趋势相关参考
#### 2.1.3 ❌ `/shell/parent/weakness`(薄弱知识点详情页,缺失)
- **CICD 参考实现**CICD 无独立 `/weakness` 页面(融合在 dashboard / error-book 中以 `weakKps` / `child_weak_points` 呈现)
- **功能描述**:家长视角的薄弱知识点详情页,应展示:
- 多子女薄弱知识点汇总
- 按学科分组、关联错题、推荐练习
- 掌握率进度条
- **技术栈建议**:复用 `error-book` 模块的 `getKnowledgePointWeakness` 模式 + `Progress` 组件
- **ARCHITECTURE.md 契约**:✅ `parentDashboard`(需扩展 weakness 子契约)
- **CICD 关键代码片段**`error-book/page.tsx``weakKps.map` 渲染 `Progress` 进度条 + `kp.knowledgePointName` + `kp.errorCount` + `kp.masteryRate` 是直接参考
---
### 2.2 children 模块1 页规划0 已完成1 缺失)⚠️ 重点
#### 2.2.1 ❌ `/shell/parent/children/[studentId]`(子女详情页,缺失)⚠️ 重要
- **CICD 参考实现**`e:\Desktop\CICD\src\app\(dashboard)\parent\children\[studentId]\page.tsx`
- **功能描述**
- **单个子女的完整详情视图**(家长域最核心页面)
- **双重权限校验**
1. `verifyParentChildRelationAction(studentId)` 校验家长与子女存在关系防跨家庭信息泄露G4-002 审计修复)
2. dataScope 二次校验:`ctx.dataScope.type === "all"``childrenIds.includes(studentId)`
- 校验失败显示 `EmptyState` + `ShieldAlert` 图标("访问被拒绝"
- **头部**`ChildDetailHeader`(子女基本信息)
- **主体面板**`ChildDetailPanel`(多 Tab 切换视图,`initialTab` 来自 searchParams
- **兄弟姐妹切换器**`SiblingSwitcher`(在多子女家庭中快速切换查看不同子女)
- 并行拉取:`getChildDashboardDataAction(studentId)` + `getChildNameListAction()`
- `notFound()` 兜底(子女不存在)
- **技术栈**
- Server Component + `force-dynamic`
- Server Actions`verifyParentChildRelationAction` / `getChildDashboardDataAction` / `getChildNameListAction`(均来自 `@/modules/parent/actions`
- `requireAuth()` + `getAuthContext()` 双重身份校验
- 组件:`ChildDetailHeader` / `ChildDetailPanel` / `SiblingSwitcher` / `EmptyState`
- 路由参数:`studentId`
- searchParams`tab`(初始 Tab
- 工具:`getSearchParam`
- **ARCHITECTURE.md 契约**:❌ `myChildren`(需新建,是家长域核心契约)
- **CICD 关键代码片段**
```tsx
const relation = await verifyParentChildRelationAction(studentId)
const isInScope = ctx.dataScope.type === "all" ||
(ctx.dataScope.type === "children" && ctx.dataScope.childrenIds.includes(studentId))
if (!relation || !isInScope) { return <EmptyState icon={ShieldAlert} ... /> }
```
> ⚠️ **此页是家长域最核心页面**是其他模块grades/attendance/homework 等)子女切换的"枢纽"。`myChildren` 契约必须在 B4 首位补齐。
---
### 2.3 grades 模块2 页规划0 已完成2 缺失)
#### 2.3.1 ❌ `/shell/parent/grades`(子女成绩列表,缺失)
- **CICD 参考实现**`e:\Desktop\CICD\src\app\(dashboard)\parent\grades\page.tsx`
- **功能描述**
- **多子女成绩对比视图**(家长域特色)
- 每个子女一块:姓名标题 + **导出按钮**`ParentExportButton`,按 studentId 导出)
- **成绩趋势卡片**`GradeTrendCard`含班级平均对比线v3-P2-8 补齐)
- **纵向成长档案图**`GrowthArchiveChart`P3-4 新增,跨学年/学期聚合)
- 学生成绩汇总(`StudentGradeSummary`
- 使用 `Promise.allSettled` 容错:单个子女查询失败不影响其他子女展示
- 用循环 + 类型守卫替代 `as` 断言P1-8 修复)
- **技术栈**
- Server Component + `force-dynamic`
- Server Actions`getStudentGradeSummary(id, ctx.dataScope)` / `getClassAverageTrend(id, undefined, undefined, ctx.dataScope)` / `getStudentGrowthArchive(id, ctx.dataScope)`
- `requirePermission(Permissions.GRADE_RECORD_READ)`
- dataScope 校验:`ctx.dataScope.type === "children"` 且 `childrenIds.length > 0`,否则显示 `ParentNoChildrenPage`
- 组件:`ParentChildrenDataPage` / `ParentNoChildrenPage` / `ParentExportButton` / `GradeTrendCard` / `GrowthArchiveChart` / `StudentGradeSummary`
- 类型:`ClassAverageTrendResult` / `StudentGrowthArchiveResult`
- **ARCHITECTURE.md 契约**:❌(列表,未定义)
#### 2.3.2 ❌ `/shell/parent/grades/report-card`(子女成绩报告卡,缺失)
- **CICD 参考实现**`e:\Desktop\CICD\src\app\(dashboard)\parent\grades\report-card\page.tsx`
- **功能描述**
- 学年 / 学期可切换的成绩报告卡(家长视角)
- **必填查询参数**`studentId`(必须在家长子女范围内)
- 可选参数:`academicYearId` / `semester`"1" | "2"
- 缺少 `studentId` 时显示提示空态 + 返回按钮
- 报告卡视图(`ReportCardView`,子女维度聚合)
- **打印操作**`ReportCardPrintAction`
- 返回成绩列表的面包屑(`ArrowLeft` + Link
- 学年数量提示
- **技术栈**
- Server Component + `force-dynamic`
- Server Actions`getReportCardData(studentId, ctx.dataScope, { academicYearId, semester })` + `getAcademicYears()`
- `requirePermission(Permissions.GRADE_RECORD_READ)`
- 组件:`ReportCardView` / `ReportCardPrintAction` / `Button` / `EmptyState`
- 工具:`getParam` / `SearchParams` 类型
- searchParams`studentId` / `academicYearId` / `semester`
- dataScope 在 data-access 层校验子女归属(防跨家庭泄露)
- **ARCHITECTURE.md 契约**:❌(未单独定义)
---
### 2.4 exams 模块2 页规划0 已完成2 缺失)⚠️ CICD 无源
> **CICD 参考项目无 exams 模块家长页面**。家长考试相关功能需 portal-shell 从零设计。
#### 2.4.1 ❌ `/shell/parent/exams`(子女考试列表,缺失)
- **CICD 参考实现**:❌ CICD 无对应源页面
- **功能描述**:家长视角的子女考试列表,应展示:
- 多子女考试汇总(每个子女一块)
- 即将到来的考试(含倒计时、考场、座位号)
- 已结束考试(含成绩、查看结果入口)
- 按学科 / 状态过滤
- **技术栈建议**:参考 CICD `parent/grades/page.tsx` 的 `ParentChildrenDataPage` 多子女布局模式 + `parent/practice/page.tsx` 的单/多子女分支渲染
- **ARCHITECTURE.md 契约**:🟡(部分,需补充)
#### 2.4.2 ❌ `/shell/parent/exams/[id]/result`(子女考试结果页,缺失)
- **CICD 参考实现**:❌ CICD 无对应源页面(可参考 `parent/grades/report-card/page.tsx` 的 searchParams + 权限校验模式)
- **功能描述**
- 子女考试得分、排名、班级均分对比
- 题目作答详情(每题对错、参考答案、子女答案)
- 知识点掌握情况
- 错题一键加入错题本入口
- **技术栈建议**:参考 CICD `parent/grades/report-card/page.tsx` 的 `verifyParentChildRelationAction` + dataScope 双重校验模式
- **ARCHITECTURE.md 契约**:🟡(部分,需补充)
---
### 2.5 homework 模块1 页规划0 已完成1 缺失)⚠️ CICD 无源
#### 2.5.1 ❌ `/shell/parent/homework`(子女作业查看,缺失)⚠️ CICD 无源
- **CICD 参考实现**:❌ CICD 无对应源页面
- **功能描述**:家长视角查看子女作业,应展示:
- 多子女作业汇总(每个子女一块)
- 作业列表(标题、状态徽章、截止时间、剩余尝试次数、最新得分、逾期提示)
- 按学科分组 + 状态过滤all/pending/submitted/graded
- **只读视图**(家长不能提交作业,仅查看)
- **技术栈建议**:参考 CICD `parent/practice/page.tsx` 的 `ParentChildrenDataPage` + 单/多子女分支 + `StatsGrid` 统计模式;状态徽章参考学生域 `StatusBadge` + `variantMap`
- **ARCHITECTURE.md 契约**:❌
---
### 2.6 attendance 模块1 页规划0 已完成1 缺失)
#### 2.6.1 ❌ `/shell/parent/attendance`(子女考勤,缺失)
- **CICD 参考实现**`e:\Desktop\CICD\src\app\(dashboard)\parent\attendance\page.tsx`
- **功能描述**
- **多子女考勤对比视图**(家长域特色)
- 顶部 `headerExtra`:出勤率卡片(`ParentAttendanceRateCard`+ 考勤预警(`ParentAttendanceWarning`
- 每个子女一块:姓名标题 + **考勤日历**`ParentAttendanceCalendar`+ **考勤明细**`ParentStudentAttendanceDetail`
- 使用 `Promise.allSettled` 容错
- **类型映射解耦**:将 attendance 模块的 `StudentAttendanceSummary` 映射为 parent 模块的 `ParentStudentAttendanceSummary`P1-2 解耦parent 模块仅消费自身类型)
- 通过接口抽象消费 attendance 数据P1-2 修复:不再直接 import data-access
- **技术栈**
- Server Component + `force-dynamic`
- Server Actions`createAttendanceReadService(ctx.dataScope).getStudentSummary(id)`(接口抽象)
- `getAuthContext()`(注意:未用 `requirePermission`,直接取 ctx
- dataScope 校验:`ctx.dataScope.type === "children"` 且 `childrenIds.length > 0`,否则显示 `ParentNoChildrenPage`
- 组件:`ParentChildrenDataPage` / `ParentNoChildrenPage` / `ParentAttendanceWarning` / `ParentAttendanceRateCard` / `ParentAttendanceCalendar` / `ParentStudentAttendanceDetail`
- 类型:`ParentStudentAttendanceSummary` / `AttendanceReadService`
- 映射函数:`toParentSummary`(手动字段映射)
- **ARCHITECTURE.md 契约**:❌
---
### 2.7 classes 模块1 页规划0 已完成1 缺失)⚠️ CICD 无源
#### 2.7.1 ❌ `/shell/parent/classes`(子女班级信息,缺失)⚠️ CICD 无源
- **CICD 参考实现**:❌ CICD 无对应源页面CICD 仅在 `course-plans` 中通过 `getStudentActiveClassId` 间接消费班级数据)
- **功能描述**:家长视角的子女班级信息,应展示:
- 多子女班级列表(每个子女一块)
- 班级基本信息(班名、班主任、任课教师、教室)
- 班级近期动态(作业、考试、公告)
- **技术栈建议**:参考 CICD `parent/course-plans/page.tsx` 的 `getStudentActiveClassId(sid)` 多子女并行查询模式 + `ParentChildrenDataPage` 布局
- **ARCHITECTURE.md 契约**:❌
---
### 2.8 course-plans 模块2 页规划0 已完成2 缺失)
#### 2.8.1 ❌ `/shell/parent/course-plans`(课程计划列表,缺失)
- **CICD 参考实现**`e:\Desktop\CICD\src\app\(dashboard)\parent\course-plans\page.tsx`
- **功能描述**
- 家长视角:解析**所有孩子的班级 ID**,用于过滤课程计划
- 并行查询每个子女的活跃班级 ID`getStudentActiveClassId`
- 仅查询 `status: "active"` 的课程计划
- 使用 `CoursePlanList` 组件渲染(`detailBaseHref="/parent/course-plans"`
- 权限上下文:`{ userId, isAdmin: false, classIds }`(家长非管理员,仅限指定班级)
- **技术栈**
- Server Component + `force-dynamic`
- Server Actions`getCoursePlans({ status: "active" }, { userId, isAdmin: false, classIds })` + `getStudentActiveClassId(sid)`(并行 `Promise.all`
- `requirePermission(Permissions.COURSE_PLAN_READ)`
- dataScope 类型守卫:`ctx.dataScope.type === "children"` 且 `childrenIds.length > 0`
- 组件:`CoursePlanList`
- 类型守卫:`filter((id): id is string => id !== null)`
- **ARCHITECTURE.md 契约**:❌
#### 2.8.2 ❌ `/shell/parent/course-plans/[id]`(课程计划详情,缺失)
- **CICD 参考实现**`e:\Desktop\CICD\src\app\(dashboard)\parent\course-plans\[id]\page.tsx`
- **功能描述**
- 家长视角:仅允许查看**孩子所在班级**的课程计划
- 解析所有孩子的班级 ID传入权限上下文
- 若计划不在子女班级范围内,`notFound()` 兜底
- 使用 `CoursePlanDetail` 组件渲染(`backHref` / `successHref` 均指向 `/parent/course-plans`
- **技术栈**
- Server Component + `force-dynamic`
- Server Actions`getCoursePlanById(id, { userId, isAdmin: false, classIds })` + `getStudentActiveClassId(sid)`(并行)
- `requirePermission(Permissions.COURSE_PLAN_READ)`
- 组件:`CoursePlanDetail`
- 路由参数:`id`
- `notFound()` 兜底
- **ARCHITECTURE.md 契约**:❌
---
### 2.9 lesson-plans 模块2 页规划0 已完成2 缺失)
#### 2.9.1 ❌ `/shell/parent/lesson-plans`(教案列表,缺失)
- **CICD 参考实现**`e:\Desktop\CICD\src\app\(dashboard)\parent\lesson-plans\page.tsx`
- **功能描述**
- 家长视角:仅查看**已发布**教案(`status: "published"`
- 学科选项并行加载(`getSubjectOptions`
- **角色配置注入**`LessonPlanProviderSetup` 包裹,传入 `PARENT_ROLE_CONFIG`使筛选功能生效P0-13 修复)
- `LessonPlanList` 以 `viewMode="parent"` 渲染(只读模式)
- `Suspense` 流式渲染 + Skeleton 占位6 个 `h-[180px]` 卡片骨架)
- **技术栈**
- Server Component + `force-dynamic`
- Server Actions`getLessonPlans({ status: "published" }, ctx.dataScope, ctx.userId)` + `getSubjectOptions()`
- `requirePermission(Permissions.LESSON_PLAN_READ)`V4 P0-2 修复:页面层补齐权限校验)
- 组件:`LessonPlanList` / `LessonPlanProviderSetup` / `Skeleton`
- Provider 配置:`PARENT_ROLE_CONFIG`(来自 `@/modules/lesson-preparation/providers/lesson-plan-provider`
- `viewMode="parent"` 标识家长只读视图
- **ARCHITECTURE.md 契约**:❌
#### 2.9.2 ❌ `/shell/parent/lesson-plans/[planId]/view`(教案只读详情,缺失)
- **CICD 参考实现**`e:\Desktop\CICD\src\app\(dashboard)\parent\lesson-plans\[planId]\view\page.tsx`
- **功能描述**
- 家长视角:仅可查看**孩子所在年级**的已发布课案V4 P0-1 修复,防跨年级信息泄露)
- **scope 校验**`assertPlanInScope(plan, ctx)`,失败 `notFound()`
- 未发布计划显示提示卡片(`readonly.notPublished`
- 教材标题 + 章节标题并行查询V4 P2-1 修复,`Promise.all` 并行)
- `LessonPlanReadonlyView` 渲染计划内容
- 全屏布局(`h-[calc(100vh-4rem)]`
- **技术栈**
- Server Component + `force-dynamic`
- Server Actions`getLessonPlanById(planId, ctx.userId)` + `getTextbookById(plan.textbookId)` + `getChaptersByTextbookId(plan.textbookId)` + `findChapterById(chapters, plan.chapterId)`
- `requirePermission(Permissions.LESSON_PLAN_READ)`
- scope 校验:`assertPlanInScope(plan, ctx)`lib/scope-check
- 组件:`LessonPlanReadonlyView` / `Skeleton`
- 路由参数:`planId`
- `notFound()` 兜底(计划不存在或越权)
- **ARCHITECTURE.md 契约**:❌
---
### 2.10 error-book 模块1 页规划0 已完成1 缺失)
#### 2.10.1 ❌ `/shell/parent/error-book`(子女错题本,缺失)
- **CICD 参考实现**`e:\Desktop\CICD\src\app\(dashboard)\parent\error-book\page.tsx`
- **功能描述**
- **单/多子女分支渲染**(家长域特色):
- **单子女**:直接展示 `StatsGrid` 5 列统计卡片(总数 / 新增 / 学习中 / 已掌握 / 待复习)
- **多子女**:每个子女一张 `Card`,含姓名 + 掌握率徽章 + 4 项统计 + `Progress` 进度条
- 汇总所有子女的错题:**Top 错题**`TopWrongQuestions`,前 5+ **薄弱知识点**`getKnowledgePointWeakness`,前 5
- 薄弱知识点:每条含知识点名称 + 错误次数 + 掌握率 + `Progress` 进度条
- 待复习数 > 0 时高亮(`highlight: stats.dueReviewCount > 0`
- `WidgetBoundary` 降级容错
- **技术栈**
- Server Component + `force-dynamic`
- Server Actions`getErrorBookStats(id)` + `getStudentNameMap(childrenIds)` + `getTopWrongQuestionsByStudentIds(childrenIds, 5)` + `getKnowledgePointWeakness(childrenIds, 5)`
- `requirePermission(Permissions.ERROR_BOOK_READ)`
- 组件:`StatsGrid` / `TopWrongQuestions` / `WidgetBoundary` / `Card` / `Badge` / `Progress` / `EmptyState`
- 工具:`formatNumber`
- icons`BookX` / `Clock` / `GraduationCap` / `Repeat` / `Sparkles` / `Users`
- **ARCHITECTURE.md 契约**:✅
---
### 2.11 diagnostic 模块1 页规划0 已完成1 缺失)
#### 2.11.1 ❌ `/shell/parent/diagnostic`(子女学情诊断,缺失)
- **CICD 参考实现**`e:\Desktop\CICD\src\app\(dashboard)\parent\diagnostic\page.tsx`
- **功能描述**
- **多子女诊断对比视图**v4-P1-9 容错增强)
- 预先查询所有子女姓名(`getUserNamesByIds`),用于错误卡片展示
- **allSettled 容错但保留 rejected 项**rejected 项不再静默丢弃,渲染错误卡片(`AlertCircle` + 学生姓名 + "数据加载失败"提示)
- 每个子女:诊断摘要(`getStudentMasterySummary`+ **已发布诊断报告**`getDiagnosticReports`v4-P1-3 修复:家长仅可见 `status: "published"` 报告,避免草稿泄露)
- `StudentDiagnosticView` 渲染(`role="parent"`
- **技术栈**
- Server Component + `force-dynamic`
- Server Actions`getStudentMasterySummary(id)` + `getDiagnosticReports({ studentId: id, status: "published" }, ctx.dataScope)` + `getUserNamesByIds(childrenIds)`
- `requirePermission(Permissions.DIAGNOSTIC_READ)`
- 组件:`ParentChildrenDataPage` / `ParentNoChildrenPage` / `StudentDiagnosticView` / `Card` / `CardContent`
- 类型:`ChildDiagnosticSuccessItem` / `ChildDiagnosticErrorItem`(联合类型 `ChildDiagnosticItem`
- icons`Stethoscope` / `AlertCircle`
- **ARCHITECTURE.md 契约**:✅
---
### 2.12 learning-path 模块1 页规划0 已完成1 缺失)⚠️ CICD 无源
#### 2.12.1 ❌ `/shell/parent/learning-path`(子女学习路径,缺失)⚠️ CICD 无源
- **CICD 参考实现**:❌ CICD 无对应源页面(学生域有 `learning/study-path`,但家长域无对应页)
- **功能描述**:家长视角查看子女的 AI 学习路径,应展示:
- 多子女学习路径汇总(每个子女一块)
- AI 生成的个性化学习路径(参考学生域 `AiStudyPath` 组件)
- 路径进度、节点完成情况
- **技术栈建议**:参考 CICD 学生域 `learning/study-path/page.tsx` 的 `AiStudyPath` + `AiClientProvider` 模式 + `requirePermission(Permissions.AI_CHAT)`;家长域需扩展为多子女布局
- **ARCHITECTURE.md 契约**:❌
---
### 2.13 practice 模块1 页规划0 已完成1 缺失)
#### 2.13.1 ❌ `/shell/parent/practice`(子女练习查看,缺失)
- **CICD 参考实现**`e:\Desktop\CICD\src\app\(dashboard)\parent\practice\page.tsx`
- **功能描述**
- **单/多子女分支渲染**(家长域特色):
- **单子女**:直接展示 4 列 `StatsGrid`(总练习次数 / 已完成 / 总答题数 / 正确率)+ `PracticeHistory` 历史列表
- **多子女**:每个子女一块 `WidgetBoundary`,含姓名标题 + 4 列统计 + 历史列表
- **家长无会话详情页**,仅展示只读卡片(注释明确:`家长无会话详情页,仅展示只读卡片`
- `PracticeServiceProvider` 包裹(注入练习服务)
- `Promise.allSettled` 容错 + 循环 + 类型守卫(非 `as` 断言)
- 姓名映射并行启动(`nameMapPromise` 与 `childResults` 并行,但类型分离以利类型收窄)
- **技术栈**
- Server Component + `force-dynamic`
- Server Actions`getPracticeStats(id)` + `getPracticeSessions(id, { pageSize: 20 })` + `getUserNamesByIds(childrenIds)`
- `requirePermission(Permissions.ADAPTIVE_PRACTICE_READ)`
- 组件:`PracticeServiceProvider` / `StatsGrid` / `PracticeHistory` / `WidgetBoundary` / `EmptyState`
- 类型:`PracticeSessionSummary` / `PracticeStats` / `ChildPracticeItem`
- icons`Target` / `Users` / `CheckCircle2` / `TrendingUp` / `Award`
- `valueClassName: "tabular-nums"` 数字对齐
- **ARCHITECTURE.md 契约**:❌
---
### 2.14 elective 模块1 页规划0 已完成1 缺失)
#### 2.14.1 ❌ `/shell/parent/elective`(子女选课查看,缺失)
- **CICD 参考实现**`e:\Desktop\CICD\src\app\(dashboard)\parent\elective\page.tsx`
- **功能描述**
- **多子女选课记录查看**(只读,家长不能选课)
- 每个子女一块:`ParentSelectionView`(子女姓名 + 选课记录列表)
- **双重校验**`getChildrenAction()` 获取关系 + `getChildBasicInfoAction(r.studentId, r.relation)` 二次校验防跨家庭信息泄露G4-002 审计修复)
- `Promise.allSettled` 容错
- **技术栈**
- Server Component + `force-dynamic`
- Server Actions`getStudentSelections(r.studentId)` + `getChildrenAction()` + `getChildBasicInfoAction(r.studentId, r.relation)`
- `requirePermission(Permissions.ELECTIVE_READ)`
- 组件:`ParentChildrenDataPage` / `ParentNoChildrenPage` / `ParentSelectionView`
- 类型:`ChildSelectionData`
- **ARCHITECTURE.md 契约**:❌
---
### 2.15 leave 模块1 页规划0 已完成1 缺失)
#### 2.15.1 ❌ `/shell/parent/leave`(家长在线请假,缺失)
- **CICD 参考实现**`e:\Desktop\CICD\src\app\(dashboard)\parent\leave\page.tsx`
- **功能描述**
- **家长域少有的"写"操作页面**(其他多为只读)
- 顶部:**在线请假表单**`LeaveRequestForm`,下拉选择子女,自动写入 classId
- 底部:该家长**所有子女**的请假申请列表(`LeaveRequestList`,按 dataScope=children 过滤)
- 子女选项构造:遍历关系列表,查询每个子女的 `basicInfo`,仅包含有活跃班级的子女(`basic.classId && basic.className`
- 返回仪表盘的面包屑(`ArrowLeft` + Link to `/parent/dashboard`
- 无关联子女时显示提示卡片
- **技术栈**
- Server Component + `force-dynamic`
- Server Actions`getChildrenAction()` + `getLeaveRequests({ scope, currentUserId, page: 1, pageSize: 50 })` + `getChildBasicInfoAction(r.studentId, r.relation)`
- `getAuthContext()`(注意:未用 `requirePermission`,直接取 ctx
- 组件:`LeaveRequestForm` / `LeaveRequestList` / `Card` / `Button`
- 类型:`ChildOption`(含 `id` / `name` / `classId` / `className`
- icons`ArrowLeft` / `CalendarDays`
- scope 处理:家长 scope 为 `children``getLeaveRequests` 按 scope 过滤所有子女记录
- **ARCHITECTURE.md 契约**:❌
---
### 2.16 notifications + settings + preferences 模块(共享 2 页 + 家长专属 1 页0 已完成1 缺失 + 2 共享)
#### 2.16.1 ❌ `/shell/parent/preferences`(家长偏好设置,缺失)
- **CICD 参考实现**:❌ CICD 无对应源页面
- **功能描述**:家长专属偏好设置,可能包括:
- 通知偏好(哪些子女事件需推送:成绩、考勤、作业、预警)
- AI 摘要偏好(摘要频率、详细程度)
- 隐私偏好(是否共享数据给 AI
- **技术栈建议**:参考共享 settings 页面模式 + 家长域专属字段
- **ARCHITECTURE.md 契约**:❌
- **批次**B4
#### 2.16.2 ❌ `/shell/notifications`(通知中心,缺失,共享)
- **CICD 参考实现**:❌ CICD `parent/` 下无对应源页面
- **功能描述**:通知中心(家长可见范围)
- **ARCHITECTURE.md 契约**:✅(共享,已就绪)
- **批次**B1/B3共享路由
#### 2.16.3 ❌ `/shell/settings`(系统设置,缺失,共享)
- **CICD 参考实现**:❌ CICD `parent/` 下无对应源页面
- **功能描述**:系统设置(通用)
- **ARCHITECTURE.md 契约**:✅(共享,已就绪)
- **批次**B1/B3共享路由
> **注**portal-shell 当前 `/shell/notifications` / `/shell/settings` 路由是否存在需在共享层确认。家长域仅需补充 `/shell/parent/preferences`。
---
## 三、按模块汇总
| 模块 | 规划页数 | 已完成 | 缺失 | 备注 |
| --------------------- | -------- | ------ | ------ | --------------------------------------- |
| dashboard | 3 | 1 | 2 | 仪表盘基础页有trend/weakness 详情页缺 |
| children | 1 | 0 | 1 | ⚠️ 家长域核心页,需 `myChildren` 契约 |
| grades | 2 | 0 | 2 | 多子女对比 + 报告卡 |
| exams | 2 | 0 | 2 | ⚠️ CICD 无源页面,全新设计 |
| homework | 1 | 0 | 1 | ⚠️ CICD 无源页面,全新设计 |
| attendance | 1 | 0 | 1 | 多子女考勤对比 |
| classes | 1 | 0 | 1 | ⚠️ CICD 无源页面,全新设计 |
| course-plans | 2 | 0 | 2 | 列表 + 详情,按子女班级过滤 |
| lesson-plans | 2 | 0 | 2 | 列表 + 只读详情scope 校验 |
| error-book | 1 | 0 | 1 | 单/多子女分支,契约 ✅ |
| diagnostic | 1 | 0 | 1 | 多子女诊断,契约 ✅ |
| learning-path | 1 | 0 | 1 | ⚠️ CICD 无源页面,全新设计 |
| practice | 1 | 0 | 1 | 单/多子女分支,只读 |
| elective | 1 | 0 | 1 | 多子女选课查看 |
| leave | 1 | 0 | 1 | 家长域少有的"写"操作 |
| preferences | 1 | 0 | 1 | 家长专属偏好 |
| notifications共享 | 1 | 0 | 1 | 共享路由,契约 ✅ |
| settings共享 | 1 | 0 | 1 | 共享路由,契约 ✅ |
| **合计** | **23** | **1** | **22** | 不含 dashboard 的 2 个详情页已计入缺失 |
> ARCHITECTURE.md §9.3 规划 24 页(含 notifications/settings 共享路由 2 页。portal-shell 当前 1 页已完成22 页缺失1 页为 dashboard 详情页(部分完成)。
---
## 四、关键技术差异 & 迁移注意事项
### 4.1 架构模式差异(最重要)
| 维度 | CICD参考 | portal-shell目标 |
| ------------- | ---------------------------------------------------------- | ------------------------------------------------------------------- |
| 渲染模式 | Server Component 为主 | 当前仪表盘是 Client Component需确定后续页面模式 |
| 数据获取 | Server Action + Drizzle 直查 DB | **必须改为** BFF / 微服务 API`teacher-bff` / `data-ana` 等) |
| 权限校验 | `requirePermission` + `getAuthContext` + dataScope | 需通过 Gateway + BFF 鉴权,前端用 `usePermission().hasPermission()` |
| 国际化 | `next-intl` `getTranslations` | portal-shell 当前仪表盘硬编码中文,需统一策略 |
| 共享 UI | `@/shared/components/ui/*` | `@/shared/components/ui/*`(已迁移部分) |
| 模块组件 | `@/modules/<domain>/components/*` | 需在 portal-shell 重建或下沉到 BFF |
| 多子女布局 | `ParentChildrenDataPage` + `ParentNoChildrenPage` 通用容器 | 需在 portal-shell 重建(家长域核心模式) |
| 单/多子女分支 | error-book / practice 中 `isSingleChild` 分支 | 需保留此模式(家长域特色) |
### 4.2 路由路径对齐
| CICD 路径 | ARCHITECTURE.md §9.3 目标路径 | 备注 |
| ----------------------------------- | ------------------------------------------ | ----------------------------------------------- |
| `parent/dashboard` | `/shell/parent`(家长仪表盘) | 提升到 `/shell/parent/page.tsx` |
| `parent/dashboard/trend` | `/shell/parent/trend` | CICD 无独立页,需新建 |
| `parent/dashboard/weakness` | `/shell/parent/weakness` | CICD 无独立页,需新建 |
| `parent/children/[studentId]` | `/shell/parent/children/[studentId]` | 路径一致 |
| `parent/grades` | `/shell/parent/grades` | 路径一致 |
| `parent/grades/report-card` | `/shell/parent/grades/report-card` | 路径一致 |
| `(无)` | `/shell/parent/exams` | 全新设计 |
| `(无)` | `/shell/parent/exams/[id]/result` | 全新设计 |
| `(无)` | `/shell/parent/homework` | 全新设计 |
| `parent/attendance` | `/shell/parent/attendance` | 路径一致 |
| `(无)` | `/shell/parent/classes` | 全新设计 |
| `parent/course-plans` | `/shell/parent/course-plans` | 路径一致 |
| `parent/course-plans/[id]` | `/shell/parent/course-plans/[id]` | 路径一致 |
| `parent/lesson-plans` | `/shell/parent/lesson-plans` | 路径一致 |
| `parent/lesson-plans/[planId]/view` | `/shell/parent/lesson-plans/[planId]/view` | 路径一致 |
| `parent/error-book` | `/shell/parent/error-book` | 路径一致 |
| `parent/diagnostic` | `/shell/parent/diagnostic` | 路径一致 |
| `(无)` | `/shell/parent/learning-path` | 全新设计(学生域有 `learning/study-path` 参考) |
| `parent/practice` | `/shell/parent/practice` | 路径一致 |
| `parent/elective` | `/shell/parent/elective` | 路径一致 |
| `parent/leave` | `/shell/parent/leave` | 路径一致 |
| `(无)` | `/shell/parent/preferences` | 全新设计 |
| 共享 | `/shell/notifications` | 共享路由 |
| 共享 | `/shell/settings` | 共享路由 |
> **注**:家长域路由迁移**压力较小**14 个 CICD 页面中有 13 个路径完全一致(仅 dashboard 从子路径提升到 `/shell/parent/page.tsx`)。需新建的 6 个页面exams×2、homework、classes、learning-path、preferences在 CICD 中无源。
### 4.3 权限点映射
CICD 中家长页面用到的权限点(迁移时需在 portal-shell `Permissions` 常量中对应):
- `GRADE_RECORD_READ`grades / report-card
- `ATTENDANCE_READ`attendanceCICD 实际用 `getAuthContext` 而非 `requirePermission`,需统一)
- `COURSE_PLAN_READ`course-plans 列表 + 详情)
- `LESSON_PLAN_READ`lesson-plans 列表 + 详情)
- `ERROR_BOOK_READ`error-book
- `DIAGNOSTIC_READ`diagnostic
- `ADAPTIVE_PRACTICE_READ`practice
- `ELECTIVE_READ`elective
- leave 用 `getAuthContext` 而非 `requirePermission`(需统一)
- children 详情用 `requireAuth` + `verifyParentChildRelationAction` + dataScope 二次校验(**双重校验模式**
- dashboard 用 `getParentDashboardAction`(内部封装权限)
### 4.4 共享组件清单(需在 portal-shell 补齐或确认已有)
**家长域通用容器(核心,必须重建)**
- `ParentChildrenDataPage`(多子女数据页通用容器,含 `renderItem` + `headerExtra` + 空态)
- `ParentNoChildrenPage`(无关联子女空态)
**dashboard 模块**
- `ParentDashboard` / `ChildCard` / `ParentAttentionBanner` / `AiChildSummary` / `ParentNoChildrenPage` / `ParentChildrenDataPage`
**children 模块**
- `ChildDetailHeader` / `ChildDetailPanel` / `SiblingSwitcher`
**grades 模块**
- `StudentGradeSummary` / `GradeTrendCard` / `GrowthArchiveChart` / `ReportCardView` / `ReportCardPrintAction` / `ParentExportButton`
**attendance 模块**
- `ParentAttendanceWarning` / `ParentAttendanceRateCard` / `ParentAttendanceCalendar` / `ParentStudentAttendanceDetail`
**course-plans 模块**
- `CoursePlanList` / `CoursePlanDetail`
**lesson-plans 模块**
- `LessonPlanList` / `LessonPlanReadonlyView` / `LessonPlanProviderSetup` + `PARENT_ROLE_CONFIG`
**error-book 模块**
- `StatsGrid` / `TopWrongQuestions` / `WidgetBoundary` / `Progress`
**diagnostic 模块**
- `StudentDiagnosticView``role="parent"`
**practice 模块**
- `PracticeServiceProvider` / `StatsGrid` / `PracticeHistory` / `WidgetBoundary`
**elective 模块**
- `ParentSelectionView`
**leave 模块**
- `LeaveRequestForm` / `LeaveRequestList` + `ChildOption` 类型
**基础 UI共享**
- `Card` / `CardContent` / `CardHeader` / `CardTitle` / `Button` / `Badge` / `EmptyState` / `Skeleton` / `Progress`
### 4.5 B4 实施优先级建议
按用户价值 + 实现复杂度 + 契约就绪度排序:
1. **P0必做家长域核心闭环**
- `children/[studentId]` 子女详情页(⚠️ 核心,需先补 `myChildren` 契约)
- `dashboard/trend` + `dashboard/weakness` 详情页(契约 ✅ `parentDashboard` 已就绪)
2. **P1高频查看契约 ✅)**
- `error-book`(契约 ✅)
- `diagnostic`(契约 ✅)
3. **P2学习数据查看**
- `grades` 列表 + `grades/report-card`
- `attendance`
- `practice`
4. **P3学习资源**
- `course-plans` 列表 + 详情
- `lesson-plans` 列表 + `lesson-plans/[planId]/view`
- `elective`
5. **P4写操作 + 偏好)**
- `leave`(家长域少有的"写"操作)
- `preferences`
6. **P5全新设计CICD 无源)**
- `exams` 列表 + `exams/[id]/result`
- `homework`
- `classes`
- `learning-path`
7. **共享**`notifications` / `settings`B1/B3 共享路由,非 B4 专属)
---
## 五、CICD 与 ARCHITECTURE.md §9.3 对照表
| ARCH §9.3 源路由 | ARCH §9.3 目标路由 | CICD 是否有源页面 | portal-shell 是否已有 | 契约状态 | 备注 |
| ----------------------------------- | ------------------------------------------ | ---------------------- | --------------------- | -------------------- | -------------------- |
| `parent/dashboard` | `/shell`(家长仪表盘) | ✅ | ✅ | ✅ `parentDashboard` | 已完成基础版 |
| `/trend` | `/shell/parent/trend` | ❌(融合在 dashboard | ❌ | ✅ `parentDashboard` | 需新建详情页 |
| `/weakness` | `/shell/parent/weakness` | ❌(融合在 dashboard | ❌ | ✅ `parentDashboard` | 需新建详情页 |
| `parent/children/[studentId]` | `/shell/parent/children/[studentId]` | ✅ | ❌ | ❌ `myChildren` | ⚠️ 核心,双重校验 |
| `parent/grades` | `/shell/parent/grades` | ✅ | ❌ | ❌ | 多子女对比 |
| `parent/grades/report-card` | `/shell/parent/grades/report-card` | ✅ | ❌ | ❌ | 打印支持 |
| `parent/exams` | `/shell/parent/exams` | ❌ | ❌ | 🟡 | CICD 无,全新设计 |
| `parent/exams/[id]/result` | `/shell/parent/exams/[id]/result` | ❌ | ❌ | 🟡 | CICD 无,全新设计 |
| `parent/homework` | `/shell/parent/homework` | ❌ | ❌ | ❌ | CICD 无,全新设计 |
| `parent/attendance` | `/shell/parent/attendance` | ✅ | ❌ | ❌ | 多子女考勤对比 |
| `parent/classes` | `/shell/parent/classes` | ❌ | ❌ | ❌ | CICD 无,全新设计 |
| `parent/course-plans` | `/shell/parent/course-plans` | ✅ | ❌ | ❌ | 按子女班级过滤 |
| `parent/course-plans/[id]` | `/shell/parent/course-plans/[id]` | ✅ | ❌ | ❌ | scope 校验 |
| `parent/lesson-plans` | `/shell/parent/lesson-plans` | ✅ | ❌ | ❌ | 已发布 + 只读 |
| `parent/lesson-plans/[planId]/view` | `/shell/parent/lesson-plans/[planId]/view` | ✅ | ❌ | ❌ | scope 校验 + 全屏 |
| `parent/error-book` | `/shell/parent/error-book` | ✅ | ❌ | ✅ | 单/多子女分支 |
| `parent/diagnostic` | `/shell/parent/diagnostic` | ✅ | ❌ | ✅ | 多子女 + 错误容错 |
| `parent/learning-path` | `/shell/parent/learning-path` | ❌ | ❌ | ❌ | CICD 无,全新设计 |
| `parent/practice` | `/shell/parent/practice` | ✅ | ❌ | ❌ | 单/多子女分支,只读 |
| `parent/elective` | `/shell/parent/elective` | ✅ | ❌ | ❌ | 多子女选课查看 |
| `parent/leave` | `/shell/parent/leave` | ✅ | ❌ | ❌ | 家长域少有的"写"操作 |
| `parent/preferences` | `/shell/parent/preferences` | ❌ | ❌ | ❌ | CICD 无,全新设计 |
| `notifications`、`settings` | 共享路由 | — | ❌ | ✅ | B1/B3共享路由 |
| `preferences` | `/shell/parent/preferences` | ❌ | ❌ | ❌ | 家长专属 |
---
## 六、风险与建议
### 6.1 高风险点
1. **`myChildren` 契约缺失**:家长域核心契约未就绪,`children/[studentId]` 子女详情页无法启动。**必须在 B4 首位补齐**,建议参考 CICD `getChildDashboardDataAction` 的数据结构定义契约
2. **6 个页面 CICD 无源**`exams`×2、`homework`、`classes`、`learning-path`、`preferences` 需从零设计,参考学生域同构页面(如 `exams` 参考学生域 `exams`、`homework` 参考学生域 `learning/assignments`、`learning-path` 参考学生域 `learning/study-path`
3. **架构模式转变**portal-shell 已转向 BFF + 微服务,**不能照搬 CICD 的 Server Action + Drizzle 直查模式**每个页面都需重新设计数据获取链路BFF → data-ana / core-edu 等服务)
4. **多子女布局是家长域核心模式**`ParentChildrenDataPage` + `ParentNoChildrenPage` 通用容器需优先重建13 个页面复用此模式
5. **单/多子女分支渲染**error-book / practice 中的 `isSingleChild` 分支需保留(单子女家庭体验更紧凑)
6. **双重权限校验**children 详情页的 `verifyParentChildRelationAction` + dataScope 二次校验是防跨家庭信息泄露的关键,迁移时必须保留
7. **国际化缺失**当前仪表盘硬编码中文22 页全部完成后需补 i18n建议从一开始就用 `next-intl`
8. **权限校验缺失**:当前仪表盘无 `requirePermission`,需建立 portal-shell 家长域权限校验中间件/装饰器
9. **leave 是少有的"写"操作**:家长域多为只读视图,`leave` 页面涉及表单提交,需重点设计 BFF 写接口 + 事务保证
### 6.2 建议
1. **先建契约**:开工前先在 `shared-proto` 中补齐 §9.3 标 ❌ / 🟡 的契约,特别是 `myChildren`(核心)、`parentDashboard` 扩展trend/weakness 子契约、exams 系列、homework、classes、learning-path、preferences
2. **统一渲染模式**:建议家长页面统一采用 Server Component + BFF 数据获取(与 CICD 一致),避免当前仪表盘的 Client Component 模式
3. **统一权限模型**:建立 portal-shell 家长域 `RequirePermission` 装饰器/中间件,覆盖所有页面;统一 `getAuthContext` 与 `requirePermission` 的使用CICD 中 attendance / leave 用 `getAuthContext`,需统一)
4. **共享容器下沉**`ParentChildrenDataPage` / `ParentNoChildrenPage` 是家长域核心容器,建议下沉到 `@/shared/components/parent/` 或 BFF 返回结构化数据
5. **复用学生域组件**:家长域多为只读视图,大量组件(`StudentGradeSummary` / `GradeTrendCard` / `ReportCardView` / `StudentDiagnosticView` / `PracticeHistory` / `CoursePlanList` / `LessonPlanReadonlyView`)可复用学生域实现,仅需传入 `role="parent"` 标识
6. **CICD 无源页面决策**6 个 CICD 无源页面需产品确认功能范围,建议参考学生域同构页面 + 家长域多子女布局组合设计
7. **分批推进**:按本报告 §4.5 的 P0→P5 优先级分批实施,每批完成后跑 `pnpm run arch:scan` 同步 arch.db
---
**分析完成。共发现 23 个待完成页面(含 2 个 dashboard 详情页 + 1 个 preferences 家长专属页 + 2 个共享路由页 + 18 个其他模块页),其中 22 个完全缺失、1 个为 dashboard 详情页缺失。最关键的 `children/[studentId]` 子女详情页需 `myChildren` 契约先行。6 个页面exams×2、homework、classes、learning-path、preferences在 CICD 中无源,需从零设计。**