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

44 KiB
Raw Blame History

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-guidelinesWeb 界面规范审查) 对比基准:v1 报告


一、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 32 页面 课案列表
lesson-plans/new/page.tsx 10 页面 新建课案
lesson-plans/[planId]/edit/page.tsx 36 页面 编辑课案

二、未修复问题清单(按严重度排序)

2.1 架构分层违规 — 严重度P0

BUG-V2-T01app 层直接访问数据库dashboard/page.tsx 未修复

  • 位置dashboard/page.tsx:4-6, 18-21
  • 问题:页面直接 import { db } from "@/shared/db" 并调用 db.query.users.findFirst(),违反项目规则「app/ 只能调用 modules/ 的 Server Actions 和 data-access不直接访问 DB」
  • 现状
    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可直接复用
    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
  • 问题:直接 db.query.subjects.findMany() 查询科目列表
  • 改进建议modules/school/data-access.ts 已有 getSubjectOptions() 函数(返回 id/name/code/order可直接复用
    import { getSubjectOptions } from "@/modules/school/data-access"
    const allSubjects = await getSubjectOptions()
    

BUG-V2-T03app 层直接访问数据库grades/analytics/page.tsx 未修复

BUG-V2-T04app 层直接访问数据库grades/entry/page.tsx 未修复

BUG-V2-T05app 层直接访问数据库grades/stats/page.tsx 未修复

BUG-V2-T06认证上下文获取方式不一致 未修复

  • 位置
  • 问题:使用 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
  • 问题import { TextbookCard } from "..."; 等多处使用分号
  • 改进建议:运行 npx prettier --write 统一格式

BUG-V2-T08textbooks/[id]/page.tsx 使用分号 未修复

BUG-V2-T09textbooks/loading.tsx 使用分号 未修复

BUG-V2-T10textbooks/[id]/loading.tsx 使用分号 未修复

BUG-V2-T10alesson-plans 系列文件使用分号 🆕 新增


2.3 TypeScript 规范违规 — 严重度P1

BUG-V2-T11使用 as 类型断言exams/[id]/build/page.tsx 未修复

  • 位置exams/[id]/build/page.tsx:32-34
  • 问题:使用 as 断言转换类型,违反编码规范「禁止 as 断言(除非从 unknown 转换)」
  • 现状
    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
  • 问题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
  • 问题type as "exam" | "quiz" | "homework" | "other"semester as "1" | "2" 直接断言
  • 改进建议:使用类型守卫

BUG-V2-T14使用 as 类型断言grades/analytics/page.tsx 未修复

BUG-V2-T15使用 as 类型断言diagnostic/page.tsx 未修复

  • 位置diagnostic/page.tsx:27-28
  • 问题reportType as DiagnosticReportTypestatus 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-T18getParam 工具函数在 16 个文件中重复定义 未修复

  • 位置:见 V2-T16 列表
  • 问题:完全相同的工具函数 getParam 和类型 SearchParams 在 16 个页面文件中复制粘贴
  • 改进建议:提取到 shared/lib/search-params.ts
    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-T19StatsClassSelector 模式重复 未修复


2.5 性能问题vercel-react-best-practices — 严重度P1

BUG-V2-T20串行数据获取 waterfallattendance/page.tsx 未修复

  • 位置attendance/page.tsx:32-41
  • 问题getTeacherClasses()getAttendanceRecords() 串行执行,但二者无依赖关系
  • 违反规则async-parallel - 独立操作应使用 Promise.all()
  • 改进建议
    const [classes, result] = await Promise.all([
      getTeacherClasses(),
      getAttendanceRecords({ ... }),
    ])
    

BUG-V2-T21串行数据获取 waterfallattendance/sheet/page.tsx 未修复

  • 位置attendance/sheet/page.tsx:24-29
  • 问题getTeacherClasses()getClassStudentsForAttendance() 串行,但 students 依赖 defaultClassId来自 searchParams可与 classes 并行
  • 改进建议:使用 Promise.all 并行

BUG-V2-T22串行数据获取 waterfallattendance/stats/page.tsx 未修复

  • 位置attendance/stats/page.tsx:28-53
  • 问题getTeacherClasses()getClassAttendanceStats() 串行
  • 改进建议:先并行获取 classes再取 targetClassId 后获取 stats当前逻辑合理但可考虑预取

BUG-V2-T23串行数据获取 waterfallgrades/page.tsx 未修复

  • 位置grades/page.tsx:33-45
  • 问题Promise.all([getTeacherClasses, db.query]) 之后串行 getGradeRecords,但 getGradeRecords 不依赖前两者结果
  • 改进建议:三个查询全部 Promise.all

BUG-V2-T24串行数据获取 waterfallgrades/entry/page.tsx 未修复

  • 位置grades/entry/page.tsx:23-34
  • 问题Promise.all([getTeacherClasses, db.query]) 后串行 getClassStudentsForEntry,但 students 依赖 defaultClassId来自 searchParams可并行
  • 改进建议Promise.all 三个查询

BUG-V2-T25串行数据获取 waterfallgrades/stats/page.tsx 未修复

  • 位置grades/stats/page.tsx:26-54
  • 问题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
  • 问题Promise.all([insights, students, schedule]) 后串行 getClassStudentSubjectScoresV2
  • 改进建议:将 getClassStudentSubjectScoresV2 加入第一个 Promise.all

BUG-V2-T27串行数据获取 waterfalldiagnostic/student/[studentId]/page.tsx 未修复

BUG-V2-T28串行数据获取 waterfallexams/[id]/build/page.tsx 未修复

  • 位置exams/[id]/build/page.tsx:12-26
  • 问题getExamByIdgetQuestionsgetQuestions(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" 声明 未修复


2.6 Web 界面规范违规web-design-guidelines — 严重度P2

BUG-V2-T31<a> 标签缺少 focus-visible 焦点样式 未修复

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
  • 问题:页面无 <h1> 标题,直接渲染 <ExamAssembly> 组件
  • 改进建议:在页面顶部添加 <h1> 标题如「Build Exam」

BUG-V2-T34标题层级缺失exams/[id]/proctoring/page.tsx 未修复

BUG-V2-T35标题层级缺失classes/my/[id]/page.tsx 未修复

  • 位置classes/my/[id]/page.tsx:65-108
  • 问题:页面无 <h1>,依赖 <ClassHeader> 组件渲染标题,需确认组件内是否有 h1
  • 改进建议:确认 ClassHeader 包含 <h1>

BUG-V2-T36长文本未截断homework/assignments/page.tsx 未修复

  • 位置homework/assignments/page.tsx:99-101
  • 问题:作业标题 <Link>{a.title}</Link> 未限制长度,长标题会破坏表格布局
  • 违反规则Content Handling - Text containers handle long content
  • 改进建议:添加 line-clamp-2truncate max-w-[200px]

BUG-V2-T37长文本未截断homework/submissions/page.tsx 未修复

BUG-V2-T38长文本未截断homework/assignments/[id]/submissions/page.tsx 未修复

BUG-V2-T39Flex 子元素缺少 min-w-0 未修复

BUG-V2-T41硬编码日期/数字格式 未修复

  • 位置:所有使用 formatDate 的文件
  • 问题:需确认 formatDate 内部是否使用 Intl.DateTimeFormat
  • 改进建议:检查 shared/lib/utils.tsformatDate 实现

BUG-V2-T42数字列未使用 tabular-nums 未修复

BUG-V2-T43大列表未虚拟化 未修复

  • 位置
  • 问题:题库页面一次加载 200 条题目,若渲染全部 DOM 节点会卡顿
  • 违反规则Performance - Large lists (>50 items): virtualize
  • 改进建议:使用 virtuacontent-visibility: auto 虚拟化长列表

2.7 组件规范违规 — 严重度P2

BUG-V2-T44不必要的包装组件classes/my/page.tsx 未修复

  • 位置classes/my/page.tsx:6-17
  • 问题:默认导出 MyClassesPage 仅调用 MyClassesPageImpl,多此一举
  • 改进建议:直接默认导出 async 函数

BUG-V2-T45非导出组件定义在 page.tsx 中 未修复

BUG-V2-T46exams/create/page.tsx 顶部多余空行 未修复


2.8 安全与权限违规 — 严重度P0

BUG-V2-T47缺少权限校验course-plans/page.tsx 未修复

  • 位置course-plans/page.tsx
  • 问题:仅通过 auth() 获取 session未调用 requirePermission()getAuthContext() 进行权限校验
  • 改进建议:使用 getAuthContext() 替代 auth(),并在 data-access 层做 DataScope 过滤

BUG-V2-T48缺少权限校验elective/page.tsx 未修复

BUG-V2-T49缺少权限校验dashboard/page.tsx 未修复

  • 位置dashboard/page.tsx
  • 问题依赖路由层代理proxy.ts做角色路由但页面本身未做二次权限校验
  • 改进建议:添加 getAuthContext() 确认教师身份

BUG-V2-T50权限校验方式不一致 未修复

BUG-V2-T50alesson-plans/page.tsx 通过 actions 调用读取操作 🆕 新增

  • 位置lesson-plans/page.tsx:1-2
  • 问题:页面读取数据使用 getLessonPlansActiongetSubjectsActionServer Actions而非 data-access 函数。Server Actions 应用于写操作(含权限校验 + revalidate读取操作应直接用 data-access
  • 现状
    import { getLessonPlansAction } from "@/modules/lesson-preparation/actions";
    import { getSubjectsAction } from "@/modules/exams/actions";
    
  • 改进建议:改为从 data-access 导入:
    import { getLessonPlans } from "@/modules/lesson-preparation/data-access";
    import { getSubjectOptions } from "@/modules/school/data-access";
    

BUG-V2-T50blesson-plans/[planId]/edit/page.tsx 通过 actions 调用读取操作 🆕 新增


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
  • 问题exams/grading/page.tsx 仅做 redirect()loading.tsx 永远不会显示
  • 改进建议:删除该 loading.tsx

2.10 逻辑与代码质量问题 — 严重度P2

BUG-V2-T53homework/assignments/page.tsx 条件取数逻辑反直觉 未修复

  • 位置homework/assignments/page.tsx:33-36
  • 问题classId && classId !== "all" ? getTeacherClasses() : Promise.resolve([]) 仅在有 classId 时才获取班级列表,逻辑反直觉
  • 改进建议:始终获取 classes或添加注释说明

BUG-V2-T54exams/[id]/build/page.tsx normalizeStructure 函数过长 未修复

  • 位置exams/[id]/build/page.tsx:52-91
  • 问题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
  • 问题:同时使用 satisfies ExamNode(好)和 as ExamNode[](违规),类型处理不一致
  • 改进建议:移除 as ExamNode[],改用类型守卫或 Array.from() 配合 filter

BUG-V2-T56grades/analytics/page.tsx 文件过长 未修复

  • 位置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
  • 问题:使用 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 的返回按钮仅含图标,无 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"
  • 位置:所有页面
  • 问题:页面无「跳到主内容」的 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 未修复

BUG-V2-T62textbooks/page.tsx 使用 h1其他页面用 h2 未修复

BUG-V2-T63exams/create/page.tsx 缺少页面标题 未修复

  • 位置exams/create/page.tsx:3-9
  • 问题:页面无任何标题,直接渲染表单
  • 改进建议:添加 <h1>Create Exam</h1>

BUG-V2-T64loading.tsx 文件命名风格不一致 未修复

BUG-V2-T65lesson-plans/page.tsx 使用非标准 CSS 类 🆕 新增

  • 位置lesson-plans/page.tsx:21, 24
  • 问题:使用 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
  • 问题:页面仅有 <h1>我的课案</h1>,缺少描述性 <p> 标签,与其他页面风格不一致
  • 改进建议:添加描述段落,如 <p className="text-muted-foreground">管理您的课案和教学准备</p>

BUG-V2-T67lesson-plans/new/page.tsx 缺少返回链接 🆕 新增

  • 位置lesson-plans/new/page.tsx
  • 问题:页面无返回到 /teacher/lesson-plans 的链接,用户无法导航回去
  • 改进建议:添加返回按钮

BUG-V2-T68lesson-plans/[planId]/edit/page.tsx 缺少页面标题 未修复

BUG-V2-T69lesson-plans 系列文件中英文混用 🆕 新增

  • 位置
  • 问题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 修复:

// 修改前
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 修复:

// 修改前
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 修复:

// 修改前
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 修复:

// 修改前
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

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

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

// 优化前
const classes = await getTeacherClasses()
const records = await getGradeRecords({ ... })

// 优化后
const [classes, records] = await Promise.all([
  getTeacherClasses(),
  getGradeRecords({ ... }),
])

6.5 统一 lesson-plans 风格(解决 V2-T65~T69

// 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-accessactions 导出
  4. modules/school/data-access.tsgetSubjectOptions 已存在,确认 005 中已记录
  5. modules/users/data-access.tsgetUserBasicInfo 已存在,确认 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已有 getUserBasicInfogetSubjectOptions 可直接复用)
  2. 第二优先级:统一权限校验为 getAuthContext()
  3. 第三优先级:修复 lesson-plans 模块的架构违规actions → data-access
  4. 第四优先级:提取共享工具 getParamFilterChips 组件
  5. 第五优先级:并行化数据获取,优化性能

建议按 P0 → P1 → P2 → P3 顺序修复,优先解决架构与安全问题。特别是 app 层直接访问 DB 的问题,已有现成的 data-access 函数可用,修复成本极低。