# 仪表盘模块审计报告 > 审查日期:2026-06-22 > 审查范围:`src/modules/dashboard/**`、`src/app/(dashboard)/*/dashboard/**`、`src/modules/parent/components/parent-dashboard.tsx`(家长端仪表盘) > 架构图参考:`docs/architecture/004_architecture_impact_map.md` §1.4.3、`docs/architecture/005_architecture_data.json` --- ## 一、现有实现概要 ### 1.1 文件分布 | 层 | 路径 | 文件数 | 说明 | |----|------|--------|------| | 路由层 | `src/app/(dashboard)/{admin,teacher,student,parent}/dashboard/` | 4 个 `page.tsx` + 3 个 `error.tsx` + 3 个 `loading.tsx` | 各角色独立路由,另有根 `/dashboard/page.tsx` 做角色重定向 | | 模块层 - admin | `src/modules/dashboard/components/admin-dashboard/` | 2 个(`admin-dashboard.tsx` 263 行、`user-growth-chart.tsx` 46 行) | | | 模块层 - teacher | `src/modules/dashboard/components/teacher-dashboard/` | 9 个组件 | `teacher-dashboard-view.tsx` 为容器,含业务计算逻辑 | | 模块层 - student | `src/modules/dashboard/components/student-dashboard/` | 6 个组件 | `student-dashboard-view.tsx` 为容器 | | 模块层 - parent | `src/modules/parent/components/parent-dashboard.tsx` | 1 个(108 行) | **不在 dashboard 模块内**,位于 parent 模块 | | 数据层 | `src/modules/dashboard/data-access.ts` | 1 个(49 行) | 仅 `getAdminDashboardData`,并行调用 6 个模块的 stats 函数 | | 类型层 | `src/modules/dashboard/types.ts` | 1 个(74 行) | Admin / Teacher / Student 类型定义 | | Actions 层 | **缺失** | 0 | 无 `actions.ts`,页面直接调用 data-access | ### 1.2 数据流 ``` [Route] /admin/dashboard/page.tsx └─▶ dashboard/data-access.getAdminDashboardData() └─▶ Promise.all(users/classes/textbooks/questions/exams/homework stats) [Route] /teacher/dashboard/page.tsx ├─▶ classes/data-access.getTeacherClasses / getClassSchedule ├─▶ homework/data-access.getHomeworkAssignments / getHomeworkSubmissions / getTeacherGradeTrends └─▶ users/data-access.getUserBasicInfo (页面层直接编排 3 个模块的 data-access) [Route] /student/dashboard/page.tsx ├─▶ users/data-access.getCurrentStudentUser ├─▶ classes/data-access.getStudentClasses / getStudentSchedule └─▶ homework/data-access.getStudentHomeworkAssignments / getStudentDashboardGrades (页面层直接编排 3 个模块的 data-access + 业务计算) [Route] /parent/dashboard/page.tsx └─▶ parent/data-access.getParentDashboardData ``` ### 1.3 架构图记录情况 `004_architecture_impact_map.md` §1.4.3 记录了 admin 仪表盘聚合链路(P0-4 已修复跨模块直查),但存在遗漏: - **未记录 teacher / student / parent 仪表盘的调用链路** - **未记录 dashboard 模块的 exports 清单**(005 JSON 中 dashboard 节点缺失 `exports` 字段) - **未记录 parent 仪表盘组件位于 parent 模块这一结构异常** --- ## 二、现存问题与原因分析 ### 2.1 安全性:权限校验完全缺失(P0) | 位置 | 问题 | 违反规则 | |------|------|----------| | [admin/dashboard/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/admin/dashboard/page.tsx) | 直接调用 `getAdminDashboardData()`,**无任何 auth/permission 校验** | "所有 Server Action 必须调用 `requirePermission()` 进行权限校验" | | [teacher/dashboard/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/teacher/dashboard/page.tsx) | 仅调用 `getAuthContext()`,未校验任何权限点 | 同上 | | [student/dashboard/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/student/dashboard/page.tsx) | **无任何 auth 调用**,完全依赖 layout 守卫 | 同上 | | [parent/dashboard/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/parent/dashboard/page.tsx) | 调用 `requireAuth()`,未校验具体权限 | 同上 | | [permissions.ts](file:///e:/Desktop/CICD/src/shared/types/permissions.ts) | **无 dashboard 相关权限点定义** | 权限体系不完整 | **后果**:admin 仪表盘数据(含全校用户数、活跃会话数、最近注册用户列表)可被任意已登录用户访问,属于严重越权。即使 layout 层有路由组守卫,data-access 层仍缺乏二次校验,不符合"Server Action 二次校验"要求。 ### 2.2 架构分层:页面层越权编排 + 模块归属错位(P0) | 位置 | 问题 | 违反规则 | |------|------|----------| | [teacher/dashboard/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/teacher/dashboard/page.tsx) L16-23 | 页面层直接 `Promise.all` 调用 classes/homework/users 三个模块的 data-access | "app/ 只能调用 modules/ 的 Server Actions 和 data-access" — 虽然语法允许,但编排逻辑应在 dashboard 模块的 actions/data-access 层完成 | | [student/dashboard/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/student/dashboard/page.tsx) L36-86 | 页面层包含 weekday 转换、作业状态统计、排序切片等 **80 行业务逻辑** | "Server Actions / Data Access 模块"应承担编排职责;纯逻辑应抽为 hooks/纯函数 | | [parent-dashboard.tsx](file:///e:/Desktop/CICD/src/modules/parent/components/parent-dashboard.tsx) | 家长仪表盘组件位于 `modules/parent` 而非 `modules/dashboard` | 仪表盘模块不完整,四角色仪表盘分散在两个模块 | | dashboard 模块无 `actions.ts` | 缺失编排层 | "模块标准结构"要求 `actions.ts`(编排层) | **后果**:页面层臃肿、逻辑不可复用、不可测试;新增角色需复制粘贴整页编排逻辑。 ### 2.3 角色硬编码(P0) | 位置 | 代码 | 违反规则 | |------|------|----------| | [dashboard/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/dashboard/page.tsx) L12-15 | `roles.includes("admin")` / `roles.includes("student")` / `roles.includes("parent")` | "前端权限判断统一使用 `usePermission().hasPermission()`,严禁出现 `role === 'xxx'` 硬编码" | | [auth-guard.ts](file:///e:/Desktop/CICD/src/shared/lib/auth-guard.ts) L69/L74/L86/L118/L131 | `roleNames.includes("admin"/"teacher"/"student"/"parent")` | 同上(dataScope 解析也基于角色硬编码) | **后果**:新增角色(如 grade_head 已存在但未处理仪表盘重定向)无法正确路由;权限策略变更需改多处代码。 ### 2.4 国际化:零覆盖 + 中英混杂(P0) | 位置 | 问题 | |------|------| | [admin-dashboard.tsx](file:///e:/Desktop/CICD/src/modules/dashboard/components/admin-dashboard/admin-dashboard.tsx) | L34 `"Dashboard"`、L63 `"Users"` 为英文;L74 `"批量导入用户"`、L113 `"用户增长趋势(近30天)"` 为中文 — **同一文件中英混杂** | | [teacher-dashboard-header.tsx](file:///e:/Desktop/CICD/src/modules/dashboard/components/teacher-dashboard/teacher-dashboard-header.tsx) L13-16 | `greeting = "早上好"/"下午好"/"晚上好"` 硬编码 | | [teacher-dashboard-view.tsx](file:///e:/Desktop/CICD/src/modules/dashboard/components/teacher-dashboard/teacher-dashboard-view.tsx) L53-55 | `"待批改作业"` / `"今日待考勤"` / `"进行中作业"` 硬编码 | | [student-stats-grid.tsx](file:///e:/Desktop/CICD/src/modules/dashboard/components/student-dashboard/student-stats-grid.tsx) | `"Enrolled Classes"` / `"Average Score"` 等全英文硬编码 | | [parent-dashboard.tsx](file:///e:/Desktop/CICD/src/modules/parent/components/parent-dashboard.tsx) L28-31 | `"Good morning"` / `"Good afternoon"` 硬编码 | | [user-growth-chart.tsx](file:///e:/Desktop/CICD/src/modules/dashboard/components/admin-dashboard/user-growth-chart.tsx) L42 | `name="新增用户"` 硬编码 | | `messages/` 目录 | **无 `dashboard.json`**,仅 onboarding/classes/auth/errors/common 有翻译文件 | **违反规则**:"所有用户可见文本必须适配 i18n(使用 next-intl),提取翻译键"。 **后果**:无法切换语言;维护时需逐文件改字符串;中英混杂给用户造成混乱。 ### 2.5 错误与边界处理:仅路由级(P1) | 位置 | 问题 | |------|------| | `error.tsx` / `loading.tsx` | 仅存在于路由级(`app/(dashboard)/*/dashboard/`),**无按数据区块的 Error Boundary** | | [admin-dashboard.tsx](file:///e:/Desktop/CICD/src/modules/dashboard/components/admin-dashboard/admin-dashboard.tsx) | 6 张 Card + 1 张表格,任一数据源异常导致整页崩溃 | | [teacher-dashboard-view.tsx](file:///e:/Desktop/CICD/src/modules/dashboard/components/teacher-dashboard/teacher-dashboard-view.tsx) | 7 个子区块,无独立 Suspense 包裹 | | error.tsx 文案 | `"页面加载失败"` 硬编码中文,未 i18n | **违反规则**:"每个独立的数据区块必须用 React Error Boundary 包裹"、"异步数据使用 React Suspense + 骨架屏"。 **后果**:单个 Widget 故障导致整页不可用;无法流式渲染,首屏白屏时间长。 ### 2.6 可测试性:业务逻辑与 UI 耦合(P1) | 位置 | 耦合的逻辑 | |------|-----------| | [teacher-dashboard-view.tsx](file:///e:/Desktop/CICD/src/modules/dashboard/components/teacher-dashboard/teacher-dashboard-view.tsx) L18-56 | `toWeekday`、`todayScheduleItems` 过滤排序、`toGradeCount`/`submissionRate` 计算、`todoItems` 聚合 — 全部内联在组件中 | | [student/dashboard/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/student/dashboard/page.tsx) L13-86 | `toWeekday`、`dueSoonCount`/`overdueCount`/`gradedCount` 单次遍历统计、`upcomingAssignments` 排序切片 — 80 行纯逻辑在 Server Component 中 | | [parent-dashboard.tsx](file:///e:/Desktop/CICD/src/modules/parent/components/parent-dashboard.tsx) L27-31 | greeting 时段判断内联在组件中 | **违反规则**:"数据获取、计算、格式化等纯逻辑全部放入纯函数或 hooks,与 UI 分离"。 **后果**:无法对统计逻辑做单元测试;逻辑变更需改组件代码;复用需复制粘贴。 ### 2.7 可复用性:四角色零共享抽象(P1) | 维度 | 现状 | |------|------| | 布局容器 | admin/teacher/student/parent 各写一套 `