V2 审计报告(docs/architecture/audit/dashboard-audit-report-v2.md)发现并修复: - P0 i18n:10 个子组件硬编码字符串全部接入 next-intl(teacher-quick-actions / teacher-classes-card / teacher-homework-card / teacher-schedule / recent-submissions / teacher-grade-trends / student-grades-card / student-today-schedule-card / student-upcoming-assignments-card / admin-dashboard),新增 ~50 个翻译键 - P1 共享抽象:新增 DashboardGreetingHeader 组件,消除 teacher/student 头部 90% 重复代码,两个 Header 改为薄包装 - P2 单测:为 6 个纯函数添加 31 个单元测试 (tests/integration/dashboard/dashboard-utils.test.ts) - P2 a11y:admin 表格 caption、teacher/student 视图语义化标签 (header / section aria-label / aside aria-label) - 同步架构图 004/005
8.6 KiB
仪表盘模块审计报告 v2
审查日期:2026-06-22(第二轮) 审查范围:基于 v1 重构后代码(commit
868ac5f+21c1e7a)的再次分析 前置报告:docs/architecture/audit/dashboard-audit-report.md(v1) 架构图参考:docs/architecture/004_architecture_impact_map.md§2.12、docs/architecture/005_architecture_data.json
一、v1 重构成果回顾
v1 报告识别的 P0/P1/P2 项目已完成的部分:
| # | 项目 | 状态 | 证据 |
|---|---|---|---|
| P0-1 | 权限校验 | ✅ 已完成 | actions.ts 4 个 Server Action 均调用 requirePermission() |
| P0-2 | 根重定向角色硬编码 | ✅ 已完成 | dashboard/page.tsx 改用 resolvePermissions() |
| P0-3 | i18n 零覆盖 | ⚠️ 部分完成 | 仅容器组件接入 i18n,10 个子组件仍英文硬编码 |
| P0-4 | 页面层越权编排 | ✅ 已完成 | teacher/student/parent 编排下沉至 actions.ts |
| P1-1 | 业务逻辑耦合 UI | ✅ 已完成 | lib/dashboard-utils.ts 抽取 6 个纯函数 |
| P1-3 | 仅路由级错误边界 | ✅ 已完成 | dashboard-section.tsx 分区 Error Boundary + Suspense |
| P2-2 | a11y 不足 | ❌ 未完成 | 仍缺语义化标签、表格 caption |
二、v2 新发现问题
2.1 i18n 覆盖严重不完整(P0 — v1 遗漏)
v1 仅对容器组件(admin-dashboard.tsx、teacher-dashboard-view.tsx、teacher-dashboard-header.tsx、teacher-stats.tsx、teacher-todo-card.tsx、student-stats-grid.tsx、student-dashboard-header.tsx、parent-dashboard.tsx、user-growth-chart.tsx)接入 i18n,10 个子组件仍全英文硬编码:
| # | 文件 | 硬编码示例 | 违反规则 |
|---|---|---|---|
| 1 | teacher-quick-actions.tsx L12-24 | "Create Assignment" / "Grade" / "My Classes" |
"所有用户可见文本必须适配 i18n" |
| 2 | teacher-classes-card.tsx L15-27 | "My Classes" / "View all" / "No classes yet" / "Create a class to start managing students and schedules." / "Create class" / "Homeroom" / "Room" |
同上 |
| 3 | teacher-homework-card.tsx L17-87 | "Homework" / "Create new assignment" / "No assignments" / "Create an assignment to get started." / "Create" / "No due date" / "View all assignments" |
同上 |
| 4 | teacher-schedule.tsx L41-141 | "Today's Schedule" / "No Classes Today" / "No timetable entries." / "View schedule" / "LIVE" / "Scroll for more" / "No more classes today" |
同上 |
| 5 | recent-submissions.tsx L22-105 | "Recent Submissions" / "No New Submissions" / "All caught up!..." / "View All" / "View submissions" / "Student" / "Assignment" / "Submitted" / "Action" / "Late" / "Grade" |
同上 |
| 6 | teacher-grade-trends.tsx L25-69 | "Class Performance" / "Average scores for the last X assignments" / "No data available" / "Publish assignments to see class performance trends." / "Average Score (%)" / "X/Y submitted" |
同上 |
| 7 | student-grades-card.tsx L30-101 | "Recent Grades" / "No graded work yet" / "Finish and submit assignments to see your score trend." / "View all" / "Score (%)" / "Latest:" / "Points:" / "Assignment" / "Score" / "When" |
同上 |
| 8 | student-today-schedule-card.tsx L52-83 | "Today's Schedule" / "View all" / "No classes today" / "Your timetable is clear for today." / "In Progress" / "Up Next" |
同上 |
| 9 | student-upcoming-assignments-card.tsx L17-22,49-72 | "Review" / "View" / "Continue" / "Start" / "Upcoming Assignments" / "View all" / "No assignments" / "You have no assigned homework right now." / "Title" / "Status" / "Due" / "Score" / "Action" / "Late" |
同上 |
| 10 | admin-dashboard.tsx L212 | {u.role ?? "unknown"} 硬编码 "unknown" |
同上 |
后果:中文用户看到大量英文,体验割裂;无法切换语言;维护时需逐文件改字符串。
2.2 四角色仍零共享抽象(P1 — v1 未处理)
| 维度 | 现状 | 期望 |
|---|---|---|
| 问候语头部 | TeacherDashboardHeader 与 StudentDashboardHeader 代码 90% 重复(仅 props 名不同) |
抽象为 DashboardGreetingHeader |
| 快捷操作 | admin 的 QuickActionCard(内联)、parent 的 QUICK_ENTRIES(内联)、teacher 的 TeacherQuickActions — 三套独立实现 |
抽象为 DashboardQuickActions |
| 仪表盘布局容器 | admin/teacher/student 各写一套 <div className="space-y-*"> |
抽象为 DashboardLayout |
违反规则:"最大化复用:识别四个角色共用的 UI 块和业务逻辑块,抽象为泛型组件和 hooks"。
2.3 无单测(P2 — v1 未处理)
lib/dashboard-utils.ts 抽取了 6 个纯函数但无任何单测:
| 函数 | 测试覆盖 | 风险 |
|---|---|---|
toWeekday |
❌ 无 | 周日映射错误未被发现 |
countStudentAssignments |
❌ 无 | 边界条件(无截止日期/已批改)未验证 |
sortUpcomingAssignments |
❌ 无 | 排序稳定性未验证 |
filterTodaySchedule |
❌ 无 | 空课表/排序未验证 |
computeTeacherMetrics |
❌ 无 | 提交率分母为零等边界未验证 |
getGreetingKey |
❌ 无 | 时段边界(12:00/18:00)未验证 |
违反规则:"数据获取、计算、格式化等纯逻辑全部放入纯函数或 hooks,与 UI 分离;导出清晰的接口类型以便 mock" + "可测试性"。
2.4 a11y 不足(P2 — v1 未处理)
| 位置 | 问题 | 违反规则 |
|---|---|---|
admin-dashboard.tsx 表格 |
无 <caption> |
"语义化标签、ARIA 属性、键盘导航" |
recent-submissions.tsx 表格 |
无 <caption> |
同上 |
student-upcoming-assignments-card.tsx 表格 |
无 <caption> |
同上 |
teacher-dashboard-view.tsx 布局 |
无 <section> / <aside> 语义化标签 |
同上 |
student-dashboard-view.tsx 布局 |
同上 | 同上 |
teacher-schedule.tsx 时间线 |
无 aria-label 描述当前/过去/未来状态 |
同上 |
2.5 流式渲染未实现(P1 — v1 未处理)
所有 page.tsx 仍 export const dynamic = "force-dynamic" + Promise.all 等全部数据就绪后才渲染。虽然 DashboardSection 内部有 Suspense,但 page 层已无 Suspense 边界,无法流式渲染首屏。
三、改进优先级(v2)
P0(紧急 — v1 遗漏的 i18n)
| # | 问题 | 改进方向 |
|---|---|---|
| v2-P0-1 | 10 个组件英文硬编码 | 全部接入 useTranslations / getTranslations;补充翻译键 |
P1(较严重 — 共享抽象 + 单测)
| # | 问题 | 改进方向 |
|---|---|---|
| v2-P1-1 | 问候语头部重复 | 抽象 DashboardGreetingHeader 组件 |
| v2-P1-2 | 纯函数无单测 | 为 lib/dashboard-utils.ts 6 个函数添加单测 |
P2(优化 — a11y + 流式)
| # | 问题 | 改进方向 |
|---|---|---|
| v2-P2-1 | 表格无 caption / 布局无语义化标签 | 补充 <caption> / <section> / aria-label |
四、架构图同步说明
v2 修改完成后需同步更新:
4.1 004_architecture_impact_map.md
- §2.12 dashboard 章节:补充新增共享组件(
DashboardGreetingHeader)、单测文件(lib/dashboard-utils.test.ts)
4.2 005_architecture_data.json
modules.dashboard.exports.components:新增DashboardGreetingHeadermodules.dashboard.exports.lib:补充单测覆盖说明