# Admin 前端文件规范核查报告

> 核查范围：`src/app/(dashboard)/admin/` 下全部 26 个 `page.tsx` 文件
> 核查依据：
> - `.trae/rules/project_rules.md`（项目规则）
> - `docs/standards/coding-standards.md`（编码规范 v1.0）
> - `docs/architecture/004_architecture_impact_map.md`（架构影响地图）
> - React / Next.js 16 最佳实践
> - Web 界面设计规范（WCAG 2.2 AA）
> 核查日期：2026-06-18

---

## 一、核查概览

| 维度 | 文件数 | 通过 | 待改进 |
|------|--------|------|--------|
| 架构分层 | 26 | 24 | 2 |
| TypeScript 规范 | 26 | 4 | 22 |
| 安全与权限 | 26 | 3 | 23 |
| UI 一致性与设计令牌 | 26 | 18 | 8 |
| 错误与加载边界 | 26 | 0 | 26 |
| 代码复用（DRY） | 26 | 0 | 26 |

**结论**：整体架构清晰、服务端组件使用规范、并行数据获取到位，但在**返回类型标注、权限校验一致性、加载/错误边界、代码复用、UI 文案一致性**方面存在系统性问题，需统一整改。

---

## 二、问题清单（按严重程度排序）

### P0 严重问题（必须立即修复）

#### P0-1 全部 26 个页面缺少 `error.tsx` 与 `loading.tsx`

**违反规范**：
- 编码规范 §2.3：「每个路由段应提供 `loading.tsx`（骨架屏）和 `error.tsx`（错误边界）」
- 编码规范 §2.4：「每个路由段都必须提供 `error.tsx`，不得出现未捕获异常导致白屏」
- 编码规范 §2.4：「`loading.tsx` 必须提供骨架屏或最小可感知的加载状态，不得使用全局 spin 遮罩」

**现状**：`src/app/(dashboard)/admin/` 及其所有子路由（`dashboard/`、`announcements/`、`school/*`、`audit-logs/*`、`scheduling/*`、`course-plans/*`、`elective/*`、`attendance/`、`files/`、`users/import/`）均**未提供** `loading.tsx` 和 `error.tsx`。

对比：`teacher/`、`student/` 路由组在关键页面已提供 `loading.tsx`（如 `teacher/exams/all/loading.tsx`、`student/dashboard/loading.tsx`），admin 路由组完全缺失。

**影响**：
- 数据获取失败时整页白屏，用户体验差
- 无加载态感知，用户误以为页面卡死
- 不符合 Next.js 16 App Router 最佳实践（Suspense 流式渲染）

**修复建议**：
1. 在 `src/app/(dashboard)/admin/` 根目录新增 `error.tsx`（具名导出，客户端组件，含重试按钮）
2. 在 `src/app/(dashboard)/admin/` 根目录新增 `loading.tsx`（骨架屏，匹配各页面布局）
3. 对数据量大的页面（`audit-logs/*`、`school/grades/insights`、`attendance`）单独提供 `loading.tsx`
4. 对动态路由（`[id]/page.tsx`）单独提供 `error.tsx` 处理 `notFound` 以外的异常

---

#### P0-2 `attendance/page.tsx` 缺少权限校验

**文件**：[src/app/(dashboard)/admin/attendance/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/admin/attendance/page.tsx)

**违反规范**：
- 项目规则：「Server Action 必须使用 `requirePermission()` 进行权限校验」
- 编码规范 §8.3：「权限校验：Server Action 必须使用 `requirePermission()`」

**现状**：第 26 行仅调用 `getAuthContext()` 获取上下文，**未调用 `requirePermission()`** 验证用户是否有考勤查看权限。

```tsx
// 当前代码（第 26 行）
const ctx = await getAuthContext()
```

**对比**：同类 admin 页面均做了权限校验：
- `audit-logs/page.tsx` 第 22 行：`await requirePermission(Permissions.AUDIT_LOG_READ)`
- `audit-logs/login-logs/page.tsx` 第 22 行：`await requirePermission(Permissions.AUDIT_LOG_READ)`
- `audit-logs/data-changes/page.tsx` 第 26 行：`await requirePermission(Permissions.AUDIT_LOG_READ)`
- `files/page.tsx` 第 12 行：`await requirePermission(Permissions.FILE_READ)`

