docs(spec): 组件化重构专项设计文档 v1
This commit is contained in:
@@ -0,0 +1,380 @@
|
||||
# 组件化重构专项设计文档
|
||||
|
||||
| 字段 | 值 |
|
||||
|------|---|
|
||||
| 文档版本 | 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 层 preset(3 个,保留并内部收敛到 `<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
|
||||
```
|
||||
Reference in New Issue
Block a user