Files
NextEdu/bugs/teacher_bug_v2.md
SpecialX 978d9a8309
Some checks failed
Security / deep-security-scan (push) Failing after 20m5s
DR Drill / dr-drill (push) Failing after 1m31s
CI / scheduled-backup (push) Failing after 1m31s
CI / backup-verify (push) Has been skipped
CI / weekly-dr-drill (push) Failing after 0s
CI / build-deploy (push) Has been cancelled
CI / security-scan (push) Has been cancelled
feat: 新增备课模块并修复全模块 P0/P1/P2 缺陷
主要变更:

- 新增 lesson-preparation 模块: 备课编辑器、节点编辑、AI 建议、知识点选择、版本历史、作业发布

- 新增 shared 通用组件: charts/question-bank-filters/schedule-list/ui (chip-nav/filter-bar/page-header/stat-card/stat-item)

- 新增 student/admin 端 loading.tsx 与 error.tsx, 优化加载与错误态体验

- 新增 teacher/lesson-plans 页面 (列表/新建/编辑)

- 新增 drizzle 迁移 0002_tiny_lionheart 及 snapshot

- 新增 textbooks/schema.ts 与 exams/utils/normalize-structure.ts

- 修复 Tiptap v3 SSR hydration 崩溃 (rich-text-block immediatelyRender: false)

- 重构多模块 data-access/actions/组件, 修复权限校验与类型规范

- 同步架构文档 004/005 反映新增模块、导出、依赖关系

