feat: 新增备课模块并修复全模块 P0/P1/P2 缺陷
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

主要变更:

- 新增 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)
This commit is contained in:
SpecialX
2026-06-22 01:06:16 +08:00
parent d8962aba96
commit 978d9a8309
327 changed files with 34070 additions and 5642 deletions

883
bugs/teacher_bug_v2.md Normal file
View File

@@ -0,0 +1,883 @@
# `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 函数可用,修复成本极低。