- 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
237 lines
9.9 KiB
Markdown
237 lines
9.9 KiB
Markdown
# 教师仪表盘实现与 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 报错。
|
||
- 构建警告(middleware):Next.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、以及每次作业的 scoreStats:avg/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`)。
|