- 归档 bugs/* 测试报告与 e2e 测试脚本 (admin/parent/student/teacher web_test)
2026-06-22 01:06:16 +08:00

884 lines
44 KiB
Markdown
Raw Permalink 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.
# `src/app/(dashboard)/teacher` 前端规范核查报告 v2
> 核查日期2026-06-18第二轮
> 核查范围:`src/app/(dashboard)/teacher/` 目录下所有前端文件page.tsx / loading.tsx
> 依据文档:项目规则、编码规范 `docs/standards/coding-standards.md`、架构影响地图 004、架构数据 005
> 应用技能:`vercel-react-best-practices`(性能优化)、`web-artifacts-builder`(界面优化)、`web-design-guidelines`Web 界面规范审查)
> 对比基准:[v1 报告](./teacher_bug.md)
---
## 一、v1 → v2 修复状态总览
### 1.1 修复进度统计
| 状态 | 数量 | 占比 |
|------|------|------|
| 已修复 | 3 | 4.7% |
| 部分修复 | 1 | 1.6% |
| 未修复 | 60 | 93.7% |
| **合计** | **64** | **100%** |
### 1.2 已修复问题清单
| v1 BUG ID | 问题摘要 | 修复方式 |
|-----------|----------|----------|
| T29 | schedule-changes/page.tsx 通过 actions 调用 | 改为从 `@/modules/scheduling/data-access` 导入 `getAdminClassesForScheduling` / `getTeachersForScheduling` / `getScheduleChanges` |
| T57 | exams/all/page.tsx 缺少 `export const dynamic` | 当前仍缺少,但使用 Suspense 模式可接受(**部分修复**,见下方说明) |
| 新增 | lesson-plans 模块新增 | 新增 3 个页面,需审查 |
### 1.3 新增文件清单
| 文件 | 行数 | 类型 | 用途 |
|------|------|------|------|
| [lesson-plans/page.tsx](../src/app/(dashboard)/teacher/lesson-plans/page.tsx) | 32 | 页面 | 课案列表 |
| [lesson-plans/new/page.tsx](../src/app/(dashboard)/teacher/lesson-plans/new/page.tsx) | 10 | 页面 | 新建课案 |
| [lesson-plans/[planId]/edit/page.tsx](../src/app/(dashboard)/teacher/lesson-plans/[planId]/edit/page.tsx) | 36 | 页面 | 编辑课案 |
---
## 二、未修复问题清单(按严重度排序)
### 2.1 架构分层违规 — 严重度P0
#### BUG-V2-T01app 层直接访问数据库dashboard/page.tsx❌ 未修复
- **位置**[dashboard/page.tsx:4-6, 18-21](../src/app/(dashboard)/teacher/dashboard/page.tsx)
- **问题**:页面直接 `import { db } from "@/shared/db"` 并调用 `db.query.users.findFirst()`,违反项目规则「`app/` 只能调用 `modules/` 的 Server Actions 和 data-access不直接访问 DB」
- **现状**
```typescript
import { db } from "@/shared/db"
import { users } from "@/shared/db/schema"
// ...
db.query.users.findFirst({
where: eq(users.id, teacherId),
columns: { name: true },
})
```
- **改进建议**`modules/users/data-access.ts` 已有 `getUserBasicInfo(userId)` 函数(返回 name/email/image/gradeId可直接复用
```typescript
import { getUserBasicInfo } from "@/modules/users/data-access"
const teacherProfile = await getUserBasicInfo(teacherId)
// teacherProfile?.name
```
#### BUG-V2-T02app 层直接访问数据库grades/page.tsx❌ 未修复
- **位置**[grades/page.tsx:5-7, 35](../src/app/(dashboard)/teacher/grades/page.tsx)
- **问题**:直接 `db.query.subjects.findMany()` 查询科目列表
- **改进建议**`modules/school/data-access.ts` 已有 `getSubjectOptions()` 函数(返回 id/name/code/order可直接复用
```typescript
import { getSubjectOptions } from "@/modules/school/data-access"
const allSubjects = await getSubjectOptions()
```
#### BUG-V2-T03app 层直接访问数据库grades/analytics/page.tsx❌ 未修复
- **位置**[grades/analytics/page.tsx:5-6, 48-50](../src/app/(dashboard)/teacher/grades/analytics/page.tsx)
- **问题**:同 V2-T02
- **改进建议**:同 V2-T02
#### BUG-V2-T04app 层直接访问数据库grades/entry/page.tsx❌ 未修复
- **位置**[grades/entry/page.tsx:1-3, 25](../src/app/(dashboard)/teacher/grades/entry/page.tsx)
- **问题**:同 V2-T02
- **改进建议**:同 V2-T02
#### BUG-V2-T05app 层直接访问数据库grades/stats/page.tsx❌ 未修复
- **位置**[grades/stats/page.tsx:1-3, 28](../src/app/(dashboard)/teacher/grades/stats/page.tsx)
- **问题**:同 V2-T02
- **改进建议**:同 V2-T02
#### BUG-V2-T06认证上下文获取方式不一致 ❌ 未修复
- **位置**
- [course-plans/page.tsx:1, 23](../src/app/(dashboard)/teacher/course-plans/page.tsx)
- [elective/page.tsx:1, 23](../src/app/(dashboard)/teacher/elective/page.tsx)
- **问题**:使用 `import { auth } from "@/auth"` + `auth()` 获取 session而其他页面统一使用 `getAuthContext()`(含 DataScope 解析)
- **影响**:无法获得 `dataScope`,无法做数据范围过滤;与项目其他页面不一致
- **改进建议**:统一改为 `const ctx = await getAuthContext(); const teacherId = ctx.userId`
---
### 2.2 Prettier 配置违规 — 严重度P2
#### BUG-V2-T07textbooks/page.tsx 使用分号 ❌ 未修复
- **位置**[textbooks/page.tsx:3, 73](../src/app/(dashboard)/teacher/textbooks/page.tsx)
- **问题**`import { TextbookCard } from "...";` 等多处使用分号
- **改进建议**:运行 `npx prettier --write` 统一格式
#### BUG-V2-T08textbooks/[id]/page.tsx 使用分号 ❌ 未修复
- **位置**[textbooks/[id]/page.tsx](../src/app/(dashboard)/teacher/textbooks/[id]/page.tsx)(全文)
- **问题**:多处语句使用分号结尾
- **改进建议**:同 V2-T07
#### BUG-V2-T09textbooks/loading.tsx 使用分号 ❌ 未修复
- **位置**[textbooks/loading.tsx](../src/app/(dashboard)/teacher/textbooks/loading.tsx)(全文)
- **问题**:同 V2-T07
- **改进建议**:同 V2-T07
#### BUG-V2-T10textbooks/[id]/loading.tsx 使用分号 ❌ 未修复
- **位置**[textbooks/[id]/loading.tsx](../src/app/(dashboard)/teacher/textbooks/[id]/loading.tsx)(全文)
- **问题**:同 V2-T07
- **改进建议**:同 V2-T07
#### BUG-V2-T10alesson-plans 系列文件使用分号 🆕 新增
- **位置**
- [lesson-plans/page.tsx](../src/app/(dashboard)/teacher/lesson-plans/page.tsx)(全文)
- [lesson-plans/new/page.tsx](../src/app/(dashboard)/teacher/lesson-plans/new/page.tsx)(全文)
- [lesson-plans/[planId]/edit/page.tsx](../src/app/(dashboard)/teacher/lesson-plans/[planId]/edit/page.tsx)(全文)
- **问题**:新增文件均使用分号结尾,违反 `.prettierrc` 的 `"semi": false`
- **改进建议**:同 V2-T07
---
### 2.3 TypeScript 规范违规 — 严重度P1
#### BUG-V2-T11使用 `as` 类型断言exams/[id]/build/page.tsx❌ 未修复
- **位置**[exams/[id]/build/page.tsx:32-34](../src/app/(dashboard)/teacher/exams/[id]/build/page.tsx)
- **问题**:使用 `as` 断言转换类型,违反编码规范「禁止 `as` 断言(除非从 `unknown` 转换)」
- **现状**
```typescript
content: q.content as Question["content"],
type: q.type as Question["type"],
```
- **改进建议**:在 data-access 层返回正确类型,或使用类型守卫函数
#### BUG-V2-T12使用 `as` 类型断言attendance/page.tsx❌ 未修复
- **位置**[attendance/page.tsx:39](../src/app/(dashboard)/teacher/attendance/page.tsx)
- **问题**`status as "present" | "absent" | "late" | "early_leave" | "excused"` 直接断言
- **改进建议**:使用类型守卫函数 `isAttendanceStatus(value): value is AttendanceStatus`
#### BUG-V2-T13使用 `as` 类型断言grades/page.tsx❌ 未修复
- **位置**[grades/page.tsx:43-44](../src/app/(dashboard)/teacher/grades/page.tsx)
- **问题**`type as "exam" | "quiz" | "homework" | "other"` 和 `semester as "1" | "2"` 直接断言
- **改进建议**:使用类型守卫
#### BUG-V2-T14使用 `as` 类型断言grades/analytics/page.tsx❌ 未修复
- **位置**[grades/analytics/page.tsx](../src/app/(dashboard)/teacher/grades/analytics/page.tsx)(多处)
- **问题**:同上模式
- **改进建议**:同上
#### BUG-V2-T15使用 `as` 类型断言diagnostic/page.tsx❌ 未修复
- **位置**[diagnostic/page.tsx:27-28](../src/app/(dashboard)/teacher/diagnostic/page.tsx)
- **问题**`reportType as DiagnosticReportType` 和 `status as DiagnosticReportStatus`
- **改进建议**:使用类型守卫
#### BUG-V2-T16函数返回值未显式标注getParam 工具函数)❌ 未修复
- **位置**:以下 16 个文件中的 `getParam` 函数均未标注返回类型
- attendance/page.tsx:15
- attendance/sheet/page.tsx:9
- attendance/stats/page.tsx:12
- classes/schedule/page.tsx:14
- classes/students/page.tsx:14
- course-plans/page.tsx:10
- diagnostic/page.tsx:10
- elective/page.tsx:10
- exams/all/page.tsx:16
- grades/page.tsx:19
- grades/analytics/page.tsx:28
- grades/entry/page.tsx:12
- grades/stats/page.tsx:15
- homework/assignments/page.tsx:23
- questions/page.tsx:15
- textbooks/page.tsx:13
- **问题**:违反编码规范「函数返回值必须显式标注,特别是 `Promise<T>`」
- **改进建议**`const getParam = (params: SearchParams, key: string): string | undefined => { ... }`
#### BUG-V2-T17页面默认导出函数未标注返回类型 ❌ 未修复
- **位置**:所有 page.tsx 文件的 `export default async function XxxPage()`
- **问题**:未标注 `Promise<JSX.Element>` 或 `Promise<React.ReactNode>`
- **规范依据**:编码规范 5.2 示例 `export default async function UsersPage(): Promise<JSX.Element>`
- **改进建议**:统一补充返回类型标注
---
### 2.4 DRY 违规(重复代码) — 严重度P2
#### BUG-V2-T18`getParam` 工具函数在 16 个文件中重复定义 ❌ 未修复
- **位置**:见 V2-T16 列表
- **问题**:完全相同的工具函数 `getParam` 和类型 `SearchParams` 在 16 个页面文件中复制粘贴
- **改进建议**:提取到 `shared/lib/search-params.ts`
```typescript
export type SearchParams = { [key: string]: string | string[] | undefined }
export function getParam(params: SearchParams, key: string): string | undefined {
const v = params[key]
return Array.isArray(v) ? v[0] : v
}
```
#### BUG-V2-T19`StatsClassSelector` 模式重复 ❌ 未修复
- **位置**
- [attendance/stats/page.tsx:91-119](../src/app/(dashboard)/teacher/attendance/stats/page.tsx)
- [grades/stats/page.tsx:86-138](../src/app/(dashboard)/teacher/grades/stats/page.tsx)
- [grades/analytics/page.tsx:150-258](../src/app/(dashboard)/teacher/grades/analytics/page.tsx)
- **问题**:三处文件都定义了「类筛选按钮组」组件,结构几乎相同(`<a>` 标签 + 条件 className
- **改进建议**:提取为共享组件 `shared/components/ui/filter-chips.tsx`
---
### 2.5 性能问题vercel-react-best-practices — 严重度P1
#### BUG-V2-T20串行数据获取 waterfallattendance/page.tsx❌ 未修复
- **位置**[attendance/page.tsx:32-41](../src/app/(dashboard)/teacher/attendance/page.tsx)
- **问题**`getTeacherClasses()` 与 `getAttendanceRecords()` 串行执行,但二者无依赖关系
- **违反规则**`async-parallel` - 独立操作应使用 `Promise.all()`
- **改进建议**
```typescript
const [classes, result] = await Promise.all([
getTeacherClasses(),
getAttendanceRecords({ ... }),
])
```
#### BUG-V2-T21串行数据获取 waterfallattendance/sheet/page.tsx❌ 未修复
- **位置**[attendance/sheet/page.tsx:24-29](../src/app/(dashboard)/teacher/attendance/sheet/page.tsx)
- **问题**`getTeacherClasses()` 与 `getClassStudentsForAttendance()` 串行,但 students 依赖 defaultClassId来自 searchParams可与 classes 并行
- **改进建议**:使用 `Promise.all` 并行
#### BUG-V2-T22串行数据获取 waterfallattendance/stats/page.tsx❌ 未修复
- **位置**[attendance/stats/page.tsx:28-53](../src/app/(dashboard)/teacher/attendance/stats/page.tsx)
- **问题**`getTeacherClasses()` → `getClassAttendanceStats()` 串行
- **改进建议**:先并行获取 classes再取 targetClassId 后获取 stats当前逻辑合理但可考虑预取
#### BUG-V2-T23串行数据获取 waterfallgrades/page.tsx❌ 未修复
- **位置**[grades/page.tsx:33-45](../src/app/(dashboard)/teacher/grades/page.tsx)
- **问题**`Promise.all([getTeacherClasses, db.query])` 之后串行 `getGradeRecords`,但 `getGradeRecords` 不依赖前两者结果
- **改进建议**:三个查询全部 `Promise.all`
#### BUG-V2-T24串行数据获取 waterfallgrades/entry/page.tsx❌ 未修复
- **位置**[grades/entry/page.tsx:23-34](../src/app/(dashboard)/teacher/grades/entry/page.tsx)
- **问题**`Promise.all([getTeacherClasses, db.query])` 后串行 `getClassStudentsForEntry`,但 students 依赖 defaultClassId来自 searchParams可并行
- **改进建议**`Promise.all` 三个查询
#### BUG-V2-T25串行数据获取 waterfallgrades/stats/page.tsx❌ 未修复
- **位置**[grades/stats/page.tsx:26-54](../src/app/(dashboard)/teacher/grades/stats/page.tsx)
- **问题**`Promise.all([getTeacherClasses, db.query])` → `Promise.all([stats, ranking])` 两段串行
- **改进建议**:合并为单个 `Promise.all`
#### BUG-V2-T26串行数据获取 waterfallclasses/my/[id]/page.tsx❌ 未修复
- **位置**[classes/my/[id]/page.tsx:21-30](../src/app/(dashboard)/teacher/classes/my/[id]/page.tsx)
- **问题**`Promise.all([insights, students, schedule])` 后串行 `getClassStudentSubjectScoresV2`
- **改进建议**:将 `getClassStudentSubjectScoresV2` 加入第一个 `Promise.all`
#### BUG-V2-T27串行数据获取 waterfalldiagnostic/student/[studentId]/page.tsx❌ 未修复
- **位置**[diagnostic/student/[studentId]/page.tsx:30-45](../src/app/(dashboard)/teacher/diagnostic/student/[studentId]/page.tsx)
- **问题**`Promise.all([summary, reports])` 后串行 `getKnowledgePointStats()`
- **改进建议**:合并为单个 `Promise.all`
#### BUG-V2-T28串行数据获取 waterfallexams/[id]/build/page.tsx❌ 未修复
- **位置**[exams/[id]/build/page.tsx:12-26](../src/app/(dashboard)/teacher/exams/[id]/build/page.tsx)
- **问题**`getExamById` → `getQuestions` → `getQuestions(ids)` 三段串行
- **改进建议**:前两个可并行;第三个依赖 exam.questions 的 ID 列表,需串行但可优化
#### BUG-V2-T29Bundle 优化 - barrel importslucide-react❌ 未修复
- **位置**:几乎所有页面文件
- **问题**`import { PlusCircle, BarChart3, ClipboardList } from "lucide-react"` 使用 barrel 文件导入,违反 `bundle-barrel-imports` 规则
- **改进建议**lucide-react 已支持 tree-shaking但可考虑使用 `lucide-react/icons` 直接导入路径
#### BUG-V2-T30缺少 `export const dynamic = "force-dynamic"` 声明 ❌ 未修复
- **位置**
- [exams/all/page.tsx](../src/app/(dashboard)/teacher/exams/all/page.tsx)(使用 Suspense可省略
- [exams/create/page.tsx](../src/app/(dashboard)/teacher/exams/create/page.tsx)
- [exams/[id]/build/page.tsx](../src/app/(dashboard)/teacher/exams/[id]/build/page.tsx)
- [questions/page.tsx](../src/app/(dashboard)/teacher/questions/page.tsx)(使用 Suspense
- [textbooks/page.tsx](../src/app/(dashboard)/teacher/textbooks/page.tsx)(使用 Suspense
- [lesson-plans/page.tsx](../src/app/(dashboard)/teacher/lesson-plans/page.tsx) 🆕
- [lesson-plans/new/page.tsx](../src/app/(dashboard)/teacher/lesson-plans/new/page.tsx) 🆕
- [lesson-plans/[planId]/edit/page.tsx](../src/app/(dashboard)/teacher/lesson-plans/[planId]/edit/page.tsx) 🆕
- **问题**:动态数据页面未声明 `force-dynamic`,可能导致静态生成尝试失败
- **改进建议**:所有含动态数据的页面统一添加 `export const dynamic = "force-dynamic"`
---
### 2.6 Web 界面规范违规web-design-guidelines — 严重度P2
#### BUG-V2-T31`<a>` 标签缺少 focus-visible 焦点样式 ❌ 未修复
- **位置**
- [attendance/stats/page.tsx:106-117](../src/app/(dashboard)/teacher/attendance/stats/page.tsx)
- [grades/analytics/page.tsx:192-253](../src/app/(dashboard)/teacher/grades/analytics/page.tsx)
- [grades/stats/page.tsx:100-135](../src/app/(dashboard)/teacher/grades/stats/page.tsx)
- **问题**:筛选按钮使用 `<a>` 标签但仅有 `hover:bg-accent`,缺少 `focus-visible:ring-*` 或 `focus-visible:outline` 焦点样式
- **违反规则**Focus States - Interactive elements need visible focus
- **改进建议**:添加 `focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2`
#### BUG-V2-T32`<a>` 标签作为筛选按钮语义不当 ❌ 未修复
- **位置**:同 V2-T31
- **问题**:筛选操作使用 `<a>` 标签导航到带 query 的 URL虽然支持 Cmd/Ctrl+click但视觉上是按钮形态应使用 `<button>` 或添加 `role="button"`
- **违反规则**`<button>` for actions, `<a>`/`<Link>` for navigation
- **改进建议**:使用 Next.js `<Link>` 并补充焦点样式,或改为 `<button>` + `useRouter` + `useSearchParams`
#### BUG-V2-T33标题层级缺失exams/[id]/build/page.tsx❌ 未修复
- **位置**[exams/[id]/build/page.tsx:104-118](../src/app/(dashboard)/teacher/exams/[id]/build/page.tsx)
- **问题**:页面无 `<h1>` 标题,直接渲染 `<ExamAssembly>` 组件
- **改进建议**:在页面顶部添加 `<h1>` 标题如「Build Exam」
#### BUG-V2-T34标题层级缺失exams/[id]/proctoring/page.tsx❌ 未修复
- **位置**[exams/[id]/proctoring/page.tsx:50-54](../src/app/(dashboard)/teacher/exams/[id]/proctoring/page.tsx)
- **问题**:同 V2-T33无 `<h1>`
- **改进建议**:同 V2-T33
#### BUG-V2-T35标题层级缺失classes/my/[id]/page.tsx❌ 未修复
- **位置**[classes/my/[id]/page.tsx:65-108](../src/app/(dashboard)/teacher/classes/my/[id]/page.tsx)
- **问题**:页面无 `<h1>`,依赖 `<ClassHeader>` 组件渲染标题,需确认组件内是否有 h1
- **改进建议**:确认 `ClassHeader` 包含 `<h1>`
#### BUG-V2-T36长文本未截断homework/assignments/page.tsx❌ 未修复
- **位置**[homework/assignments/page.tsx:99-101](../src/app/(dashboard)/teacher/homework/assignments/page.tsx)
- **问题**:作业标题 `<Link>{a.title}</Link>` 未限制长度,长标题会破坏表格布局
- **违反规则**Content Handling - Text containers handle long content
- **改进建议**:添加 `line-clamp-2` 或 `truncate max-w-[200px]`
#### BUG-V2-T37长文本未截断homework/submissions/page.tsx❌ 未修复
- **位置**[homework/submissions/page.tsx:58-60](../src/app/(dashboard)/teacher/homework/submissions/page.tsx)
- **问题**:同 V2-T36
- **改进建议**:同 V2-T36
#### BUG-V2-T38长文本未截断homework/assignments/[id]/submissions/page.tsx❌ 未修复
- **位置**[homework/assignments/[id]/submissions/page.tsx:65](../src/app/(dashboard)/teacher/homework/assignments/[id]/submissions/page.tsx)
- **问题**:学生姓名单元格未限制长度
- **改进建议**:添加 `truncate max-w-[160px]`
#### BUG-V2-T39Flex 子元素缺少 `min-w-0` ❌ 未修复
- **位置**
- [homework/assignments/[id]/page.tsx:26-42](../src/app/(dashboard)/teacher/homework/assignments/[id]/page.tsx)
- [classes/my/[id]/page.tsx:86-104](../src/app/(dashboard)/teacher/classes/my/[id]/page.tsx)
- **问题**flex 容器内的文本子元素未设置 `min-w-0`,长内容无法正确截断
- **违反规则**Flex children need `min-w-0` to allow text truncation
- **改进建议**:在 flex 子元素添加 `min-w-0`
#### BUG-V2-T41硬编码日期/数字格式 ❌ 未修复
- **位置**:所有使用 `formatDate` 的文件
- **问题**:需确认 `formatDate` 内部是否使用 `Intl.DateTimeFormat`
- **改进建议**:检查 `shared/lib/utils.ts` 的 `formatDate` 实现
#### BUG-V2-T42数字列未使用 `tabular-nums` ❌ 未修复
- **位置**
- [exams/all/page.tsx:54-60](../src/app/(dashboard)/teacher/exams/all/page.tsx) - 考试计数
- [homework/submissions/page.tsx:69-71](../src/app/(dashboard)/teacher/homework/submissions/page.tsx) - 计数列
- [homework/assignments/[id]/submissions/page.tsx:73](../src/app/(dashboard)/teacher/homework/assignments/[id]/submissions/page.tsx) - 分数
- **问题**:数字列未使用 `font-variant-numeric: tabular-nums`
- **改进建议**:数字单元格添加 `tabular-nums` 类
#### BUG-V2-T43大列表未虚拟化 ❌ 未修复
- **位置**
- [questions/page.tsx:42](../src/app/(dashboard)/teacher/questions/page.tsx) - `pageSize: 200`
- [exams/all/page.tsx](../src/app/(dashboard)/teacher/exams/all/page.tsx) - ExamDataTable
- **问题**:题库页面一次加载 200 条题目,若渲染全部 DOM 节点会卡顿
- **违反规则**Performance - Large lists (>50 items): virtualize
- **改进建议**:使用 `virtua` 或 `content-visibility: auto` 虚拟化长列表
---
### 2.7 组件规范违规 — 严重度P2
#### BUG-V2-T44不必要的包装组件classes/my/page.tsx❌ 未修复
- **位置**[classes/my/page.tsx:6-17](../src/app/(dashboard)/teacher/classes/my/page.tsx)
- **问题**:默认导出 `MyClassesPage` 仅调用 `MyClassesPageImpl`,多此一举
- **改进建议**:直接默认导出 async 函数
#### BUG-V2-T45非导出组件定义在 page.tsx 中 ❌ 未修复
- **位置**
- [attendance/stats/page.tsx:91-119](../src/app/(dashboard)/teacher/attendance/stats/page.tsx) - `StatsClassSelector`
- [grades/analytics/page.tsx:150-258](../src/app/(dashboard)/teacher/grades/analytics/page.tsx) - `AnalyticsFilters`
- [grades/stats/page.tsx:86-138](../src/app/(dashboard)/teacher/grades/stats/page.tsx) - `StatsClassSelector`
- [classes/schedule/page.tsx:45-63](../src/app/(dashboard)/teacher/classes/schedule/page.tsx) - `ScheduleResultsFallback`
- [classes/students/page.tsx:68-81](../src/app/(dashboard)/teacher/classes/students/page.tsx) - `StudentsResultsFallback`
- [exams/all/page.tsx:101-128](../src/app/(dashboard)/teacher/exams/all/page.tsx) - `ExamsResultsFallback`
- [questions/page.tsx:75-88](../src/app/(dashboard)/teacher/questions/page.tsx) - `QuestionBankResultsFallback`
- **问题**:辅助组件定义在 page.tsx 中,违反「其余所有组件使用具名导出」规范,且无法复用
- **改进建议**:提取到 `components/` 目录或 `shared/components/ui/`
#### BUG-V2-T46exams/create/page.tsx 顶部多余空行 ❌ 未修复
- **位置**[exams/create/page.tsx:5](../src/app/(dashboard)/teacher/exams/create/page.tsx)
- **问题**JSX 开始标签前有多余空行
- **改进建议**:删除空行
---
### 2.8 安全与权限违规 — 严重度P0
#### BUG-V2-T47缺少权限校验course-plans/page.tsx❌ 未修复
- **位置**[course-plans/page.tsx](../src/app/(dashboard)/teacher/course-plans/page.tsx)
- **问题**:仅通过 `auth()` 获取 session未调用 `requirePermission()` 或 `getAuthContext()` 进行权限校验
- **改进建议**:使用 `getAuthContext()` 替代 `auth()`,并在 data-access 层做 DataScope 过滤
#### BUG-V2-T48缺少权限校验elective/page.tsx❌ 未修复
- **位置**[elective/page.tsx](../src/app/(dashboard)/teacher/elective/page.tsx)
- **问题**:同 V2-T47
- **改进建议**:同 V2-T47
#### BUG-V2-T49缺少权限校验dashboard/page.tsx❌ 未修复
- **位置**[dashboard/page.tsx](../src/app/(dashboard)/teacher/dashboard/page.tsx)
- **问题**依赖路由层代理proxy.ts做角色路由但页面本身未做二次权限校验
- **改进建议**:添加 `getAuthContext()` 确认教师身份
#### BUG-V2-T50权限校验方式不一致 ❌ 未修复
- **位置**
- [exams/[id]/proctoring/page.tsx:21](../src/app/(dashboard)/teacher/exams/[id]/proctoring/page.tsx) - 使用 `requirePermission(Permissions.EXAM_PROCTOR)`
- [diagnostic/class/[classId]/page.tsx:15-23](../src/app/(dashboard)/teacher/diagnostic/class/[classId]/page.tsx) - 使用 `getAuthContext()` + DataScope 校验
- [grades/page.tsx:26](../src/app/(dashboard)/teacher/grades/page.tsx) - 使用 `getAuthContext()`
- **问题**:权限校验方式不统一
- **改进建议**:统一权限校验策略,页面入口用 `getAuthContext()`,写操作用 `requirePermission()`
#### BUG-V2-T50alesson-plans/page.tsx 通过 actions 调用读取操作 🆕 新增
- **位置**[lesson-plans/page.tsx:1-2](../src/app/(dashboard)/teacher/lesson-plans/page.tsx)
- **问题**:页面读取数据使用 `getLessonPlansAction` 和 `getSubjectsAction`Server Actions而非 data-access 函数。Server Actions 应用于写操作(含权限校验 + revalidate读取操作应直接用 data-access
- **现状**
```typescript
import { getLessonPlansAction } from "@/modules/lesson-preparation/actions";
import { getSubjectsAction } from "@/modules/exams/actions";
```
- **改进建议**:改为从 data-access 导入:
```typescript
import { getLessonPlans } from "@/modules/lesson-preparation/data-access";
import { getSubjectOptions } from "@/modules/school/data-access";
```
#### BUG-V2-T50blesson-plans/[planId]/edit/page.tsx 通过 actions 调用读取操作 🆕 新增
- **位置**[lesson-plans/[planId]/edit/page.tsx:2](../src/app/(dashboard)/teacher/lesson-plans/[planId]/edit/page.tsx)
- **问题**:同 V2-T50a使用 `getLessonPlanByIdAction` 读取单条数据
- **改进建议**:改为从 data-access 导入 `getLessonPlanById`
---
### 2.9 加载态缺失 — 严重度P3
#### BUG-V2-T51缺少 loading.tsx 的目录 ❌ 未修复
- **位置**
- `attendance/`(含 sheet/、stats/
- `course-plans/`(含 [id]/
- `diagnostic/`(含 class/、student/
- `elective/`
- `exams/[id]/`(含 build/、proctoring/
- `grades/`(含 analytics/、entry/、stats/
- `homework/`(含 assignments/、submissions/
- `schedule-changes/`
- `lesson-plans/`(含 new/、[planId]/edit/)🆕
- **问题**:以上目录无 `loading.tsx`,导航时无骨架屏反馈
- **改进建议**:为每个动态页面目录添加 `loading.tsx`
#### BUG-V2-T52exams/grading/loading.tsx 实际无用 ❌ 未修复
- **位置**[exams/grading/loading.tsx](../src/app/(dashboard)/teacher/exams/grading/loading.tsx)
- **问题**`exams/grading/page.tsx` 仅做 `redirect()`loading.tsx 永远不会显示
- **改进建议**:删除该 loading.tsx
---
### 2.10 逻辑与代码质量问题 — 严重度P2
#### BUG-V2-T53homework/assignments/page.tsx 条件取数逻辑反直觉 ❌ 未修复
- **位置**[homework/assignments/page.tsx:33-36](../src/app/(dashboard)/teacher/homework/assignments/page.tsx)
- **问题**`classId && classId !== "all" ? getTeacherClasses() : Promise.resolve([])` 仅在有 classId 时才获取班级列表,逻辑反直觉
- **改进建议**:始终获取 classes或添加注释说明
#### BUG-V2-T54exams/[id]/build/page.tsx `normalizeStructure` 函数过长 ❌ 未修复
- **位置**[exams/[id]/build/page.tsx:52-91](../src/app/(dashboard)/teacher/exams/[id]/build/page.tsx)
- **问题**40 行的 `normalizeStructure` 函数定义在组件内部,包含嵌套递归逻辑
- **改进建议**:提取到 `modules/exams/utils/normalize-structure.ts`,并添加单元测试
#### BUG-V2-T55exams/[id]/build/page.tsx 使用 `satisfies` 但混合 `as` ❌ 未修复
- **位置**[exams/[id]/build/page.tsx:74, 84, 86](../src/app/(dashboard)/teacher/exams/[id]/build/page.tsx)
- **问题**:同时使用 `satisfies ExamNode`(好)和 `as ExamNode[]`(违规),类型处理不一致
- **改进建议**:移除 `as ExamNode[]`,改用类型守卫或 `Array.from()` 配合 filter
#### BUG-V2-T56grades/analytics/page.tsx 文件过长 ❌ 未修复
- **位置**[grades/analytics/page.tsx](../src/app/(dashboard)/teacher/grades/analytics/page.tsx) - 259 行
- **问题**:单文件 259 行,包含页面 + `AnalyticsFilters` 组件
- **改进建议**:将 `AnalyticsFilters` 提取到 `modules/grades/components/analytics-filters.tsx`
#### BUG-V2-T57exams/all/page.tsx 缺少 `export const dynamic` ⚠️ 部分修复
- **位置**[exams/all/page.tsx](../src/app/(dashboard)/teacher/exams/all/page.tsx)
- **问题**:使用 Suspense 但未声明 `force-dynamic`
- **说明**Next.js 16 中使用 Suspense 边界的动态页面可省略 `force-dynamic`,但为一致性建议添加
- **改进建议**:添加 `export const dynamic = "force-dynamic"` 以保持一致性
---
### 2.11 可访问性问题 — 严重度P2
#### BUG-V2-T58图标按钮缺少 aria-label ❌ 未修复
- **位置**
- [textbooks/[id]/page.tsx:33-36](../src/app/(dashboard)/teacher/textbooks/[id]/page.tsx) - 返回按钮
- **问题**`textbooks/[id]/page.tsx` 的返回按钮仅含图标,无 `aria-label`
- **违反规则**Accessibility - Icon-only buttons need `aria-label`
- **改进建议**:添加 `aria-label="Back to textbooks"`
#### BUG-V2-T59装饰性图标未标记 aria-hidden ❌ 未修复
- **位置**:几乎所有页面中的 lucide 图标
- **问题**:如 `<BarChart3 className="mr-2 h-4 w-4" />` 等装饰性图标未添加 `aria-hidden="true"`
- **违反规则**Accessibility - Decorative icons need `aria-hidden="true"`
- **改进建议**:装饰性图标添加 `aria-hidden="true"`
#### BUG-V2-T60缺少 skip link ❌ 未修复
- **位置**:所有页面
- **问题**:页面无「跳到主内容」的 skip link
- **违反规则**Accessibility - include skip link for main content
- **改进建议**:在 dashboard layout 添加 skip link应在 layout 层处理)
---
### 2.12 其他问题 — 严重度P3
#### BUG-V2-T61homework/assignments/[id]/page.tsx 使用 h1 但其他页面用 h2 ❌ 未修复
- **位置**
- [homework/assignments/[id]/page.tsx:36](../src/app/(dashboard)/teacher/homework/assignments/[id]/page.tsx) - `<h1>`
- [attendance/page.tsx:47](../src/app/(dashboard)/teacher/attendance/page.tsx) - `<h2>`
- [grades/page.tsx:54](../src/app/(dashboard)/teacher/grades/page.tsx) - `<h2>`
- **问题**:页面主标题层级不统一
- **改进建议**:统一使用 h1 作为页面主标题
#### BUG-V2-T62textbooks/page.tsx 使用 h1其他页面用 h2 ❌ 未修复
- **位置**
- [textbooks/page.tsx:57](../src/app/(dashboard)/teacher/textbooks/page.tsx) - `<h1>`
- [textbooks/[id]/page.tsx:45](../src/app/(dashboard)/teacher/textbooks/[id]/page.tsx) - `<h1>`
- **问题**:同 V2-T61
- **改进建议**:统一标题层级策略
#### BUG-V2-T63exams/create/page.tsx 缺少页面标题 ❌ 未修复
- **位置**[exams/create/page.tsx:3-9](../src/app/(dashboard)/teacher/exams/create/page.tsx)
- **问题**:页面无任何标题,直接渲染表单
- **改进建议**:添加 `<h1>Create Exam</h1>`
#### BUG-V2-T64loading.tsx 文件命名风格不一致 ❌ 未修复
- **位置**
- [textbooks/loading.tsx](../src/app/(dashboard)/teacher/textbooks/loading.tsx) - 使用 Card 组件
- [classes/my/loading.tsx](../src/app/(dashboard)/teacher/classes/my/loading.tsx) - 使用纯 div
- **问题**:骨架屏风格不统一
- **改进建议**:统一骨架屏风格
#### BUG-V2-T65lesson-plans/page.tsx 使用非标准 CSS 类 🆕 新增
- **位置**[lesson-plans/page.tsx:21, 24](../src/app/(dashboard)/teacher/lesson-plans/page.tsx)
- **问题**:使用 `font-headline-lg text-headline-lg` 类名,这些类名不在标准 Tailwind 配置中,需确认是否在 globals.css 中定义
- **改进建议**:确认设计令牌定义,或改用标准 Tailwind 类名 `text-2xl font-bold tracking-tight`
#### BUG-V2-T66lesson-plans/page.tsx 缺少页面描述 ❌ 未修复
- **位置**[lesson-plans/page.tsx:18-31](../src/app/(dashboard)/teacher/lesson-plans/page.tsx)
- **问题**:页面仅有 `<h1>我的课案</h1>`,缺少描述性 `<p>` 标签,与其他页面风格不一致
- **改进建议**:添加描述段落,如 `<p className="text-muted-foreground">管理您的课案和教学准备</p>`
#### BUG-V2-T67lesson-plans/new/page.tsx 缺少返回链接 🆕 新增
- **位置**[lesson-plans/new/page.tsx](../src/app/(dashboard)/teacher/lesson-plans/new/page.tsx)
- **问题**:页面无返回到 `/teacher/lesson-plans` 的链接,用户无法导航回去
- **改进建议**:添加返回按钮
#### BUG-V2-T68lesson-plans/[planId]/edit/page.tsx 缺少页面标题 ❌ 未修复
- **位置**[lesson-plans/[planId]/edit/page.tsx](../src/app/(dashboard)/teacher/lesson-plans/[planId]/edit/page.tsx)
- **问题**:页面无 `<h1>` 标题,直接渲染 `<LessonPlanEditor>`
- **改进建议**:添加页面标题
#### BUG-V2-T69lesson-plans 系列文件中英文混用 🆕 新增
- **位置**
- [lesson-plans/page.tsx:21, 24](../src/app/(dashboard)/teacher/lesson-plans/page.tsx) - "我的课案"、"新建课案"
- [lesson-plans/new/page.tsx:6](../src/app/(dashboard)/teacher/lesson-plans/new/page.tsx) - "新建课案"
- **问题**teacher 模块其他页面均使用英文标题(如 "Attendance"、"Grades"),但 lesson-plans 使用中文,风格不一致
- **改进建议**:统一为英文 "My Lesson Plans" / "New Lesson Plan",或在 i18n 配置中统一管理
---
## 三、v1 已修复问题确认
### 3.1 已确认修复
| v1 BUG ID | 问题摘要 | 修复确认 |
|-----------|----------|----------|
| T29部分 | schedule-changes/page.tsx 通过 actions 调用 | ✅ 已改为从 `@/modules/scheduling/data-access` 导入 |
### 3.2 修复说明
**schedule-changes/page.tsx** 的修复:
- v1 状态:`import { getAdminClassesForScheduling, getScheduleChanges, getTeachersForScheduling } from "@/modules/scheduling/actions"`
- v2 状态:`import { getAdminClassesForScheduling, getScheduleChanges, getTeachersForScheduling } from "@/modules/scheduling/data-access"`
- 评价:✅ 正确修复,读取操作应从 data-access 导入,而非 actions
---
## 四、改进优先级汇总v2
### P0 - 立即修复(架构与安全)
| BUG ID | 问题 | 影响 | v1 状态 |
|--------|------|------|----------|
| V2-T01 | dashboard/page.tsx 直接访问 DB | 破坏三层架构 | ❌ 未修复 |
| V2-T02 | grades/page.tsx 直接访问 DB | 破坏三层架构 | ❌ 未修复 |
| V2-T03 | grades/analytics/page.tsx 直接访问 DB | 破坏三层架构 | ❌ 未修复 |
| V2-T04 | grades/entry/page.tsx 直接访问 DB | 破坏三层架构 | ❌ 未修复 |
| V2-T05 | grades/stats/page.tsx 直接访问 DB | 破坏三层架构 | ❌ 未修复 |
| V2-T06 | 认证方式不一致 | 数据范围过滤缺失 | ❌ 未修复 |
| V2-T47 | course-plans/page.tsx 缺权限校验 | 越权访问风险 | ❌ 未修复 |
| V2-T48 | elective/page.tsx 缺权限校验 | 越权访问风险 | ❌ 未修复 |
| V2-T49 | dashboard/page.tsx 缺权限校验 | 越权访问风险 | ❌ 未修复 |
| V2-T50 | 权限校验方式不一致 | 安全隐患 | ❌ 未修复 |
| V2-T50a | lesson-plans/page.tsx 通过 actions 读取 🆕 | 架构违规 | 🆕 新增 |
| V2-T50b | lesson-plans/[planId]/edit 通过 actions 读取 🆕 | 架构违规 | 🆕 新增 |
### P1 - 高优先级TypeScript 与性能)
| BUG ID | 问题 | v1 状态 |
|--------|------|----------|
| V2-T11~T15 | 使用 `as` 类型断言5 处) | ❌ 未修复 |
| V2-T16~T17 | 函数返回值未标注 | ❌ 未修复 |
| V2-T20~T28 | 串行数据获取 waterfall9 处) | ❌ 未修复 |
| V2-T43 | 大列表未虚拟化 | ❌ 未修复 |
### P2 - 中优先级(规范与可访问性)
| BUG ID | 问题 | v1 状态 |
|--------|------|----------|
| V2-T07~T10a | Prettier 分号违规 | ❌ 未修复 |
| V2-T18~T19 | DRY 违规 | ❌ 未修复 |
| V2-T31~T32 | 筛选按钮焦点样式/语义 | ❌ 未修复 |
| V2-T36~T39 | 长文本未截断 | ❌ 未修复 |
| V2-T42 | 数字列未用 tabular-nums | ❌ 未修复 |
| V2-T58~T60 | 可访问性缺失 | ❌ 未修复 |
| V2-T65~T69 | lesson-plans 系列问题 🆕 | 🆕 新增 |
### P3 - 低优先级(代码质量)
| BUG ID | 问题 | v1 状态 |
|--------|------|----------|
| V2-T44~T46 | 组件定义问题 | ❌ 未修复 |
| V2-T51~T52 | loading.tsx 缺失/冗余 | ❌ 未修复 |
| V2-T53~T57 | 逻辑与长度问题 | ❌ 未修复 |
| V2-T61~T64 | 标题层级与风格 | ❌ 未修复 |
---
## 五、v1 → v2 改进对比
### 5.1 改进情况
| 维度 | v1 问题数 | v2 已修复 | v2 新增 | v2 总计 | 净变化 |
|------|-----------|-----------|---------|---------|--------|
| 架构分层 | 6 | 0 | 2 | 8 | +2 |
| Prettier | 4 | 0 | 1 | 5 | +1 |
| TypeScript | 7 | 0 | 0 | 7 | 0 |
| DRY | 2 | 0 | 0 | 2 | 0 |
| 性能 | 11 | 0 | 0 | 11 | 0 |
| Web 规范 | 13 | 0 | 0 | 13 | 0 |
| 组件规范 | 3 | 0 | 0 | 3 | 0 |
| 安全权限 | 4 | 0 | 2 | 6 | +2 |
| 加载态 | 2 | 0 | 0 | 2 | 0 |
| 代码质量 | 5 | 0 | 0 | 5 | 0 |
| 可访问性 | 3 | 0 | 0 | 3 | 0 |
| 其他 | 4 | 0 | 5 | 9 | +5 |
| **合计** | **64** | **1** | **10** | **74** | **+10** |
### 5.2 关键观察
1. **修复进度缓慢**v1 的 64 个问题中仅 1 个确认修复schedule-changes 的 actions→data-access修复率 1.6%
2. **新增问题**lesson-plans 模块新增 10 个问题,主要涉及:
- 架构违规:通过 Server Actions 读取数据(应使用 data-access
- Prettier 违规:使用分号
- 风格不一致:中英文混用、非标准 CSS 类
- 缺少基础元素:标题、返回链接、页面描述
3. **P0 问题全部未修复**5 处 app 层直接访问 DB、3 处权限校验缺失、认证方式不一致等关键问题均未处理
4. **已有可复用函数未利用**
- `modules/users/data-access.ts` 已有 `getUserBasicInfo(userId)` 可替代 dashboard/page.tsx 的直接 DB 访问
- `modules/school/data-access.ts` 已有 `getSubjectOptions()` 可替代 grades 系列页面的直接 DB 访问
- 但这些现成函数均未被采用
---
## 六、推荐改进方案v2 更新)
### 6.1 立即修复 P0 问题(架构与安全)
#### 6.1.1 修复 app 层直接访问 DBV2-T01~T05
**dashboard/page.tsx** 修复:
```typescript
// 修改前
import { db } from "@/shared/db"
import { users } from "@/shared/db/schema"
import { eq } from "drizzle-orm"
// ...
db.query.users.findFirst({ where: eq(users.id, teacherId), columns: { name: true } })
// 修改后
import { getUserBasicInfo } from "@/modules/users/data-access"
// ...
const teacherProfile = await getUserBasicInfo(teacherId)
```
**grades/page.tsx、grades/analytics/page.tsx、grades/entry/page.tsx、grades/stats/page.tsx** 修复:
```typescript
// 修改前
import { db } from "@/shared/db"
import { subjects } from "@/shared/db/schema"
import { asc } from "drizzle-orm"
// ...
db.query.subjects.findMany({ orderBy: [asc(subjects.order), asc(subjects.name)] })
// 修改后
import { getSubjectOptions } from "@/modules/school/data-access"
// ...
const allSubjects = await getSubjectOptions()
```
#### 6.1.2 修复权限校验V2-T06, T47~T50
**course-plans/page.tsx、elective/page.tsx** 修复:
```typescript
// 修改前
import { auth } from "@/auth"
const session = await auth()
const teacherId = String(session?.user?.id ?? "")
// 修改后
import { getAuthContext } from "@/shared/lib/auth-guard"
const ctx = await getAuthContext()
const teacherId = ctx.userId
```
#### 6.1.3 修复 lesson-plans 架构违规V2-T50a, T50b
**lesson-plans/page.tsx** 修复:
```typescript
// 修改前
import { getLessonPlansAction } from "@/modules/lesson-preparation/actions";
import { getSubjectsAction } from "@/modules/exams/actions";
// 修改后
import { getLessonPlans } from "@/modules/lesson-preparation/data-access";
import { getSubjectOptions } from "@/modules/school/data-access";
```
### 6.2 提取共享工具(解决 V2-T16, T18
新建 `src/shared/lib/search-params.ts`
```typescript
export type SearchParams = { [key: string]: string | string[] | undefined }
export function getParam(params: SearchParams, key: string): string | undefined {
const v = params[key]
return Array.isArray(v) ? v[0] : v
}
```
所有页面统一 `import { getParam, type SearchParams } from "@/shared/lib/search-params"`。
### 6.3 提取共享筛选组件(解决 V2-T19, T31, T32
新建 `src/shared/components/ui/filter-chips.tsx`
```tsx
import Link from "next/link"
import { cn } from "@/shared/lib/utils"
interface FilterChip {
id: string
label: string
href: string
active: boolean
}
export function FilterChips({ chips }: { chips: FilterChip[] }) {
return (
<div className="flex flex-wrap gap-2">
{chips.map((c) => (
<Link
key={c.id}
href={c.href}
className={cn(
"rounded-md border px-3 py-1.5 text-sm transition-colors",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
c.active
? "border-primary bg-primary text-primary-foreground"
: "bg-card hover:bg-accent"
)}
>
{c.label}
</Link>
))}
</div>
)
}
```
### 6.4 并行数据获取优化(解决 V2-T20~T28
将串行 `await` 改为 `Promise.all`
```typescript
// 优化前
const classes = await getTeacherClasses()
const records = await getGradeRecords({ ... })
// 优化后
const [classes, records] = await Promise.all([
getTeacherClasses(),
getGradeRecords({ ... }),
])
```
### 6.5 统一 lesson-plans 风格(解决 V2-T65~T69
```typescript
// lesson-plans/page.tsx 修复
export default async function LessonPlansPage() {
const [items, subjects] = await Promise.all([
getLessonPlans({}),
getSubjectOptions(),
])
return (
<div className="p-6 space-y-4">
<div className="flex justify-between items-center">
<div>
<h1 className="text-2xl font-bold tracking-tight">My Lesson Plans</h1>
<p className="text-muted-foreground">Manage your lesson preparation and teaching plans.</p>
</div>
<Button asChild>
<Link href="/teacher/lesson-plans/new">
<Plus className="h-4 w-4 mr-2" />
New Lesson Plan
</Link>
</Button>
</div>
<LessonPlanList initialItems={items} subjects={subjects} />
</div>
)
}
```
---
## 七、架构图同步建议
本次核查未修改源码,无需同步架构图。但建议在后续修复时:
1. 若新增 `shared/lib/search-params.ts`,需在 005_architecture_data.json 的 `shared.lib.exports` 中添加
2. 若新增 `shared/components/ui/filter-chips.tsx`,需在 005 的 `shared.components.exports` 中添加
3. `lesson-plans` 模块需在 005 的 `modules` 中新增节点,记录其 `data-access` 和 `actions` 导出
4. `modules/school/data-access.ts` 的 `getSubjectOptions` 已存在,确认 005 中已记录
5. `modules/users/data-access.ts` 的 `getUserBasicInfo` 已存在,确认 005 中已记录
---
## 八、总结
本次 v2 核查覆盖 `src/app/(dashboard)/teacher/` 下全部 **48 个前端文件**37 个 page.tsx + 8 个 loading.tsx + 3 个新增 lesson-plans 页面),共发现 **74 个问题**,分布如下:
| 严重度 | 数量 | 类别 | v1 对比 |
|--------|------|------|---------|
| P0 | 12 | 架构违规、权限缺失 | +3含 2 个新增) |
| P1 | 16 | TypeScript、性能 | 0 |
| P2 | 23 | 规范、可访问性 | +5含 5 个新增) |
| P3 | 23 | 代码质量 | +2 |
### 核心问题v2 更新)
1. **架构层违规加剧**5 处 app 层直接访问 DB 未修复,新增 2 处 lesson-plans 通过 actions 读取数据
2. **权限校验不一致**3 处页面无校验未修复,新增 lesson-plans 模块未做权限校验
3. **性能 waterfall 普遍**9 处串行数据获取未修复
4. **DRY 违规突出**`getParam` 函数在 16 个文件中重复
5. **可访问性缺失**焦点样式、aria-label、skip link 普遍缺失
6. **新增模块质量待提升**lesson-plans 模块存在架构违规、风格不一致、基础元素缺失等问题
### 修复建议优先级
1. **第一优先级**:修复 5 处 app 层直接访问 DB已有 `getUserBasicInfo` 和 `getSubjectOptions` 可直接复用)
2. **第二优先级**:统一权限校验为 `getAuthContext()`
3. **第三优先级**:修复 lesson-plans 模块的架构违规actions → data-access
4. **第四优先级**:提取共享工具 `getParam` 和 `FilterChips` 组件
5. **第五优先级**:并行化数据获取,优化性能
建议按 P0 → P1 → P2 → P3 顺序修复,优先解决架构与安全问题。特别是 app 层直接访问 DB 的问题,已有现成的 data-access 函数可用,修复成本极低。