**影响**：越权风险——无考勤查看权限的用户可直接访问 `/admin/attendance` 查看全校考勤数据。

**修复建议**：在 `getAuthContext()` 前增加权限校验：
```tsx
await requirePermission(Permissions.ATTENDANCE_READ)
const ctx = await getAuthContext()
```

---

### P1 重要问题（应尽快修复）

#### P1-1 全部 26 个页面组件缺少返回类型标注

**违反规范**：
- 编码规范 §4.2：「函数返回值必须显式标注，特别是 `Promise<T>`」
- 项目规则：「函数返回值必须显式标注」

**现状**：所有 `page.tsx` 的默认导出函数均未标注返回类型，例如：

```tsx
// dashboard/page.tsx
export default async function AdminDashboardPage() {  // ❌ 缺少 : Promise<JSX.Element>
  const data = await getAdminDashboardData()
  return <AdminDashboardView data={data} />
}
```

**影响**：26 个文件全部不合规，类型推导依赖 TS 隐式推断，不利于代码审查与维护。

**修复建议**：统一补充返回类型：
```tsx
export default async function AdminDashboardPage(): Promise<JSX.Element> {
  // ...
}
```

涉及文件：admin 目录下全部 26 个 `page.tsx`。

---

#### P1-2 `getParam` 工具函数在 27 个文件中重复定义

**违反规范**：
- 编码规范 §一：「单一职责」「工具函数 ≤ 40 行」
- DRY 原则

**现状**：以下 admin 文件各自重复定义了相同的 `getParam` / `SearchParams` 类型与函数：

| 文件 | 行号 |
|------|------|
| `announcements/page.tsx` | 8-13 |
| `audit-logs/page.tsx` | 10-15 |
| `audit-logs/login-logs/page.tsx` | 10-15 |
| `audit-logs/data-changes/page.tsx` | 14-19 |
| `scheduling/changes/page.tsx` | 16-21 |
| `course-plans/page.tsx` | 7-12 |
| `elective/page.tsx` | 7-12 |
| `attendance/page.tsx` | 13-18 |
| `school/grades/insights/page.tsx` | 15-22 |

全项目共 27 个文件重复（含 teacher / student / management 路由组）。

**影响**：维护成本高，任何一处逻辑变更需同步修改 27 处。

**修复建议**：
1. 在 `src/shared/lib/utils.ts` 新增共享工具：
```tsx
export type SearchParams = { [key: string]: string | string[] | undefined }

export function getSearchParam(params: SearchParams, key: string): string | undefined {
  const v = params[key]
  return Array.isArray(v) ? v[0] : v
}
```
2. 全部页面改为 `import { getSearchParam, type SearchParams } from "@/shared/lib/utils"`
3. 同步更新架构文档 004 / 005

---

#### P1-3 多个页面使用 `as` 类型断言违反 TypeScript 规范

**违反规范**：
- 编码规范 §4.2：「不使用 `as` 断言，除非从 `unknown` 强制转换或在测试中（需注释原因）」
- 项目规则：「禁止 `as` 断言（除非从 `unknown` 转换或测试中，需注释原因）」

**现状**：以下文件使用 `as` 进行类型断言而非类型守卫：

| 文件 | 行号 | 问题代码 |
|------|------|---------|
| `audit-logs/page.tsx` | 28 | `(getParam(params, "status") as AuditLogStatus \| undefined)` |
| `audit-logs/login-logs/page.tsx` | 26-27 | `as LoginLogAction \| undefined`、`as LoginLogStatus \| undefined` |
| `audit-logs/data-changes/page.tsx` | 31 | `as DataChangeAction \| undefined` |
| `attendance/page.tsx` | 39 | `as "present" \| "absent" \| "late" \| "early_leave" \| "excused"` |

**对比（正确示例）**：以下文件已使用类型守卫，应作为模板推广：
- `announcements/page.tsx` 第 15-16 行：`isValidStatus` 类型守卫
- `scheduling/changes/page.tsx` 第 23-24 行：`isValidStatus` 类型守卫
- `course-plans/page.tsx` 第 14-15 行：`isValidStatus` 类型守卫
- `elective/page.tsx` 第 14-15 行：`isValidStatus` 类型守卫

