# 仪表盘模块审计报告 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](file:///e:/Desktop/CICD/src/modules/dashboard/actions.ts) 4 个 Server Action 均调用 `requirePermission()` |
| P0-2 | 根重定向角色硬编码 | ✅ 已完成 | [dashboard/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/dashboard/page.tsx) 改用 `resolvePermissions()` |
| P0-3 | i18n 零覆盖 | ⚠️ 部分完成 | 仅容器组件接入 i18n，**10 个子组件仍英文硬编码** |
| P0-4 | 页面层越权编排 | ✅ 已完成 | teacher/student/parent 编排下沉至 actions.ts |
| P1-1 | 业务逻辑耦合 UI | ✅ 已完成 | [lib/dashboard-utils.ts](file:///e:/Desktop/CICD/src/modules/dashboard/lib/dashboard-utils.ts) 抽取 6 个纯函数 |
| P1-3 | 仅路由级错误边界 | ✅ 已完成 | [dashboard-section.tsx](file:///e:/Desktop/CICD/src/modules/dashboard/components/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](file:///e:/Desktop/CICD/src/modules/dashboard/components/teacher-dashboard/teacher-quick-actions.tsx) L12-24 | `"Create Assignment"` / `"Grade"` / `"My Classes"` | "所有用户可见文本必须适配 i18n" |
| 2 | [teacher-classes-card.tsx](file:///e:/Desktop/CICD/src/modules/dashboard/components/teacher-dashboard/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](file:///e:/Desktop/CICD/src/modules/dashboard/components/teacher-dashboard/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](file:///e:/Desktop/CICD/src/modules/dashboard/components/teacher-dashboard/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](file:///e:/Desktop/CICD/src/modules/dashboard/components/teacher-dashboard/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](file:///e:/Desktop/CICD/src/modules/dashboard/components/teacher-dashboard/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](file:///e:/Desktop/CICD/src/modules/dashboard/components/student-dashboard/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](file:///e:/Desktop/CICD/src/modules/dashboard/components/student-dashboard/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](file:///e:/Desktop/CICD/src/modules/dashboard/components/student-dashboard/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](file:///e:/Desktop/CICD/src/modules/dashboard/components/admin-dashboard/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`：新增 `DashboardGreetingHeader`
- `modules.dashboard.exports.lib`：补充单测覆盖说明
