# parent-portal 工作排期 > 负责人:ai15 > 关联:[workline.md](../workline.md)、[coord.md](../coord.md)、[contracts/parent-portal_contract.md](../contracts/parent-portal_contract.md) > 模式:全并行(各 AI 一口气完成 P2-P6 全部代码,开发期间用 mock,最后统一集成测试) --- ## §1 总览 parent-portal 是家长端微前端(MF Remote),挂载到 teacher-portal Shell,覆盖家长仪表盘、多子女切换、子女学情查看、通知偏好等场景。 - **MF 角色**:Remote(Shell = teacher-portal :4000) - **端口**:4002(dev/prod 一致,[port-allocation.md](../../../../infra/port-allocation.md) §4) - **阶段归属**:P4 启动(依赖 P4 的 parent-bff + data-ana 就绪) - **DataScope**:CHILDREN(仅查看自己绑定子女的数据) - **全阶段目标**:P4 MF Remote 骨架 + 核心页面 → P5 推送接入 + 通知中心 → P6 硬化(A11y/性能/安全/PWA/多语言) > **前置阻塞**(见 [objections/parent-portal_issue.md](../objections/parent-portal_issue.md) ISSUE-010): > > - iam `GetChildrenByParent` 接口缺失(P0 阻塞,ai06 补全),补全前用 mock(固定 2 个子女 student-001 + student-002) > - ISSUE-001 待 coord 仲裁(REST vs GraphQL),仲裁前按 GraphQL 预排期,mock 用 MSW 拦截 GraphQL --- ## §2 全阶段甘特图(P4-P6) ```mermaid gantt title ai15 parent-portal 全阶段排期(P4-P6) dateFormat YYYY-MM-DD axisFormat %m-%d section P4 骨架与核心页面(11d) 4.1 MF Remote 骨架+next.config.js+健康检查 :crit, a15a, 2026-07-29, 2d 4.2 GraphQL client接入+MSW mock层 :crit, a15b, after a15a, 1d 4.3 ChildSwitcher+useChildSwitcher+Zustand slice :crit, a15c, after a15b, 2d 4.4 Dashboard页面+ParentDashboard组件 :a15d, after a15c, 2d 4.5 子女成绩页面+ChildGradeChart :a15e, after a15c, 1d 4.6 子女作业页面 :a15f, after a15e, 1d 4.7 通知偏好页面+PreferenceForm+Zod :a15g, after a15d, 1d 4.8 跨标签同步(BroadcastChannel) :a15h, after a15c, 1d section P4 质量保障(并行) 4.9 Vitest单测+MSW集成测试 :a15i, after a15g, 2d 4.10 Dockerfile多阶段构建 :a15j, after a15a, 1d section P5 推送与通知中心(5d) 5.1 WebSocket接入+事件处理 :crit, a15k, after a15i, 2d 5.2 通知中心页面+NotificationFeed :a15l, after a15k, 2d 5.3 推送降级(HTTP轮询) :a15m, after a15l, 1d section P6 硬化(8d) 6.1 Web Vitals+OTel browser SDK :a15n, after a15m, 2d 6.2 A11y WCAG 2.2 AA审计+修复 :a15o, after a15n, 2d 6.3 性能优化+bundle分析 :a15p, after a15o, 1d 6.4 多语言扩展(en-US) :a15q, after a15p, 1d 6.5 PWA(Service Worker+manifest) :a15r, after a15q, 1d 6.6 安全硬化(CSP+敏感数据脱敏) :a15s, after a15r, 1d ``` > **总工期**:P4 11d + P5 5d + P6 8d = 24d(约 5 周) > **关键路径**(红色 crit):MF 骨架 → GraphQL client → ChildSwitcher → 质量保障 → WebSocket → 通知中心 --- ## §3 详细任务 ### P4 阶段任务 #### P4-1:MF Remote 骨架 + next.config.js + 健康检查 - **负责人**:ai15 - **依赖**:teacher-portal Shell MF 配置就绪(ARB-002,ai13 P2 交付);ISSUE-002 仲裁(MF shared 清单) - **交付物**: - `apps/parent-portal/next.config.js`(NextFederationPlugin,Remote 角色,`name: parent_app`,`exposes: ./pages + ./ChildSwitcher`,`shared` 含 ARB-002 全部 7 项) - `apps/parent-portal/src/app/layout.tsx`(RootLayout,复用 Shell 暴露的字体/令牌/i18n Provider) - `apps/parent-portal/src/app/api/health/route.ts`(`GET /api/health` → `{ status: 'ok', ts }`) - `apps/parent-portal/src/app/api/ready/route.ts`(`GET /api/ready` → 检查 API_GATEWAY_URL 可达) - `apps/parent-portal/tsconfig.json`(继承 tsconfig.base.json,strict) - `apps/parent-portal/package.json`(依赖对齐 Shell:react 18.3 + next 14 + urql + @tanstack/react-query v5 + zustand + nuqs) - **验收标准**: 1. `pnpm --filter parent-portal dev` 启动 :4002 2. `GET /api/health` 返回 200 3. teacher-portal Shell 能加载 parent-portal remoteEntry.js(MF 拓扑验证) 4. feature flag `NEXT_PUBLIC_MF_ENABLED` 可控制 MF 开关 #### P4-2:GraphQL client 接入 + MSW mock 层 - **负责人**:ai15 - **依赖**:P4-1;ISSUE-001 仲裁(确认 GraphQL);teacher-portal Shell 暴露 GraphQLProvider(ARB-002) - **交付物**: - `apps/parent-portal/src/lib/graphql-client.ts`(从 Shell 暴露的 `useGraphQLClient()` 获取 urql client 单例) - `apps/parent-portal/src/graphql/queries/`(currentUser / myChildren / childSummary / childGrades / childHomework / childTrend / childWeakness 查询文档) - `apps/parent-portal/src/graphql/mutations/`(markAsRead / updateNotificationPreferences mutation 文档) - `apps/parent-portal/src/mocks/handlers.ts`(MSW 拦截 `POST /api/v1/parent/graphql`,按 operationName 返回 mock) - `apps/parent-portal/src/mocks/fixtures/*.json`(固定 2 个子女 student-001 李同学 + student-002 李妹妹,与 parent-bff mock 一致) - `apps/parent-portal/src/mocks/browser.ts`(MSW worker 初始化,`NEXT_PUBLIC_API_MOCKING=enabled` 控制) - **验收标准**: 1. MSW enabled 时,所有 GraphQL 查询返回 mock 数据 2. myChildren mock 返回 2 个子女,id 与 childGrades/childHomework mock 的 student_id 一致 3. urql client 单例跨组件共享(MF shared singleton 验证) #### P4-3:ChildSwitcher + useChildSwitcher + Zustand slice - **负责人**:ai15 - **依赖**:P4-2;ISSUE-009 仲裁(switchChild 是 GraphQL Mutation 还是纯前端状态) - **交付物**: - `apps/parent-portal/src/stores/childSwitcherSlice.ts`(Zustand slice:children / currentChildId / isLoading / error / switchChild / refreshChildren) - `apps/parent-portal/src/hooks/useChildSwitcher.ts`(封装 myChildren GraphQL query + 切换逻辑 + invalidate 子女维度查询) - `apps/parent-portal/src/components/ChildSwitcher.tsx`(variant: tab | dropdown,状态机:idle/switching/switched/error) - `apps/parent-portal/src/components/MultiChildTabBar.tsx`(≤3 子女用 Tab,>3 用下拉,移动端友好) - localStorage 持久化 `parent:currentChildId`(刷新恢复) - **验收标准**: 1. 切换子女后,`['parent','grades',currentChildId]` 等子女维度查询 invalidate 重拉 2. 刷新页面后 currentChildId 从 localStorage 恢复 3. 0 子女显示 EmptyChildState;1 子女不显示 TabBar;2-3 子女显示 Tab 4. 切换子女竞态:快速连续切换,旧请求 abort,新数据正确显示 #### P4-4:Dashboard 页面 + ParentDashboard 组件 - **负责人**:ai15 - **依赖**:P4-3 - **交付物**: - `apps/parent-portal/src/app/(app)/parent/dashboard/page.tsx` - `apps/parent-portal/src/components/ParentDashboard.tsx`(组合 useChildren + useChildSummary,插槽:summary-cards / todo-reminders / recent-grades / attendance / custom) - `apps/parent-portal/src/components/ChildSummaryCard.tsx`(单子女概览:头像/姓名/年级/今日作业数/成绩趋势缩略图) - `apps/parent-portal/src/components/AttendanceCalendar.tsx`(出勤日历热力图) - **验收标准**: 1. 多子女并列卡片展示 2. 权限校验:`PARENT_DASHBOARD_VIEW`,用 `` 3. SSR 首屏 + CSR 交互(依 02 §14.4 渲染策略) #### P4-5:子女成绩页面 + ChildGradeChart - **负责人**:ai15 - **依赖**:P4-3 - **交付物**: - `apps/parent-portal/src/app/(app)/parent/grades/page.tsx` - `apps/parent-portal/src/components/ChildGradeChart.tsx`(recharts 折线 + 班级均分对比 + 多子女对比模式) - **验收标准**: 1. 权限校验:`GRADES_READ_CHILD` 2. 切换子女后图表刷新 3. 多子女对比模式可选 #### P4-6:子女作业页面 - **负责人**:ai15 - **依赖**:P4-3 - **交付物**:`apps/parent-portal/src/app/(app)/parent/homework/page.tsx` - **验收标准**: 1. 权限校验:`HOMEWORK_READ_CHILD` 2. 复用 Shell 暴露的 DataTable 展示作业列表 #### P4-7:通知偏好页面 + PreferenceForm + Zod - **负责人**:ai15 - **依赖**:P4-4 - **交付物**: - `apps/parent-portal/src/app/(app)/parent/preferences/page.tsx` - `apps/parent-portal/src/components/PreferenceForm.tsx`(矩阵式 UI:子女×事件×渠道,react-hook-form + zodResolver) - `apps/parent-portal/src/schemas/notificationPreferences.ts`(Zod schema,见 02 §14.4) - **验收标准**: 1. 权限校验:`PARENT_PREFERENCES_UPDATE` 2. 不可用渠道 Toggle disabled + tooltip 3. 保存成功后 invalidate `['parent','preferences']` 4. 表单 dirty 状态追踪 + 离开页提示 #### P4-8:跨标签同步(BroadcastChannel) - **负责人**:ai15 - **依赖**:P4-3 - **交付物**: - `apps/parent-portal/src/lib/crossTabSync.ts`(见 02 §16.2 完整实现) - 集成到 RootLayout(`useCrossTabSync()`) - **验收标准**: 1. Tab A 切换子女 → Tab B 同步更新 2. LWW 冲突解决(ts 大的胜出) 3. Safari 降级为 storage 事件 #### P4-9:Vitest 单测 + MSW 集成测试 - **负责人**:ai15 - **依赖**:P4-4 ~ P4-7 - **交付物**: - `apps/parent-portal/vitest.config.ts` - 单测:组件渲染/交互、Hook 逻辑、Zod schema 校验、纯函数 utils(覆盖率 ≥ 85%) - 集成测试:useChildSwitcher + Zustand slice + invalidate 流程(MSW mock,覆盖率 ≥ 75%) - **验收标准**: 1. `pnpm --filter parent-portal test` 全绿 2. 覆盖率达标(单元 ≥ 85%,集成 ≥ 75%) #### P4-10:Dockerfile 多阶段构建 - **负责人**:ai15 - **依赖**:P4-1 - **交付物**:`apps/parent-portal/Dockerfile`(builder + runtime,node:22-alpine) - **验收标准**: 1. `docker build` 成功 2. HEALTHCHECK 指向 `/api/health` 3. 镜像体积 < 300MB ### P5 阶段任务 #### P5-1:WebSocket 接入 + 事件处理 - **负责人**:ai15 - **依赖**:push-gateway :8081/ws 就绪(ai02);parent-portal P4 完成 - **交付物**: - `apps/parent-portal/src/hooks/useWebSocket.ts`(连接 push-gateway ws,JWT 鉴权,自动重连) - 事件处理:`NotificationRequested` → toast + 未读数+1;`GradeRecorded` → toast + 成绩 invalidate;`SchoolAnnouncement` → toast + dashboard invalidate - **验收标准**: 1. WS 连接建立后收事件正常 2. 断线自动重连(指数退避) #### P5-2:通知中心页面 + NotificationFeed - **负责人**:ai15 - **依赖**:P5-1 - **交付物**: - `apps/parent-portal/src/app/(app)/parent/notifications/page.tsx` - `apps/parent-portal/src/components/NotificationFeed.tsx`(按子女×类型×已读筛选,批量已读,跳转,置顶) - **验收标准**: 1. 权限校验:`NOTIFICATION_READ_OWN` 2. WebSocket 推送 invalidate 通知列表 #### P5-3:推送降级(HTTP 轮询) - **负责人**:ai15 - **依赖**:P5-1 - **交付物**:WS 重试 5 次失败后降级为 HTTP 轮询(60s 拉取通知列表) - **验收标准**:降级后通知延迟 ≤ 60s,用户感知降级提示 ### P6 阶段任务 #### P6-1:Web Vitals + OTel browser SDK - **交付物**:`next/web-vitals` 上报 + OTel browser SDK(复用 Shell 暴露的 TracerProvider) - **验收标准**:LCP/CLS/TTFB 指标上报到 Gateway #### P6-2:A11y WCAG 2.2 AA 审计 + 修复 - **交付物**:axe-core 自动扫描 + 手动键盘导航测试,0 严重违规 - **验收标准**:所有页面 0 严重 A11y 违规 #### P6-3:性能优化 + bundle 分析 - **交付物**:bundle 分析报告 + 代码分割优化(首屏 JS ≤ 80KB gzipped) - **验收标准**:Lighthouse 移动端 4G ≥ 90 分 #### P6-4:多语言扩展(en-US) - **交付物**:`apps/parent-portal/src/i18n/messages/en-US/*.json`(镜像 zh-CN 结构) - **验收标准**:en-US 完成度 100% #### P6-5:PWA(Service Worker + manifest) - **交付物**:`public/manifest.json` + Service Worker 缓存策略(见 02 §18.4) - **验收标准**:可安装到主屏,离线可查看缓存的子女数据 #### P6-6:安全硬化(CSP + 敏感数据脱敏) - **交付物**:CSP 头配置(复用 Shell)+ 截图脱敏 + 页面离开遮罩 - **验收标准**:CSP 无违规报告;敏感数据不泄漏 --- ## §4 依赖与就绪信号 ### 4.1 我依赖的上游就绪标志 | 上游 | 就绪信号 | 提供方 | 状态 | 阻塞影响 | | --------------------------------- | ----------------------------------------------------------------------------- | --------- | ---------- | ----------------------------- | | teacher-portal Shell | MF exposes(AppShell + GraphQLProvider + hooks + UI 组件)+ shared singleton | ai13 | ⏳ P2 | P4 无法启动 | | parent-bff GraphQL | `POST /graphql` :3010 + currentUser/myChildren/childSummary/childGrades Query | ai05 | ⏳ P4 | 核心数据源 | | iam GetChildrenByParent | gRPC 50052 + `iam_student_guardians` 表 | ai06 | ⏳ P3 补全 | P0 多子女阻塞(见 ISSUE-010) | | core-edu | gRPC 50053 + GradeService/HomeworkService/AttendanceService | ai08 | ⏳ P3 | 成绩/作业数据 | | data-ana | gRPC 50055 + AnalyticsService | ai11 | ⏳ P4 | 学情分析数据 | | msg | gRPC 50056 + NotificationService | ai10 | ⏳ P5 | 通知中心 | | push-gateway | :8081/ws WebSocket | ai02 | ⏳ P5 | 实时推送 | | shared-ts | ApiClient/Logger(coord 维护) | coord | ⏳ | 基础工具 | | contracts | Permissions 常量(coord 维护) | coord | ⏳ | 权限校验 | | ui-tokens / ui-components / hooks | 三层令牌 + shadcn + usePermission/useAuth(ai07/ai13 维护) | ai07/ai13 | ⏳ P2 收尾 | UI 基础 | ### 4.2 我的就绪信号(供下游消费) | 信号 | 说明 | 阶段 | | ----------------------------------- | --------------------------------------------------------------- | ---------- | | parent-portal :4002 dev server 启用 | MF Remote 可被 Shell 加载 | P4-1 完成 | | MF Remote remoteEntry.js 可加载 | Shell 端 `remotes.parent` 可解析 | P4-1 完成 | | 核心 GraphQL 查询可执行 | currentUser / myChildren / childSummary 返回数据(mock 或真实) | P4-2 完成 | | 多子女切换可用 | ChildSwitcher + invalidate 流程通过 | P4-3 完成 | | Dashboard 可访问 | 家长登录 → 看到 Dashboard(含子女卡片) | P4-4 完成 | | 健康检查通过 | `GET /api/health` + `GET /api/ready` 200 | P4-1 完成 | | 测试覆盖率达标 | 单元 ≥ 85% + 集成 ≥ 75% | P4-9 完成 | | Docker 镜像可构建 | `docker build` 成功 | P4-10 完成 | ### 4.3 全并行 Mock 策略 | 消费接口 | Mock 方式 | 切换真实时机 | | ---------------------- | ---------------------------------------------------------------------------------- | -------------------------------- | | parent-bff GraphQL | MSW 拦截 `POST /api/v1/parent/graphql`,按 operationName 返回 fixtures | parent-bff GraphQL :3010 就绪 ✅ | | iam login | MSW 返回固定 JWT(parent 角色) | api-gateway + iam 就绪 ✅ | | push-gateway WebSocket | mock-socket 模拟 WS 推送(每 30s 1 条通知) | push-gateway :8081 就绪 ✅ | | 子女数据一致性 | myChildren mock 返回 student-001 + student-002,与所有 child* 查询 student_id 一致 | iam GetChildrenByParent 就绪 | > Mock 由 `NEXT_PUBLIC_API_MOCKING=enabled` 环境变量控制,上游就绪后设为 `disabled`。 --- ## §5 风险与缓解 | 风险 | 影响 | 缓解 | | ----------------------------------------- | ---------------------------------- | -------------------------------------------------------- | | ISSUE-001/002 未仲裁(REST vs GraphQL) | P4-2 GraphQL client 接入方向不确定 | 先按 GraphQL 预排期;仲裁若改 REST,P4-2 重写(预计 1d) | | iam GetChildrenByParent 缺失(ISSUE-010) | 多子女场景无法落地 | mock 固定 2 子女开发;coord 跟踪 ai06 P3 补全 | | MF SSR 对齐复杂 | Remote SSR 需 Shell 上下文 | 优先 CSR,仅 Dashboard 首屏 SSR;P4-1 PoC 验证 | | parent-bff 契约未最终确认 | GraphQL schema 可能变动 | P4 启动前与 ai05 对齐 schema;MSW mock 解耦 | | TanStack Query 缓存膨胀 | 多子女历史查询堆积 | gcTime 5min + 切换子女清理非当前子女缓存 | --- ## §6 进度跟踪(2026-07-13 更新) > 当前分支:main(已合并 feat-review-parent-portal-docs-nRb7cN + feat/parent-portal-ai15) > ARB-020 全部 10 项 ISSUE 已裁决(见 coord.md §22) > ARB-020 §22.5 switchChild 双层实现已完成(useChildSwitcher + SWITCH_CHILD mutation) > ARB-022 §24.4 双 /v1 前缀已修正(GraphQL + iam login + notifications + web-vitals 全部对齐方案 A) ### 6.1 P4 骨架与核心页面 | 任务 | 状态 | 说明 | | ------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------ | | P4-1 MF Remote 骨架+next.config.js+健康检查 | ✅ 完成 | next.config.js 含 NextFederationPlugin,health/ready route 已就绪 | | P4-2 GraphQL client接入+MSW mock层 | ✅ 完成 | graphql-client.ts + operations.ts + handlers.ts + fixtures.ts 全部就绪;ARB-022 §24.4 双 /v1 端点已对齐 | | P4-3 ChildSwitcher+useChildSwitcher+Zustand slice | ✅ 完成 | child-store.ts + useChildSwitcher.ts + ChildSwitcher.tsx + MultiChildTabBar.tsx | | P4-4 Dashboard页面+ParentDashboard组件 | ✅ 完成 | dashboard/page.tsx + ParentDashboard.tsx + ChildSummaryCard.tsx + AttendanceCalendar.tsx | | P4-5 子女成绩页面+ChildGradeChart | ✅ 完成 | grades/page.tsx + ChildGradeChart.tsx(recharts 柱状图) | | P4-6 子女作业页面 | ✅ 完成 | homework/page.tsx 含状态过滤器 | | P4-7 通知偏好页面+PreferenceForm+Zod | ✅ 完成 | preferences/page.tsx + PreferenceForm.tsx + notification-preferences.ts | | P4-8 跨标签同步(BroadcastChannel) | ✅ 完成 | useCrossTabSync.ts + child-store.ts BroadcastChannel 集成 | | P4-9 Vitest单测+MSW集成测试 | ✅ 完成 | 413 测试通过,覆盖率 99%+(statements 99.03% / branches 92.85% / functions 97.29% / lines 99.03%),全部 ≥85% 阈值 | | P4-10 Dockerfile多阶段构建 | ✅ 完成 | builder + runtime(node:20-alpine),HEALTHCHECK 指向 /api/health | ### 6.2 P5 推送与通知中心 | 任务 | 状态 | 说明 | | ---------------------------------- | ------- | ------------------------------------------------------------------------------------ | | P5-1 WebSocket接入+事件处理 | ✅ 完成 | useWebSocket.ts(指数退避重连+降级轮询)+ useRealtimeNotifications.ts(5类事件处理) | | P5-2 通知中心页面+NotificationFeed | ✅ 完成 | notifications/page.tsx + NotificationFeed.tsx(筛选/批量已读/置顶) | | P5-3 推送降级(HTTP轮询) | ✅ 完成 | useWebSocket.ts 内实现(重试5次后降级60s轮询) | ### 6.3 P6 硬化 | 任务 | 状态 | 说明 | | --------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | P6-1 Web Vitals+OTel browser SDK | ✅ 完成 | observability/env.ts + otel.ts + web-vitals.ts + WebVitalsInitializer;providers.tsx 挂载 OTel + WebVitals;optionalDependencies 含 @opentelemetry/* + web-vitals | | P6-2 A11y WCAG 2.2 AA审计+修复 | ✅ 完成 | observability/a11y.ts 审计工具(axe-core + 对比度检查);修复 ARIA 属性(role/aria-live/aria-label);添加 sr-only CSS 类 | | P6-3 性能优化+bundle分析 | ✅ 完成 | next.config.js 集成 @next/bundle-analyzer(ANALYZE=true 启用);package.json 添加 analyze 脚本 | | P6-4 多语言扩展(en-US) | ✅ 完成 | i18n.ts 含 zh-CN + en-US 双语翻译表 | | P6-5 PWA(Service Worker+manifest) | ✅ 完成 | manifest.json + sw.js 已就绪,providers.tsx 生产环境注册 | | P6-6 安全硬化(CSP+敏感数据脱敏) | ✅ 完成 | middleware.ts CSP 已收紧(移除 unsafe-eval),安全头齐全 | ### 6.4 超出原 workline 的已实现内容 | 内容 | 说明 | | ---------------------------------------- | --------------------------------------------------------------------- | | 考勤页面 `/parent/attendance` | useChildAttendance.ts + AttendanceCalendar.tsx(月度日历热力图) | | 学情薄弱点页面 `/parent/weakness` | useChildWeakness.ts + weakness/page.tsx(掌握度进度条+推荐建议) | | 学习趋势页面 `/parent/trend` | useChildTrend.ts + trend/page.tsx(recharts 折线图+周期选择器) | | 考试列表页面 `/parent/exams` | useChildExams.ts + exams/page.tsx(按状态分组,含状态徽标) | | 考试结果页面 `/parent/exams/[id]/result` | useChildExamResult.ts + result/page.tsx(分数摘要+答题回顾+逐题分析) | | 班级列表页面 `/parent/classes` | useChildClasses.ts + classes/page.tsx(班级卡片网格) | | 学习路径页面 `/parent/learning-path` | useChildLearningPath.ts + learning-path/page.tsx(知识点进度+推荐) | | 设置页面 `/parent/settings` | settings/page.tsx(家长信息只读展示) | | useNotificationPreferences.ts | 通知偏好查询 hook | | useRealtimeNotifications.ts | 实时通知事件处理(5类 WebSocket 事件) | | ErrorBoundary 组件 | React 渲染异常兜底,已集成到 providers.tsx | | Service Worker(PWA) | sw.js + manifest.json,providers.tsx 生产环境注册 | | middleware.ts | CSP 安全头 + 认证守卫 | | i18n.ts | 双语翻译表(zh-CN + en-US) | | observability 模块 | env.ts + otel.ts + web-vitals.ts + a11y.ts(可观测性 + A11y 审计) | | bundle-analyzer | next.config.js 集成 @next/bundle-analyzer(ANALYZE=true 启用) | ### 6.5 参考项目差距分析(对照 student-portal + teacher-portal) | 参考项目功能 | parent-portal 状态 | 说明 | | -------------------------------- | ------------------ | -------------------------------------------------- | | 仪表盘 `/dashboard` | ✅ 已实现 | `/parent/dashboard` | | 成绩 `/my-grades` | ✅ 已实现 | `/parent/grades`(含柱状图+明细表) | | 考勤 `/my-attendance` | ✅ 已实现 | `/parent/attendance`(月度日历) | | 作业 `/my-homework` | ✅ 已实现 | `/parent/homework`(状态筛选) | | 学情诊断 `/dashboard/weakness` | ✅ 已实现 | `/parent/weakness`(掌握度+推荐) | | 学习趋势 `/dashboard/trend` | ✅ 已补齐 | `/parent/trend`(折线图+周期选择) | | 考试列表 `/my-exams` | ✅ 已补齐 | `/parent/exams`(按状态分组) | | 考试结果 `/my-exams/[id]/result` | ✅ 已补齐 | `/parent/exams/[id]/result`(逐题回顾) | | 班级列表 `/my-classes` | ✅ 已补齐 | `/parent/classes` | | 学习路径 `/learning-path` | ✅ 已补齐 | `/parent/learning-path` | | 通知中心 `/notifications` | ✅ 已实现 | `/parent/notifications`(含 WebSocket 实时) | | 通知偏好 | ✅ 已实现 | `/parent/preferences`(矩阵式表单+Zod) | | 设置 `/settings` | ✅ 已补齐 | `/parent/settings`(家长信息只读) | | ErrorBoundary | ✅ 已补齐 | providers.tsx 集成 | | Service Worker(PWA) | ✅ 已补齐 | sw.js + manifest.json | | OTel browser SDK | ✅ 已补齐 | observability/otel.ts + providers.tsx 挂载 | | Web Vitals | ✅ 已补齐 | observability/web-vitals.ts + WebVitalsInitializer | | A11y 审计工具 | ✅ 已补齐 | observability/a11y.ts(axe-core + 对比度检查) | | Bundle 分析 | ✅ 已补齐 | @next/bundle-analyzer + analyze 脚本 | | CSP 安全头 | ✅ 已实现 | middleware.ts(已收紧 unsafe-eval) | | 多语言 (en-US) | ✅ 已实现 | i18n.ts 双语翻译表 | > **不适用功能**(学生专属,家长端不实现): > > - 考试作答 `/my-exams/[id]/take`(家长不参加考试) > - 作业提交 `/my-homework/[id]/submit`(家长不提交作业) > - AI 辅学 `/ai-tutor`(学生专属功能) > - 教材列表 `/textbooks`(家长端暂不需要) > - 防作弊/多标签检测(考试作答专属) ### 6.6 剩余工作 1. ~~创建 `/parent/trend` 学习趋势页面~~ ✅ 2. ~~创建 `ErrorBoundary` 组件并集成~~ ✅ 3. ~~创建 Service Worker 实现 PWA 离线缓存~~ ✅ 4. ~~收紧 CSP(移除 unsafe-eval)~~ ✅ 5. ~~P6-1: OTel browser SDK + Web Vitals 挂载~~ ✅ 6. ~~P6-2: A11y 审计工具 + ARIA 修复~~ ✅ 7. ~~P6-3: Bundle 分析配置~~ ✅ 8. ~~补齐考试列表/考试结果/班级/学习路径/设置页面~~ ✅ 9. ~~ARB-020 §22.5 switchChild 双层实现~~ ✅ 10. ~~P4-9: 测试覆盖率验证(单元 ≥ 85%,集成 ≥ 75%)~~ ✅(413 测试通过,覆盖率 99%+) 11. ~~ARB-022 §24.4 双 /v1 前缀修正(GraphQL + iam login + notifications + web-vitals)~~ ✅ > **parent-portal 全部 P4-P6 任务已完成**。无剩余工作项。 --- ## §7 参考项目(CICD 单体)差距分析与实现安排 > 参考项目:`e:\Desktop\CICD\`(单体 Next_Edu 教育平台),parent 页面位于 `src/app/(dashboard)/parent/` > 分析日期:2026-07-13 > 原则:保留当前"单子女切换"范式(已稳定 13 页),按参考项目功能点补齐缺失页面,不迁移到"多子女同屏对比"范式 ### 7.1 参考项目 parent 页面全览(11 个主路由,14 个页面) | 路由 | 分类 | 核心功能 | 当前状态 | | ---- | ---- | -------- | -------- | | `/parent/dashboard` | 仪表盘 | 多子女卡片网格 + AI 摘要 + 关注横幅 + 趋势图标 | ⚠️ 部分实现 | | `/parent/attendance` | 考勤 | 聚合出勤率 + 预警横幅 + 月历导航 + a11y | ⚠️ 部分实现 | | `/parent/children/[studentId]` | 综合详情 | 多 Tab 聚合(overview/homework/grades/exams/schedule) | ❌ 缺失(设计差异,可选) | | `/parent/course-plans` + `[id]` | 课程 | 课程计划列表 + 详情只读 | ❌ 缺失 | | `/parent/diagnostic` | 诊断 | 已发布诊断报告 + 掌握度摘要 | ❌ 缺失 | | `/parent/elective` | 选修 | 选修课选课记录 | ❌ 缺失 | | `/parent/error-book` | 错题 | 5 项统计 + Top 错题 + 薄弱知识点 | ⚠️ 部分实现(weakness 仅有知识点) | | `/parent/grades` + `report-card` | 成绩 | 趋势 + 班级均对比 + 成长档案 + 导出 + 报告卡 | ⚠️ 部分实现 | | `/parent/leave` | 请假 | 在线请假表单 + 历史列表 | ❌ 缺失 | | `/parent/lesson-plans` + `[planId]/view` | 备课 | 已发布备课列表 + 只读详情 | ❌ 缺失 | | `/parent/practice` | 练习 | 4 项统计 + 练习历史 | ❌ 缺失 | ### 7.2 实现安排(按优先级) #### P0 高优先级(核心家长功能) | 任务 | 路由 | 说明 | | ---- | ---- | ---- | | P0-1 | `/parent/leave` | 请假表单(选子女/时间/原因)+ 历史列表 | | P0-2 | `/parent/grades/report-card` | 可打印报告卡 + 学年/学期筛选 | | P0-3 | `/parent/children/[studentId]` | 子女详情聚合页(Tab: overview/homework/grades/exams/schedule) | #### P1 中优先级(学情闭环) | 任务 | 路由 | 说明 | | ---- | ---- | ---- | | P1-1 | `/parent/error-book` | 错题统计网格(5 项)+ Top 错题列表 | | P1-2 | `/parent/diagnostic` | 已发布诊断报告 + 掌握度摘要 | | P1-3 | `/parent/practice` | 练习统计(4 项)+ 历史列表 | #### P2 低优先级(教学侧只读视图) | 任务 | 路由 | 说明 | | ---- | ---- | ---- | | P2-1 | `/parent/course-plans` + `[id]` | 课程计划列表 + 详情 | | P2-2 | `/parent/lesson-plans` + `[planId]/view` | 备课列表 + 只读详情 | | P2-3 | `/parent/elective` | 选修课选课记录 | #### P3 现有页面增强 | 任务 | 路由 | 增强内容 | | ---- | ---- | -------- | | P3-1 | `/parent/dashboard` | 多子女卡片网格 + 关注横幅 + 趋势图标 + 逾期高亮 | | P3-2 | `/parent/attendance` | 月份导航 + 异常预警横幅 + 聚合出勤率卡 | | P3-3 | `/parent/grades` | 班级均对比线 + 导出按钮 + 成长档案图表 | ### 7.3 实现进度 | 任务 | 状态 | 说明 | | ---- | ---- | ---- | | P0-1 `/parent/leave` | ✅ 完成 | LeaveRequestForm + LeaveRequestList + Zod 校验 + 历史筛选 | | P0-2 `/parent/grades/report-card` | ✅ 完成 | ReportCardView + 学年/学期筛选 + 打印按钮 | | P0-3 `/parent/children/[studentId]` | ✅ 完成 | ChildDetailPanel + 5 Tab(overview/homework/grades/exams/schedule) | | P1-1 `/parent/error-book` | ✅ 完成 | ErrorBookStatsCard(5 项统计) + TopWrongQuestionList + 薄弱知识点 | | P1-2 `/parent/diagnostic` | ✅ 完成 | MasterySummaryCard + DiagnosticReportList(仅 published) | | P1-3 `/parent/practice` | ✅ 完成 | PracticeStatsCard(4 项统计) + PracticeSessionList(历史) | | P2-1 `/parent/course-plans` | ✅ 完成 | CoursePlanList + CoursePlanDetail + 章节列表 | | P2-2 `/parent/lesson-plans` | ✅ 完成 | LessonPlanList(学科筛选) + LessonPlanReadonlyView(只读) | | P2-3 `/parent/elective` | ✅ 完成 | ElectiveSelectionList + 分类色点 + 状态徽标 | | P3-1 dashboard 增强 | ✅ 完成 | ParentAttentionBanner + 多子女卡片网格 + 趋势图标 + 逾期高亮 | | P3-2 attendance 增强 | ✅ 完成 | AttendanceRateCard + AttendanceWarningBanner + 月份导航 | | P3-3 grades 增强 | ✅ 完成 | GrowthArchiveChart + ExportGradesButton + 班级均对比线 | ### 7.4 实现统计 - **新增页面**: 9 个(leave / grades/report-card / children/[studentId] / error-book / diagnostic / practice / course-plans + [id] / lesson-plans + [planId]/view / elective) - **新增组件**: 20+ 个(LeaveRequestForm / LeaveRequestList / ReportCardView / ChildDetailPanel / ErrorBookStatsCard / TopWrongQuestionList / MasterySummaryCard / DiagnosticReportList / PracticeStatsCard / PracticeSessionList / CoursePlanList / CoursePlanDetail / LessonPlanList / LessonPlanReadonlyView / ElectiveSelectionList / ParentAttentionBanner / AttendanceWarningBanner / AttendanceRateCard / GrowthArchiveChart / ExportGradesButton) - **新增 hooks**: 15+ 个(useChildLeaveRequests / useCreateLeaveRequest / useAcademicYears / useReportCard / useChildDetail / useChildErrorBook / useChildDiagnostic / useChildPractice / useChildCoursePlans / useChildCoursePlanDetail / useChildLessonPlans / useChildLessonPlanDetail / useChildElective / useChildGrowthArchive / useExportChildGrades) - **新增 GraphQL operations**: 19 个(17 query + 2 mutation) - **新增 MSW handlers**: 19 个 - **新增类型**: 20+ 个(LeaveRequest / ReportCard / ErrorBookStats / TopWrongQuestion / DiagnosticReport / PracticeStats / CoursePlan / LessonPlan / ElectiveSelection / ChildDetail / ScheduleItem 等) - **测试总数**: 763 测试通过(从 413 增至 763,+350 测试) - **质量校验**: typecheck 0 错误 / lint 0 错误 / test 71 文件 763 测试全部通过 ### 7.5 参考项目功能覆盖完成度 | 参考项目页面 | 对应实现 | 覆盖度 | | ---- | ---- | ---- | | `/parent/dashboard` | `/parent/dashboard`(增强) | ✅ 100% | | `/parent/attendance` | `/parent/attendance`(增强) | ✅ 100% | | `/parent/children/[studentId]` | `/parent/children/[studentId]` | ✅ 100% | | `/parent/course-plans` + `[id]` | `/parent/course-plans` + `[id]` | ✅ 100% | | `/parent/diagnostic` | `/parent/diagnostic` | ✅ 100% | | `/parent/elective` | `/parent/elective` | ✅ 100% | | `/parent/error-book` | `/parent/error-book` | ✅ 100% | | `/parent/grades` + `report-card` | `/parent/grades`(增强) + `report-card` | ✅ 100% | | `/parent/leave` | `/parent/leave` | ✅ 100% | | `/parent/lesson-plans` + `[planId]/view` | `/parent/lesson-plans` + `[planId]/view` | ✅ 100% | | `/parent/practice` | `/parent/practice` | ✅ 100% | > **参考项目所有家长端功能已全部覆盖**。保留当前"单子女切换"范式,未迁移到"多子女同屏对比"范式(仪表盘除外,已支持多子女卡片网格)。 --- ## §8 质量门禁 每个任务完成前必须通过: - `pnpm --filter parent-portal lint` 零错误 - `pnpm --filter parent-portal typecheck` 零错误 - `pnpm --filter parent-portal test` 全绿(P4-9 起强制) - 设计令牌三层规则(无 `#hex` / 无硬编码字体 / 无任意值,ESLint 强制) - A11y:jsx-a11y error 级零违规 > 提交前校验见 [project_rules §8](../../../../.trae/rules/project_rules.md),commit 遵循 Conventional Commits:`feat(parent-portal): ...`