**影响**：运行时无法捕获非法枚举值，类型安全被绕过。

**修复建议**：为每个枚举类型补充类型守卫，替换 `as` 断言：
```tsx
const isValidAuditLogStatus = (v?: string): v is AuditLogStatus =>
  v === "success" || v === "failure" || v === "pending"

const status = isValidAuditLogStatus(statusParam) ? statusParam : undefined
```

---

#### P1-4 UI 文案语言不统一（中英文混用）

**违反规范**：
- 编码规范 §一：「可读性优先」
- 项目定位为「Next_Edu K12 智慧教务系统」（中文用户）

**现状**：

| 文件 | 文案语言 |
|------|---------|
| `users/import/page.tsx` | 中文（"批量导入用户"、"返回"） |
| `announcements/[id]/page.tsx` | 英文（"Edit Announcement"） |
| `school/schools/page.tsx` | 英文（"Schools"、"Manage schools..."） |
| `school/classes/page.tsx` | 英文（"Classes"、"Manage classes..."） |
| `school/grades/page.tsx` | 英文（"Grades"、"Manage grades..."） |
| `school/grades/insights/page.tsx` | 英文（"Grade Insights"、"Filters"） |
| `school/academic-year/page.tsx` | 英文（"Academic Year"） |
| `school/departments/page.tsx` | 英文（"Departments"） |
| `audit-logs/page.tsx` | 英文（"Audit Logs"） |
| `audit-logs/login-logs/page.tsx` | 英文（"Login Logs"） |
| `audit-logs/data-changes/page.tsx` | 英文（"Data Change Logs"） |
| `scheduling/auto/page.tsx` | 英文（"Auto Schedule"） |
| `scheduling/changes/page.tsx` | 英文（"Schedule Change Requests"） |
| `scheduling/rules/page.tsx` | 英文（"Scheduling Rules"） |
| `course-plans/page.tsx` | 英文（"Course Plans"） |
| `course-plans/create/page.tsx` | 英文（"New Course Plan"） |
| `course-plans/[id]/edit/page.tsx` | 英文（"Edit Course Plan"） |
| `elective/page.tsx` | 英文（"Elective Courses"） |
| `elective/create/page.tsx` | 英文（"New Elective Course"） |
| `elective/[id]/edit/page.tsx` | 英文（"Edit Elective Course"） |
| `attendance/page.tsx` | 英文（"Attendance Overview"） |

**影响**：用户体验割裂，admin 区仅 `users/import` 为中文，其余全英文，与系统定位不符。

**修复建议**：统一为中文（与 `users/import/page.tsx` 保持一致），或引入 i18n 方案统一管理。建议优先统一为中文。

---

### P2 一般问题（建议修复）

#### P2-1 `school/grades/insights/page.tsx` 使用原生 `<select>` 而非共享组件

