Files
CICD/docs/design/002_teacher_dashboard_implementation.md
SpecialX ade8d4346c feat(dashboard): optimize teacher dashboard ui and layout
- Refactor layout: move Needs Grading to main column, Homework to sidebar
- Enhance TeacherStats: replace static counts with actionable metrics (Needs Grading, Active Assignments, Avg Score, Submission Rate)
- Update RecentSubmissions: table view with quick grade actions and late status
- Update TeacherSchedule: vertical timeline view with scroll hints
- Update TeacherHomeworkCard: compact list view
- Integrate Recharts: add TeacherGradeTrends chart and shared chart component
- Update documentation
2026-01-12 11:38:27 +08:00

237 lines
9.9 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.

# 教师仪表盘实现与 Hydration 修复记录
**日期**: 2025-12-23
**作者**: 资深前端工程师 (Senior Frontend Engineer)
**状态**: 已实现
## 1. 概述
本文档详细说明了教师仪表盘 (Teacher Dashboard) 的实现细节,该实现严格遵循 Next_Edu 设计系统 v1.3.0。文档还记录了开发过程中遇到的 Hydration 错误及其解决方案。
## 2. 组件架构
仪表盘采用垂直切片架构 (Vertical Slice Architecture),代码位于 `src/modules/dashboard`
### 2.1 文件结构
```
src/modules/dashboard/
└── components/
├── teacher-stats.tsx # 核心指标 (学生数, 课程数, 待批改作业)
├── teacher-schedule.tsx # 今日日程列表
├── recent-submissions.tsx # 最近的学生提交记录
└── teacher-quick-actions.tsx # 常用操作 (创建作业等)
```
### 2.2 设计系统集成
所有组件严格遵循 v1.3.0 规范:
- **排版 (Typography)**: 使用 `Geist Sans`,数据展示开启 `tabular-nums`
- **色彩 (Colors)**: 使用语义化 HSL 变量 (`muted`, `primary`, `destructive`)。
- **图标 (Icons)**: 使用 `lucide-react` (如 `Users`, `BookOpen`, `Inbox`)。
- **状态 (States)**:
- **Loading**: 使用自定义骨架屏 (Skeleton),拒绝全屏 Spinner。
- **Empty**: 使用 `EmptyState` 组件处理无数据场景。
## 3. 组件详情
### 3.1 TeacherStats (教师统计)
- **用途**: 展示教师当前状态的高层概览。
- **特性**:
- 在响应式网格中展示 4 个关键指标。
- 支持 `isLoading` 属性以渲染骨架屏。
- 使用 `Card` 组件作为容器。
### 3.2 TeacherSchedule (教师日程)
- **用途**: 展示今日课程安排。
- **特性**:
- 列出课程时间及地点。
- 使用 Badge 区分 "Lecture" (讲座) 和 "Workshop" (研讨会)。
- **空状态**: 当无日程时显示 "No Classes Today"。
### 3.3 RecentSubmissions (最近提交)
- **用途**: 追踪最新的学生活动。
- **特性**:
- 展示学生头像、姓名、作业名称及时间。
- "Late" (迟交) 状态指示器。
- **空状态**: 当列表为空时显示 "No New Submissions"。
### 3.4 EmptyState Component (空状态组件)
- **位置**: `src/shared/components/ui/empty-state.tsx`
- **规范**:
- 虚线边框容器。
- 居中图标 (Muted 背景)。
- 清晰的标题和描述。
- 可选的操作按钮插槽。
## 4. Hydration 错误修复
### 4.1 问题描述
开发过程中观察到 "Hydration failed" 错误,原因是 HTML 嵌套无效。具体来说,是 `p` 标签内包含了块级元素(或 React 在 hydration 检查期间视为块级的元素)。
### 4.2 根本原因分析
React 的 hydration 过程对 HTML 有效性要求极高。将 `div` 放入 `p` 标签中违反了 HTML5 标准,但浏览器通常会自动修正 DOM 结构,导致实际 DOM 与 React 基于虚拟 DOM 预期的结构不一致。
### 4.3 实施的修复
将所有仪表盘组件中存在风险的 `p` 标签替换为 `div` 标签,以确保嵌套结构的健壮性。
**示例 (RecentSubmissions):**
*修改前 (有风险):*
```tsx
<p className="text-sm font-medium leading-none">
{item.studentName}
</p>
```
*修改后 (安全):*
```tsx
<div className="text-sm font-medium leading-none">
{item.studentName}
</div>
```
**受影响的组件:**
1. `recent-submissions.tsx`
2. `teacher-stats.tsx`
3. `teacher-schedule.tsx`
## 5. 更新记录2026-01-04
- 教师仪表盘从 Mock Data 切换为真实数据查询:`/teacher/dashboard` 组合 `getTeacherClasses``getClassSchedule``getHomeworkSubmissions({ creatorId })` 渲染 KPI / 今日课表 / 最近提交。
- Quick Actions 落地为真实路由跳转(创建作业、查看列表等)。
- Schedule / Submissions 增加 “View All” 跳转到对应列表页(并携带筛选参数)。
---
## 6. 教师端班级管理模块(真实数据接入记录)
**日期**: 2025-12-31
**范围**: 教师端「我的班级 / 学生 / 课表」页面与 MySQL(Drizzle) 真数据对接
### 6.1 页面入口与路由
班级管理相关页面位于:
- `src/app/(dashboard)/teacher/classes/my/page.tsx`
- `src/app/(dashboard)/teacher/classes/students/page.tsx`
- `src/app/(dashboard)/teacher/classes/schedule/page.tsx`
为避免构建期/预渲染阶段访问数据库导致失败,以上页面显式启用动态渲染:
- `export const dynamic = "force-dynamic"`
### 6.2 模块结构Vertical Slice
班级模块采用垂直切片架构,代码位于 `src/modules/classes/`
```
src/modules/classes/
├── components/
│ ├── my-classes-grid.tsx
│ ├── students-filters.tsx
│ ├── students-table.tsx
│ ├── schedule-filters.tsx
│ └── schedule-view.tsx
├── data-access.ts
└── types.ts
```
其中 `data-access.ts` 负责班级、学生、课表三类查询的服务端数据读取,并作为页面层唯一的数据入口。
### 6.3 数据库表与迁移
新增班级领域表:
- `classes`
- `class_enrollments`
- `class_schedule`
对应 Drizzle Schema
- `src/shared/db/schema.ts`
- `src/shared/db/relations.ts`
对应迁移文件:
- `drizzle/0003_petite_newton_destine.sql`
外键关系(核心):
- `classes.teacher_id` -> `users.id`
- `class_enrollments.class_id` -> `classes.id`
- `class_enrollments.student_id` -> `users.id`
- `class_schedule.class_id` -> `classes.id`
索引(核心):
- `classes_teacher_idx`, `classes_grade_idx`
- `class_enrollments_class_idx`, `class_enrollments_student_idx`
- `class_schedule_class_idx`, `class_schedule_class_day_idx`
### 6.4 Seed 数据
Seed 脚本已覆盖班级相关数据,以便在开发环境快速验证页面渲染与关联关系:
- `scripts/seed.ts`
- 运行命令:`npm run db:seed`
### 6.5 开发过程中的问题与处理
- 端口占用EADDRINUSE开发服务器端口被占用时通过更换端口启动规避例如 `next dev -p <port>`)。
- Next dev 锁文件:出现 `.next/dev/lock` 无法获取锁时,需要确保只有一个 dev 实例在运行,并清理残留 lock。
- 头像资源 404移除 Header 中硬编码的本地头像资源引用,避免 `public/avatars/...` 不存在导致的 404 噪音(见 `src/modules/layout/components/site-header.tsx`)。
- 班级人数统计查询失败:`class_enrollments` 表实际列名为 `class_enrollment_status`,修复查询中引用的列名以恢复教师端班级列表渲染。
- Students 页面 key 冲突:学生列表跨班级汇总时,`<TableRow key={studentId}>` 会重复,改为使用 `classId:studentId` 作为 key。
- Build 预渲染失败(/login`LoginForm` 使用 `useSearchParams()` 获取回跳地址,需在 `/login` 页面用 `Suspense` 包裹以避免 CSR bailout 报错。
- 构建警告middlewareNext.js 16 将文件约定从 `middleware.ts` 改为 `proxy.ts`,已迁移以消除警告。
### 6.6 班级详情页(聚合视图 + Schedule Builder + Homework 统计)
**日期**: 2026-01-04
**入口**: `src/app/(dashboard)/teacher/classes/my/[id]/page.tsx`
聚合数据在单次 RSC 请求内并发获取:
- 学生:`getClassStudents({ classId })`
- 课表:`getClassSchedule({ classId })`
- 作业统计:`getClassHomeworkInsights({ classId, limit })`(包含 latest、历史列表、overallScores、以及每次作业的 scoreStatsavg/median
页面呈现:
- 顶部 KPI 卡片:学生数、课表条目数、作业数、整体 avg/median
- Latest homework目标人数、提交数、批改数、avg/median直达作业与提交列表
- Students / Schedule 预览:提供 View all 跳转到完整列表页
- Homework history 表格:支持通过 URL query `?hw=all|active|overdue` 过滤作业记录,并展示每条作业的 avg/median
课表编辑能力复用既有 Builder
- 组件:`src/modules/classes/components/schedule-view.tsx`(新增/编辑/删除课表项)
- 数据变更:`src/modules/classes/actions.ts`
### 6.7 班级邀请码6 位码)加入与管理
**日期**: 2026-01-08
**范围**: 为班级新增 6 位邀请码,支持学生通过输入邀请码加入班级;教师可查看与刷新邀请码
---
## 7. 教师仪表盘体验优化 (2026-01-12)
**目标**: 提升教师仪表盘的信息密度与易用性,优化核心指标展示,调整布局以符合教师工作流。
### 7.1 核心指标卡片重构 (TeacherStats)
- **原有问题**: 展示的总学生数、总课程数等静态指标对日常教学决策帮助有限。
- **优化方案**: 替换为高频动态指标,并增强视觉提示。
- **Needs Grading (待批改)**: 高亮显示待处理事项,使用 Amber 色彩引起注意。
- **Active Assignments (活跃作业)**: 显示当前发布的作业数量,反映教学负载。
- **Average Score (平均分)**: 展示近期作业平均分,快速了解学情。
- **Submission Rate (提交率)**: 展示整体作业完成度,反映学生参与度。
### 7.2 布局调整 (Layout Restructuring)
- **原有问题**: "Needs Grading" 位于侧边栏,空间受限;"Homework" 列表占据主栏,信息密度低。
- **优化方案**:
- **Needs Grading 移至主栏**: 给予更多宽幅空间,展示详细的学生、作业信息及操作按钮。
- **Homework 移至侧边栏**: 改为紧凑列表视图,作为快速导航入口。
- **Schedule 优化**: 引入时间轴 (Timeline) 视图,支持滚动提示与当前状态指示。
### 7.3 组件功能增强
- **RecentSubmissions (Needs Grading)**:
- 升级为 Table 视图,展示头像、作业名、提交时间。
- 增加 "Grade" 快捷按钮,一键进入批改页面。
- 增加 "Late" 状态标记。
- **TeacherSchedule**:
- 采用垂直时间轴设计。
- 增加滚动提示 (Scroll Hint) 与 "No more classes" 状态提示。
- **TeacherHomeworkCard**:
- 优化为紧凑型列表,显示发布状态 (Published/Draft) 与截止日期。
### 7.4 技术细节
- 引入 `recharts` 替换手写 SVG 图表,统一图表风格。
- 优化 Grid 布局响应式表现 (`lg:grid-cols-12`)。