Files
NextEdu/docs/superpowers/specs/2026-07-06-component-refactoring-design.md
2026-07-06 17:44:15 +08:00

381 lines
16 KiB
Markdown
Raw 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.
# 组件化重构专项设计文档
| 字段 | 值 |
|------|---|
| 文档版本 | v1 |
| 创建日期 | 2026-07-06 |
| 作者 | Trae 协作生成 |
| 状态 | 待用户审查 |
| 范围 | 巨型文件拆分9 个)+ 重复组件收敛49 个)+ 共享底座补全 |
| 策略 | 混合先收敛底座再按模块垂直闭环3 批风险分级) |
---
## 1. 背景与现状
### 1.1 巨型文件清单9 个,>400 行)
基于 2026-07-06 实际扫描:
| # | 路径 | 行数 | 模块 |
|---|------|------|------|
| 1 | `src/modules/textbooks/components/textbook-reader.tsx` | >450 | textbooks |
| 2 | `src/modules/lesson-preparation/components/lesson-plan-editor.tsx` | >450 | lesson-preparation |
| 3 | `src/modules/grades/components/batch-grade-entry.tsx` | >450 | grades |
| 4 | `src/modules/grades/components/grade-record-list.tsx` | >450 | grades |
| 5 | `src/modules/homework/components/homework-take-view.tsx` | 428 | homework |
| 6 | `src/modules/homework/components/homework-grading-view.tsx` | >450 | homework |
| 7 | `src/modules/exams/components/exam-assembly.tsx` | >450 | exams |
| 8 | `src/modules/ai/components/ai-chat-panel.tsx` | 417 | ai |
| 9 | `src/modules/textbooks/components/knowledge-graph-inner.tsx` | 411 | textbooks |
**已瘦身的 5 个文件**不在本次范围内exam-rich-form.tsx (384)、message-list.tsx (396)、selection-toolbar.tsx (366)、error-book-detail-dialog.tsx (336)、admin-users-view.tsx (332)。
### 1.2 重复组件清单49 个)
| 类型 | 数量 | 示例路径 |
|------|------|---------|
| `*-filters.tsx` | 20 | `grades/components/grade-filters.tsx` 等 |
| `*-stats-cards.tsx` / `*-stats-card.tsx` | 8 | `attendance/components/attendance-stats-cards.tsx` 等 |
| `*-skeleton.tsx` | 8 | `ai/components/ai-skeleton.tsx` 等 |
| `*-error-boundary.tsx` | 8 | `audit/components/audit-error-boundary.tsx` 等 |
| `*-dashboard.tsx` | 5 | `dashboard/components/admin-dashboard/admin-dashboard.tsx` 等 |
**已知冲突**
- `textbooks/components/section-error-boundary.tsx``shared/components/section-error-boundary.tsx` 同名
- `attendance/components/attendance-stats-card.tsx`(单数)与 `attendance-stats-cards.tsx`(复数)并存
### 1.3 共享底座现状(关键发现)
| 底座 | 状态 | 路径 | 当前接口 |
|------|------|------|---------|
| `FilterBar` | 已存在 | `shared/components/ui/filter-bar.tsx` (124 行) | children-based 组合式:`FilterBar` + `FilterSearchInput` + `FilterResetButton` |
| `StatCard` | 已存在 | `shared/components/ui/stat-card.tsx` (95 行) | 单卡片,无 grid 容器 |
| `Skeleton` | 已存在 | `shared/components/ui/skeleton.tsx` (15 行) | 仅原语,无 variant |
| `ErrorBoundary` | **缺失** | — | 有 3 个分散替代件:`section-error-boundary.tsx` (148)、`route-error.tsx` (44)、`widget-boundary.tsx` (155) |
### 1.4 架构文档缺口
`docs/architecture/005_architecture_data.json``lastUpdate` 仅记录缓存策略重构2026-07-05**未记录** `filter-bar`/`stat-card`/`widget-boundary` 等底座组件的存在,违反项目规则"新增组件必须同步 004/005"。
---
## 2. 目标与非目标
### 2.1 目标
1. **补全底座**:新增 `ui/error-boundary.tsx` 基础组件 + 收敛 3 个分散替代件为 preset
2. **扩展底座**:新增 `StatsGrid` 容器(基于 `StatCard`)、`SkeletonCard` variant基于 `Skeleton`
3. **拆分巨型文件**9 个 >400 行组件全部拆为容器+子组件,目标 ≤500 行
4. **迁移重复组件**49 个重复组件迁移到底座,删除旧实现(不留 backwards-compat shim
5. **同步架构文档**004 / 005 / known-issues.md 全量更新
### 2.2 非目标YAGNI
- `shared/db/schema.ts` (1111 行) 拆分 — 属于解耦专项
- `exams/actions.ts` (633 行) 拆分 — 属于解耦专项
- 各模块 `data-access.ts` 拆分 — 属于解耦专项
- `proctoring/exam-mode-config.tsx` 死代码清理 — 单独任务
- `useDialogState` 批量接入 — V5 状态专项收尾
- 跨模块直接 DB 查询扫描 — 解耦专项遗留
- FilterBar 接口改为配置驱动 — 当前 children-based 组合式更符合 React 模式,保持不变
- 单元测试编写 — 项目无单测覆盖,本次不引入
---
## 3. 架构设计
### 3.1 Phase 1底座收敛与补全
#### 3.1.1 ErrorBoundary 收敛方案
**新增** `src/shared/components/ui/error-boundary.tsx`
```tsx
interface ErrorBoundaryProps {
fallback: React.ReactNode | ((error: Error, reset: () => void) => React.ReactNode);
onError?: (error: Error, info: React.ErrorInfo) => void;
children: React.ReactNode;
}
export class ErrorBoundary extends React.Component<ErrorBoundaryProps, { hasError: boolean; error: Error | null }> {
// 标准 React ErrorBoundary 实现
}
```
**收敛 3 个替代件为 preset**(保留外部 API内部改用 `<ErrorBoundary>`
| 现有文件 | 收敛后 | 位置 |
|---------|-------|------|
| `shared/components/section-error-boundary.tsx` | `SectionErrorBoundary` preset | 保留原路径,内部改为 `<ErrorBoundary fallback={...}>` 包装 |
| `shared/components/route-error.tsx` | `RouteErrorBoundary` preset | 保留原路径 |
| `shared/components/widget-boundary.tsx` | `WidgetBoundary` preset | 保留原路径(含 Suspense + Skeleton 三合一) |
**模块层 8 个 `*-error-boundary.tsx`**:删除,改为直接使用 `SectionErrorBoundary` preset。
#### 3.1.2 StatsGrid 新增方案
**新增** `src/shared/components/ui/stats-grid.tsx`
```tsx
interface StatItem {
label: string;
value: string | number;
trend?: { direction: 'up' | 'down' | 'flat'; delta: string };
icon?: React.ComponentType<{ className?: string }>;
href?: string;
}
interface StatsGridProps {
items: StatItem[];
columns?: 2 | 3 | 4; // 默认响应式
isLoading?: boolean;
}
```
内部用 `StatCard` 渲染,`isLoading` 时渲染 `StatCardSkeleton`
#### 3.1.3 SkeletonCard variant 方案
**扩展** `src/shared/components/ui/skeleton.tsx`15 行 → ~80 行):
```tsx
interface SkeletonCardProps {
variant: 'table' | 'list' | 'chart' | 'form' | 'stats-grid';
rows?: number;
}
export function SkeletonCard({ variant, rows = 5 }: SkeletonCardProps) {
// 按 variant 渲染不同骨架布局
}
export function Skeleton(props: React.HTMLAttributes<HTMLDivElement>) {
// 保留原语
}
```
#### 3.1.4 FilterBar 与 StatCard
- `FilterBar`**保持现状**,不修改接口。模块层 `*-filters.tsx` 改为 `<FilterBar><FilterSearchInput .../><select .../></FilterBar>` 组合实现
- `StatCard`**保持现状**,作为 `StatsGrid` 内部使用
#### 3.1.5 Phase 1 交付物
| 文件 | 操作 |
|------|------|
| `shared/components/ui/error-boundary.tsx` | 新增 |
| `shared/components/ui/stats-grid.tsx` | 新增 |
| `shared/components/ui/skeleton.tsx` | 扩展(新增 SkeletonCard |
| `shared/components/ui/filter-bar.tsx` | 不修改 |
| `shared/components/ui/stat-card.tsx` | 不修改 |
| `shared/components/section-error-boundary.tsx` | 内部改用 ErrorBoundary |
| `shared/components/route-error.tsx` | 内部改用 ErrorBoundary |
| `shared/components/widget-boundary.tsx` | 内部改用 ErrorBoundary |
| `shared/components/index.ts` | 新增 re-export |
| `docs/architecture/004` / `005` | 同步底座节点 |
### 3.2 Phase 2模块垂直闭环
#### 3.2.1 批次划分
| 批次 | 模块 | 巨型文件 | 重复组件 | 风险 |
|------|------|---------|---------|------|
| **第 1 批** | grades | `batch-grade-entry.tsx``grade-record-list.tsx` | `grade-stats-card``grade-filters``grade-query-filters``analytics-filters` | 低 |
| | attendance | — | `attendance-stats-cards``attendance-stats-card`(单数,重复)、`attendance-filters` | 低 |
| | error-book | — | `error-book-stats-cards``error-book-filters``analytics-stats-cards` | 低 |
| | elective | — | `elective-stats-cards``elective-filters` | 低 |
| **第 2 批** | homework | `homework-take-view.tsx` (428)、`homework-grading-view.tsx` | `assignment-filters` | 中 |
| | exams | `exam-assembly.tsx` | `exam-filters` | 中 |
| | textbooks | `textbook-reader.tsx``knowledge-graph-inner.tsx` (411) | `textbook-filters``section-error-boundary.tsx`(同名冲突) | 中 |
| **第 3 批** | lesson-preparation | `lesson-plan-editor.tsx` | `lesson-plan-filters``lesson-plan-skeleton``lesson-plan-error-boundary` | 高 |
| | ai | `ai-chat-panel.tsx` (417) | `ai-skeleton``ai-error-boundary` | 高 |
| | dashboard | — | `dashboard-loading-skeleton`、4 个角色 dashboard 子组件(仅抽象布局壳) | 高 |
#### 3.2.2 单模块闭环流程6 步)
```
1. 模块审计 → Read 全部目标文件 + 重复组件,记录依赖与外部 API
2. 拆分巨型文件 → 拆为 容器 + 子组件(保持外部 API 不变)
3. 迁移到底座 → *-filters → FilterBar、*-stats-cards → StatsGrid、
*-skeleton → SkeletonCard、*-error-boundary → SectionErrorBoundary
4. 删除旧组件 → 直接删除,不留 backwards-compat shim
5. 验证 → tsc --noEmit + npm run lint + 手动回归
6. 文档同步 → 004 / 005 / known-issues.md
```
#### 3.2.3 跨批次依赖规则
- Phase 1 完成 → 启动第 1 批
- 第 1 批完成 → 评估底座接口是否需调整(允许返回 Phase 1 调整)
- 第 2 批启动前 → 第 1 批验证通过
- 第 3 批启动前 → 第 2 批验证通过(高风险模块需底座稳定)
#### 3.2.4 dashboard 4 角色抽象范围
仅抽象**布局壳**`<DashboardShell>` 含 PageHeader + StatsGrid 区 + 内容区),各角色业务逻辑保持独立。不强制 4 个 dashboard 使用相同内容区。
---
## 4. 验收标准
### 4.1 代码验收(硬性门禁)
| 检查项 | 命令 | 通过标准 |
|--------|------|---------|
| TypeScript | `npx tsc --noEmit` | 零错误 |
| ESLint | `npm run lint` | 零新增错误pre-existing warnings 不计入) |
| 文件行数 | Read 确认 | 9 个巨型文件拆分后 ≤500 行 |
| 重复组件删除 | Grep 旧组件名 | 全局无残留引用 |
| 外部 API 不变 | Grep 模块导出名 | 容器组件对外 API 签名不变 |
| 设计令牌合规 | Grep `#hex``'Inter'``w-[` | 零违规(豁免场景除外) |
### 4.2 行为验收(手动回归)
| 模块类型 | 验收方式 |
|---------|---------|
| 列表/筛选页 | 进入页面 → 应用筛选 → 重置 → 翻页 → 数据正确 |
| 表单页 | 打开 Dialog → 填写 → 提交 → 列表刷新 |
| 编辑器 | 进入 → 编辑内容 → 保存 → 重新加载内容存在 |
| dashboard | 4 角色分别登录 → 卡片渲染 → 数据正确 |
### 4.3 文档同步
- `004_architecture_impact_map.md`:模块章节组件清单 + shared/components 章节 + 文末"组件化重构专项"章节
- `005_architecture_data.json``modules.*.exports` + `sharedComponents` + `lastUpdate` + `dependencyMatrix`
- `known-issues.md`:每批新增章节,速查手册风格记录底座使用规则与拆分模式
### 4.4 Commit 规范
每批一个 squash commit
```
refactor(grades,attendance,error-book,elective): 组件化重构第 1 批
- 新增 ErrorBoundary/StatsGrid/SkeletonCard 底座
- 拆分 grades/batch-grade-entry.tsx (XXX → YYY 行)
- 删除 12 个重复组件,迁移到底座
- 同步 004/005 架构图known-issues 新增章节
验收tsc + lint 零错误,手动回归 4 模块页面通过
```
---
## 5. 风险与缓解
| 风险 | 缓解 |
|------|------|
| 底座接口设计不准 → 返工 | 第 1 批低风险模块验证后允许调整底座 |
| 巨型文件拆分破坏外部 API | 容器保持外部 API 不变,仅内部拆子组件 |
| 删除旧组件后引用未清理 | tsc + lint + grep 三重校验 |
| textbooks 同名 `section-error-boundary.tsx` 冲突 | 模块层版本删除,改用 shared 层 |
| 富文本/编辑器拆分难度高 | textbooks 按 `003_ui_refactoring_plan.md` 已有方案执行 |
| dashboard 4 角色抽象范围蔓延 | 仅抽象布局壳,业务逻辑保持独立 |
---
## 6. 失败回滚策略
- 模块闭环中暴露底座接口问题 → 停止该模块,回 Phase 1 调整底座,已完成模块不回滚
- 模块闭环中暴露业务逻辑问题(非组件化引起)→ 不在本次范围,记录到 known-issues组件化继续推进
---
## 7. 完成定义Definition of Done
- [ ] Phase 1 完成ErrorBoundary/StatsGrid/SkeletonCard 落地3 个替代件收敛为 preset
- [ ] 第 1 批完成grades/attendance/error-book/elective 闭环
- [ ] 第 2 批完成homework/exams/textbooks 闭环
- [ ] 第 3 批完成lesson-preparation/ai/dashboard 闭环
- [ ] 9 个巨型文件全部 ≤500 行
- [ ] 49 个重复组件全部删除并迁移到底座
- [ ] 004 / 005 / known-issues 同步更新
- [ ] 3 个批次 commit 全部提交
---
## 8. 附录:完整重复组件清单
### 8.1 `*-filters.tsx`20 个)
```
shared/components/question/question-bank-filters.tsx
modules/grades/components/grade-query-filters.tsx
modules/grades/components/grade-filters.tsx
modules/grades/components/analytics-filters.tsx
modules/classes/components/students-filters.tsx
modules/classes/components/schedule-filters.tsx
modules/attendance/components/attendance-filters.tsx
modules/error-book/components/error-book-filters.tsx
modules/exams/components/exam-filters.tsx
modules/audit/components/data-change-log-filters.tsx
modules/audit/components/login-log-filters.tsx
modules/audit/components/audit-log-filters.tsx
modules/lesson-preparation/components/lesson-plan-filters.tsx
modules/homework/components/assignment-filters.tsx
modules/questions/components/question-filters.tsx
modules/student/components/course-filters.tsx
modules/student/components/student-schedule-filters.tsx
modules/school/components/grade-insights-filters.tsx
modules/textbooks/components/textbook-filters.tsx
modules/elective/components/elective-filters.tsx
```
### 8.2 `*-stats-cards.tsx` / `*-stats-card.tsx`8 个)
```
modules/error-book/components/analytics-stats-cards.tsx
modules/error-book/components/error-book-stats-cards.tsx
modules/attendance/components/attendance-stats-cards.tsx
modules/attendance/components/attendance-stats-card.tsx ← 单数,与复数重复
modules/elective/components/elective-stats-cards.tsx
modules/adaptive-practice/components/practice-overview-stats-cards.tsx
modules/adaptive-practice/components/practice-stats-cards.tsx
modules/grades/components/grade-stats-card.tsx
```
### 8.3 `*-skeleton.tsx`8 个)
```
modules/messaging/components/message-list-skeleton.tsx
modules/announcements/components/announcement-list-skeleton.tsx
modules/audit/components/audit-log-table-skeleton.tsx
modules/classes/components/class-skeleton.tsx
modules/ai/components/ai-skeleton.tsx
modules/school/components/school-skeleton.tsx
modules/dashboard/components/dashboard-loading-skeleton.tsx
modules/lesson-preparation/components/lesson-plan-skeleton.tsx
```
### 8.4 ErrorBoundary 相关文件10 个)
**shared 层 preset3 个,保留并内部收敛到 `<ErrorBoundary>`**
```
shared/components/section-error-boundary.tsx
shared/components/route-error.tsx
shared/components/widget-boundary.tsx
```
**模块层待删除7 个,改为直接使用 `SectionErrorBoundary` preset**
```
modules/audit/components/audit-error-boundary.tsx
modules/school/components/school-error-boundary.tsx
modules/classes/components/class-error-boundary.tsx
modules/textbooks/components/section-error-boundary.tsx ← 与 shared 同名,删除
modules/settings/components/settings-section-error-boundary.tsx
modules/ai/components/ai-error-boundary.tsx
modules/lesson-preparation/components/lesson-plan-error-boundary.tsx
```
### 8.5 `*-dashboard.tsx`5 个)
```
modules/ai/components/ai-usage-dashboard.tsx
modules/dashboard/components/parent-dashboard/parent-dashboard.tsx
modules/dashboard/components/admin-dashboard/admin-dashboard.tsx
modules/proctoring/components/proctoring-dashboard.tsx
modules/exams/components/exam-analytics-dashboard.tsx
```