**文件**：[src/app/(dashboard)/admin/school/grades/insights/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/admin/school/grades/insights/page.tsx#L57-L68)

**现状**：第 57-68 行使用原生 `<select>` 元素，而项目已提供 `@/shared/components/ui/select.tsx`（shadcn Select）。

```tsx
<select
  name="gradeId"
  defaultValue={selected || "all"}
  className="h-10 w-full rounded-md border bg-background px-3 text-sm md:w-[360px]"
>
```

**影响**：
- UI 风格与其他页面不一致（其他页面使用 shadcn Select）
- 原生 `<select>` 样式难以跨浏览器统一
- 可访问性较弱（缺少 ARIA 属性）

**修复建议**：替换为 `@/shared/components/ui/select.tsx` 的 `Select` / `SelectTrigger` / `SelectContent` / `SelectItem` 组合。

---

#### P2-2 `users/import/page.tsx` 使用原生 `<table>` 而非共享组件

**文件**：[src/app/(dashboard)/admin/users/import/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/admin/users/import/page.tsx#L93-L128)

**现状**：第 93-128 行使用原生 `<table>` 元素手写表格，而项目已提供 `@/shared/components/ui/table.tsx`（shadcn Table）。

**影响**：与 `school/grades/insights/page.tsx` 等使用 shadcn Table 的页面风格不一致。

**修复建议**：替换为 `Table` / `TableHeader` / `TableBody` / `TableRow` / `TableHead` / `TableCell` 组合。

---

#### P2-3 Tailwind 任意值违规

**违反规范**：
- 编码规范 §6.2：「禁止使用任意值（`w-[137px]`），除非有充分理由并注释说明」
- 项目规则：「禁止使用任意值（`w-[137px]`），除非有充分理由并注释」

**现状**：

| 文件 | 行号 | 问题类名 |
|------|------|---------|
| `school/grades/insights/page.tsx` | 60 | `md:w-[360px]` |
| `school/grades/insights/page.tsx` | 82, 89, 96 | `h-[360px]` |
| `users/import/page.tsx` | 16 | `h-full flex-1 flex-col`（`flex-1` 合理，但整体布局类应复用） |

**修复建议**：
- `md:w-[360px]` → 使用设计令牌宽度类（如 `md:w-72` 或 `md:w-80`）或在 globals.css 定义 `--filter-width` 变量
- `h-[360px]` → 使用 `h-80`（320px）或 `h-96`（384px）等标准档位

---

#### P2-4 `users/import/page.tsx` 使用硬编码颜色

**违反规范**：
- 编码规范 §6.3：「所有视觉设计决策（颜色、字号、间距）必须体现在设计令牌中，组件中不使用硬编码值」

**文件**：[src/app/(dashboard)/admin/users/import/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/admin/users/import/page.tsx#L67)

**现状**：第 67 行使用 `text-amber-500` 硬编码颜色：
```tsx
<Info className="h-5 w-5 text-amber-500" />
```

**修复建议**：使用设计令牌颜色，如 `text-warning`（若存在）或在 globals.css 定义 `--warning` 变量。如暂无 warning 令牌，可使用 `text-primary` 或 `text-muted-foreground` 保持一致。

---

#### P2-5 `school/grades/insights/page.tsx` 导入顺序违规

**违反规范**：
- 编码规范 §4.3：「导入顺序：React → 第三方 → 内部绝对路径 → 相对路径 → 类型导入」
- 项目规则引用的 ESLint `import/order` 规则

**文件**：[src/app/(dashboard)/admin/school/grades/insights/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/admin/school/grades/insights/page.tsx#L1-L11)

**现状**：第 1-11 行导入顺序混乱，`lucide-react`（第三方库）被放在所有 `@/` 内部导入之后：
```tsx
import Link from "next/link"                                          // next（外部）
import { getGrades } from "@/modules/school/data-access"              // 内部
import { getGradeHomeworkInsights } from "@/modules/classes/data-access"
import { EmptyState } from "@/shared/components/ui/empty-state"
import { Card, CardContent, CardHeader, CardTitle } from "@/shared/components/ui/card"
import { Badge } from "@/shared/components/ui/badge"
import { Button } from "@/shared/components/ui/button"
import { Table, TableBody, ... } from "@/shared/components/ui/table"
import { formatDate } from "@/shared/lib/utils"
import { BarChart3 } from "lucide-react"                              // ❌ 第三方应在前
```

**修复建议**：调整为 `next` → `lucide-react` → `@/` 内部导入，分组间空一行：
```tsx
import Link from "next/link"

import { BarChart3 } from "lucide-react"

import { getGrades } from "@/modules/school/data-access"
// ...
```

---

#### P2-6 `course-plans/[id]/edit/page.tsx` 同模块重复导入

**文件**：[src/app/(dashboard)/admin/course-plans/[id]/edit/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/admin/course-plans/[id]/edit/page.tsx#L3-L4)

**现状**：第 3-4 行从同一模块 `@/modules/course-plans/data-access` 分两行导入：
```tsx
import { getCoursePlanById } from "@/modules/course-plans/data-access"
import { getSubjectOptions } from "@/modules/course-plans/data-access"
```

**修复建议**：合并为单行：
```tsx
import { getCoursePlanById, getSubjectOptions } from "@/modules/course-plans/data-access"
```

---

#### P2-7 `scheduling/*` 页面从 `actions` 而非 `data-access` 获取数据

**违反规范**：
- 编码规范 §7.1：「服务端数据获取通过模块的 `data-access.ts` 函数」
- 架构影响地图：「actions.ts（编排层：权限 + 调用 data-access + revalidate）」

**现状**：以下页面从 `@/modules/scheduling/actions` 导入数据查询函数：

| 文件 | 导入函数 |
|------|---------|
| `scheduling/auto/page.tsx` | `getAdminClassesForScheduling` |
| `scheduling/changes/page.tsx` | `getAdminClassesForScheduling`、`getScheduleChanges` |
| `scheduling/rules/page.tsx` | `getAdminClassesForScheduling`、`getSchedulingRules` |

**说明**：规范允许 `app/` 调用 Server Actions，但 Server Actions 的职责是「编排：权限 + 调用 data-access + revalidate」，主要用于**变更操作**。纯读取操作应通过 `data-access.ts` 暴露，避免在 Server Component 中触发不必要的 `revalidate` 逻辑。

**修复建议**：将 `getAdminClassesForScheduling`、`getScheduleChanges`、`getSchedulingRules` 等纯查询函数迁移到 `scheduling/data-access.ts`，或在 actions 中明确标注其为只读封装。需同步更新架构文档 004 / 005。

---

## 三、React 性能优化建议（基于最佳实践）

### R1 利用 Suspense 流式渲染提升首屏感知性能

**现状**：所有页面使用 `export const dynamic = "force-dynamic"` 整页动态渲染，数据获取完成前无任何内容呈现。

**建议**：对数据量大的页面（`audit-logs/*`、`school/grades/insights`、`attendance`）拆分为多个 Suspense 边界，优先渲染页面骨架，慢查询部分流式注入：

```tsx
import { Suspense } from "react"

export default async function AuditLogsPage(): Promise<JSX.Element> {
  return (
    <div className="flex h-full flex-col space-y-8 p-8">
      <Header />
      <Suspense fallback={<FilterSkeleton />}>
        <Filters />
      </Suspense>
      <Suspense fallback={<TableSkeleton />}>
        <AuditTable />
      </Suspense>
    </div>
  )
}
```

### R2 `school/grades/insights/page.tsx` 串行查询可优化为并行

**文件**：[src/app/(dashboard)/admin/school/grades/insights/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/admin/school/grades/insights/page.tsx#L30-L33)

**现状**：第 30-33 行先 `await getGrades()` 再条件 `await getGradeHomeworkInsights()`，两次串行查询：
```tsx
const grades = await getGrades()
const selected = gradeId && gradeId !== "all" ? gradeId : ""
const insights = selected ? await getGradeHomeworkInsights({ gradeId: selected, limit: 50 }) : null
```

**说明**：`insights` 依赖 `selected`（来自 URL 参数，非 `grades` 结果），两者无数据依赖，可并行：
```tsx
const selected = gradeId && gradeId !== "all" ? gradeId : ""
const [grades, insights] = await Promise.all([
  getGrades(),
  selected ? getGradeHomeworkInsights({ gradeId: selected, limit: 50 }) : Promise.resolve(null),
])
```

### R3 列表页 `classOptions` 映射可下沉至 data-access

**现状**：`scheduling/auto`、`scheduling/changes`、`scheduling/rules`、`attendance`、`course-plans/create`、`course-plans/[id]/edit`、`elective/create`、`elective/[id]/edit` 等页面均在组件内 `.map()` 转换数据形状：

```tsx
const classOptions = classes.map((c) => ({ id: c.id, name: c.name, grade: c.grade }))
```

**建议**：在对应 `data-access.ts` 提供 `getClassOptions()`、`getStaffOptions()` 等轻量查询函数，仅返回 `{ id, name }` 形状，减少传输数据量与组件层转换逻辑。

---

## 四、Web 界面设计规范建议（基于 WCAG 2.2 AA）

### W1 表单 `<label>` 与控件关联不规范

**文件**：[src/app/(dashboard)/admin/school/grades/insights/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/admin/school/grades/insights/page.tsx#L56-L57)

**现状**：第 56-57 行 `<label>` 与 `<select>` 未通过 `htmlFor` / `id` 关联：
```tsx
<label className="text-sm font-medium">Grade</label>
<select name="gradeId" ...>
```

**违反**：WCAG 2.2 SC 1.3.1（信息与关系）、SC 3.3.2（标签或指令）。

**修复建议**：
```tsx
<label htmlFor="grade-filter" className="text-sm font-medium">Grade</label>
<select id="grade-filter" name="gradeId" ...>
```

### W2 `users/import/page.tsx` 表格缺少 `<caption>` 与语义化标注

**文件**：[src/app/(dashboard)/admin/users/import/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/admin/users/import/page.tsx#L93-L128)

**现状**：原生 `<table>` 缺少 `<caption>` 描述表格用途，屏幕阅读器无法快速理解表格主题。

**修复建议**：增加 `<caption className="sr-only">模板字段说明</caption>`，或替换为 shadcn Table 后通过 `aria-label` 补充。

### W3 页面标题层级不统一

**现状**：
- 部分页面使用 `<h2>` 作为页面主标题（如 `school/schools`、`audit-logs`）
- `users/import/page.tsx` 也使用 `<h2>`
- 但页面布局中未见统一的 `<h1>` 主标题层级

**建议**：确认 `(dashboard)/layout.tsx` 是否提供 `<h1>` 或页面 `<main>` 的 accessible name，若无，建议各页面统一使用 `<h1>` 作为页面主标题，`<h2>` 用于区块标题，保持标题层级连贯。

### W4 交互式筛选器缺少 `aria-live` 反馈

**文件**：`school/grades/insights/page.tsx`、`attendance/page.tsx`、`audit-logs/*`

**现状**：筛选器提交后表格数据刷新，但屏幕阅读器用户无法感知数据已更新。

**违反**：WCAG 2.2 SC 4.1.3（状态消息）。

**建议**：在表格容器添加 `aria-live="polite"` 或使用项目已有的 `useAriaLive` Hook 通知「已加载 N 条记录」。

### W5 `EmptyState` 组件使用一致但图标语义可优化

**现状**：`scheduling/*`、`attendance`、`school/grades/insights` 均使用 `EmptyState` 组件，图标统一使用 `ClipboardList` / `BarChart3`，体验一致（优点）。

**建议**：`BarChart3` 用于「无数据」与「选择年级」两种语义略显混淆，建议「等待操作」类空状态使用 `MousePointerClick` 或 `Filter` 图标区分。

---

## 五、优秀实践（已符合规范，应保持）

1. **服务端组件默认化**：全部 26 个页面均为 async 服务端组件，未滥用 `"use client"`，符合 §5.2。
2. **并行数据获取**：`announcements/page.tsx`、`audit-logs/*`、`course-plans/create`、`course-plans/[id]/edit`、`elective/create`、`elective/[id]/edit`、`school/grades`、`scheduling/rules` 等均使用 `Promise.all` 并行查询，性能良好。
3. **类型守卫正确使用**：`announcements/page.tsx`、`scheduling/changes/page.tsx`、`course-plans/page.tsx`、`elective/page.tsx` 使用 `isValidStatus` 类型守卫，是 `as` 断言的正确替代方案。
4. **404 处理**：`announcements/[id]/page.tsx`、`course-plans/[id]/page.tsx`、`course-plans/[id]/edit/page.tsx`、`elective/[id]/edit/page.tsx` 使用 `notFound()` 处理资源不存在场景。
5. **权限校验到位**：`audit-logs/*`（3 个文件）、`files/page.tsx` 正确调用 `requirePermission()`。
6. **模块化组合**：页面仅负责数据获取与组合，UI 逻辑下沉至 `modules/*/components/`，符合三层架构。
7. **`force-dynamic` 标注**：需要实时数据的页面均显式声明 `export const dynamic = "force-dynamic"`。
8. **`metadata` 导出**：`users/import/page.tsx` 正确导出 `metadata` 用于 SEO（建议其他页面补充）。

---

## 六、修复优先级与建议执行顺序

| 优先级 | 问题编号 | 建议执行顺序 | 影响范围 |
|--------|---------|-------------|---------|
| P0 | P0-2 | 立即修复 attendance 权限 | 1 文件 |
| P0 | P0-1 | 补充 error.tsx / loading.tsx | 新增 ~6 文件 |
| P1 | P1-1 | 补充返回类型标注 | 26 文件 |
| P1 | P1-2 | 抽取共享 getSearchParam | 27 文件 |
| P1 | P1-3 | 替换 as 断言为类型守卫 | 4 文件 |
| P1 | P1-4 | 统一 UI 文案语言 | ~20 文件 |
| P2 | P2-1 ~ P2-7 | 逐步整改 | 单文件级 |
| R1 ~ R3 | 性能优化 | 迭代优化 | 关键页面 |
| W1 ~ W5 | 可访问性 | 迭代优化 | 关键页面 |

---

## 七、附：文件清单与合规状态

| 文件 | P0 | P1 | P2 | 备注 |
|------|----|----|----|----|
| `dashboard/page.tsx` | - | 缺返回类型 | - | 整体合规 |
| `announcements/page.tsx` | - | 缺返回类型、getParam 重复 | - | 类型守卫正确 |
| `announcements/[id]/page.tsx` | - | 缺返回类型、英文文案 | - | - |
| `users/import/page.tsx` | - | 缺返回类型 | 原生 table、硬编码颜色 | 文案为中文（正确） |
| `school/page.tsx` | - | 缺返回类型 | - | 仅 redirect |
| `school/schools/page.tsx` | - | 缺返回类型、英文文案 | - | - |
| `school/classes/page.tsx` | - | 缺返回类型、英文文案 | - | - |
| `school/grades/page.tsx` | - | 缺返回类型、英文文案 | - | - |
| `school/grades/insights/page.tsx` | - | 缺返回类型、英文文案 | 原生 select、任意值、导入顺序、label 未关联 | 问题最多 |
| `school/academic-year/page.tsx` | - | 缺返回类型、英文文案 | - | - |
| `school/departments/page.tsx` | - | 缺返回类型、英文文案 | - | - |
| `audit-logs/page.tsx` | - | 缺返回类型、as 断言、英文文案、getParam 重复 | - | 权限校验正确 |
| `audit-logs/login-logs/page.tsx` | - | 缺返回类型、as 断言、英文文案、getParam 重复 | - | 权限校验正确 |
| `audit-logs/data-changes/page.tsx` | - | 缺返回类型、as 断言、英文文案、getParam 重复 | - | 权限校验正确 |
| `scheduling/auto/page.tsx` | - | 缺返回类型、英文文案 | 从 actions 取数 | - |
| `scheduling/changes/page.tsx` | - | 缺返回类型、英文文案、getParam 重复 | 从 actions 取数 | 类型守卫正确 |
| `scheduling/rules/page.tsx` | - | 缺返回类型、英文文案 | 从 actions 取数 | - |
| `course-plans/page.tsx` | - | 缺返回类型、英文文案、getParam 重复 | - | 类型守卫正确 |
| `course-plans/create/page.tsx` | - | 缺返回类型、英文文案 | - | - |
| `course-plans/[id]/page.tsx` | - | 缺返回类型 | - | - |
| `course-plans/[id]/edit/page.tsx` | - | 缺返回类型、英文文案 | 重复导入 | - |
| `elective/page.tsx` | - | 缺返回类型、英文文案、getParam 重复 | - | 类型守卫正确 |
| `elective/create/page.tsx` | - | 缺返回类型、英文文案 | - | - |
| `elective/[id]/edit/page.tsx` | - | 缺返回类型、英文文案 | - | - |
| `attendance/page.tsx` | **缺权限校验** | 缺返回类型、as 断言、英文文案、getParam 重复 | - | 最高优先级 |
| `files/page.tsx` | - | 缺返回类型 | - | 权限校验正确、整体合规 |

---

> 报告生成完毕。建议按「六、修复优先级」顺序整改，每完成一批次后运行 `npm run lint` 与 `npx tsc --noEmit` 验证，并同步更新架构文档 004 / 005。
