879 lines
30 KiB
Markdown
879 lines
30 KiB
Markdown
# CLAUDE.md
|
||
|
||
本文件为 Claude Code (claude.ai/code) 提供在此代码库中工作的指导说明。
|
||
|
||
## 项目概览
|
||
|
||
混合式 React 仪表板,用于金融/交易分析,采用 Flask 后端。基于 Argon Dashboard Chakra PRO 模板构建。
|
||
|
||
### 技术栈
|
||
|
||
**前端**
|
||
- React 18.3.1 + Chakra UI 2.8.2 + Ant Design
|
||
- Redux Toolkit 用于状态管理
|
||
- React Router v6 配合 React.lazy() 实现代码分割
|
||
- CRACO 构建系统,具有激进的 webpack 优化
|
||
- 图表库: ApexCharts、ECharts、Recharts、D3
|
||
- 其他: Three.js、FullCalendar、Leaflet 地图
|
||
|
||
**后端**
|
||
- Flask + SQLAlchemy ORM
|
||
- ClickHouse(分析型数据库)+ MySQL/PostgreSQL(事务型数据库)
|
||
- Flask-SocketIO 实现 WebSocket 实时更新
|
||
- Celery + Redis 处理后台任务
|
||
- 腾讯云短信 + 微信支付集成
|
||
|
||
## 开发命令
|
||
|
||
### 前端开发
|
||
```bash
|
||
npm start # 使用 mock 数据启动(.env.mock),代理到 localhost:5001
|
||
npm run start:real # 使用真实后端启动(.env.local)
|
||
npm run start:dev # 使用开发配置启动(.env.development)
|
||
npm run start:test # 同时启动后端(app.py)和前端(.env.test)
|
||
npm run dev # 'npm start' 的别名
|
||
npm run backend # 仅启动 Flask 服务器(python app.py)
|
||
|
||
npm run build # 生产环境构建,包含 Gulp 许可证头
|
||
npm run build:analyze # 使用 webpack bundle analyzer 构建
|
||
npm test # 运行 React 测试套件(CRACO)
|
||
|
||
npm run lint:check # 检查 ESLint 规则(退出码 0)
|
||
npm run lint:fix # 自动修复 ESLint 问题
|
||
npm run clean # 删除 node_modules 和 package-lock.json
|
||
npm run reinstall # 清洁安装(运行 clean + install)
|
||
```
|
||
|
||
### 后端开发
|
||
```bash
|
||
python app.py # 主 Flask 服务器
|
||
python simulation_background_processor.py # 交易模拟的后台任务处理器
|
||
pip install -r requirements.txt # 安装 Python 依赖
|
||
```
|
||
|
||
### 部署
|
||
```bash
|
||
npm run deploy # 从本地部署(scripts/deploy-from-local.sh)
|
||
npm run rollback # 回滚到上一个版本
|
||
```
|
||
|
||
## 架构
|
||
|
||
### 应用入口流程
|
||
```
|
||
src/index.js
|
||
└── src/App.js(根组件)
|
||
├── AppProviders (src/providers/AppProviders.js)
|
||
│ ├── ReduxProvider(store 来自 src/store/)
|
||
│ ├── ChakraProvider(主题来自 src/theme/)
|
||
│ ├── NotificationProvider (src/contexts/NotificationContext.js)
|
||
│ └── AuthProvider (src/contexts/AuthContext.js)
|
||
├── AppRoutes (src/routes/index.js)
|
||
│ ├── MainLayout 路由(带导航栏/页脚)
|
||
│ └── 独立路由(认证页面、全屏视图)
|
||
└── GlobalComponents(模态框覆盖层、全局 UI)
|
||
```
|
||
|
||
### 路由架构(模块化设计)
|
||
路由采用**声明式**设计,并拆分到 `src/routes/` 中的多个文件:
|
||
|
||
- **index.js** - 主路由器(组合配置 + 渲染路由)
|
||
- **routeConfig.js** - 路由定义(路径、组件、保护模式、布局、子路由)
|
||
- **lazy-components.js** - React.lazy() 导入,用于代码分割
|
||
- **homeRoutes.js** - 嵌套的首页路由
|
||
- **constants/** - 保护模式、布局映射
|
||
- **utils/** - 路由渲染逻辑(wrapWithProtection、renderRoute)
|
||
|
||
路由保护模式(PROTECTION_MODES):
|
||
- `PUBLIC` - 无需认证
|
||
- `MODAL` - 未登录时显示认证模态框
|
||
- `REDIRECT` - 未登录时重定向到 /auth/sign-in
|
||
|
||
### 前端目录结构
|
||
```
|
||
src/
|
||
├── App.js - 根组件(providers + 路由)
|
||
├── providers/ - Provider 组合(AppProviders.js)
|
||
├── routes/ - 模块化路由系统(见上文)
|
||
├── layouts/ - 页面布局(MainLayout、Auth)
|
||
├── views/ - 页面组件(Community、TradingSimulation 等)
|
||
├── components/ - 可复用 UI 组件
|
||
├── contexts/ - React contexts(Auth、Notification、Sidebar)
|
||
├── store/ - Redux store + slices(auth、posthog、stock、industry 等)
|
||
├── services/ - API 层(axios 封装)
|
||
├── utils/ - 工具函数(apiConfig、priceFormatters、logger)
|
||
├── constants/ - 应用常量(animations 等)
|
||
├── hooks/ - 自定义 React hooks
|
||
├── theme/ - Chakra UI 主题定制
|
||
└── mocks/ - 开发用 MSW handlers
|
||
├── handlers/ - 按领域划分的请求处理器(auth、stock、company 等)
|
||
├── data/ - Mock 数据文件
|
||
└── browser.js - MSW 设置(当 REACT_APP_ENABLE_MOCK=true 时启动)
|
||
```
|
||
|
||
### 后端结构
|
||
```
|
||
app.py - Flask 服务器(路由、认证、业务逻辑)
|
||
simulation_background_processor.py - 交易模拟的 Celery worker
|
||
concept_api.py - 概念/行业分析 API
|
||
wechat_pay.py / wechat_pay_config.py - 微信支付集成
|
||
tdays.csv - 交易日历(启动时加载)
|
||
requirements.txt - Python 依赖
|
||
```
|
||
|
||
### 状态管理策略
|
||
- **Redux Toolkit**: 全局状态(认证模态框、posthog、股票数据、行业数据、订阅、社区数据)
|
||
- **React Context**: 跨切面关注点(AuthContext、NotificationContext、SidebarContext)
|
||
- **组件状态**: 本地 UI 状态(表单、开关等)
|
||
|
||
### 实时更新
|
||
- Flask-SocketIO 用于 WebSocket 连接
|
||
- 示例:社区事件通知通过 WebSocket 推送
|
||
- 客户端:`socket.io-client` 库
|
||
|
||
## 配置
|
||
|
||
### 环境文件
|
||
```
|
||
.env.mock - Mock 模式(默认):MSW 拦截所有 API 调用,无需后端
|
||
.env.development - 开发模式:连接到开发后端
|
||
.env.test - 测试模式:用于 'npm run start:test'(后端 + 前端一起)
|
||
.env.production - 生产环境构建配置
|
||
```
|
||
|
||
**关键环境变量:**
|
||
- `REACT_APP_ENABLE_MOCK=true` - 启用 MSW mocking
|
||
- `REACT_APP_API_URL` - 后端 URL(空字符串 = 使用相对路径或 MSW)
|
||
|
||
### MSW (Mock Service Worker) 设置
|
||
MSW 用于开发期间的 API mocking:
|
||
|
||
1. **激活方式**:在 env 文件中设置 `REACT_APP_ENABLE_MOCK=true`
|
||
2. **Worker 文件**:`public/mockServiceWorker.js`(自动生成)
|
||
3. **Handlers**:`src/mocks/handlers/`(按领域组织:auth、stock、company 等)
|
||
4. **模式**:`onUnhandledRequest: 'warn'` - 未处理的请求会传递到后端
|
||
|
||
当 MSW 激活时,开发服务器代理被禁用(MSW 优先拦截)。
|
||
|
||
### 路径别名 (craco.config.js)
|
||
所有别名解析到 `src/` 子目录:
|
||
```
|
||
@/ → src/
|
||
@assets/ → src/assets/
|
||
@components/ → src/components/
|
||
@constants/ → src/constants/
|
||
@contexts/ → src/contexts/
|
||
@data/ → src/data/
|
||
@hooks/ → src/hooks/
|
||
@layouts/ → src/layouts/
|
||
@lib/ → src/lib/
|
||
@mocks/ → src/mocks/
|
||
@providers/ → src/providers/
|
||
@routes/ → src/routes/
|
||
@services/ → src/services/
|
||
@store/ → src/store/
|
||
@styles/ → src/styles/
|
||
@theme/ → src/theme/
|
||
@utils/ → src/utils/
|
||
@variables/ → src/variables/
|
||
@views/ → src/views/
|
||
```
|
||
|
||
### Webpack 优化 (craco.config.js)
|
||
**性能特性:**
|
||
- 文件系统缓存(重新构建速度提升 50-80%)
|
||
- 按库激进的代码分割:
|
||
- `react-vendor` - React 核心(优先级 30)
|
||
- `charts-lib` - echarts、d3、apexcharts、recharts(优先级 25)
|
||
- `chakra-ui` - Chakra UI + Emotion(优先级 23)
|
||
- `antd-lib` - Ant Design(优先级 22)
|
||
- `three-lib` - Three.js(优先级 20)
|
||
- `calendar-lib` - moment、date-fns、FullCalendar(优先级 18)
|
||
- 从构建中移除 ESLint 插件(速度提升 20-30%)
|
||
- 启用 Babel 缓存
|
||
- moment locale 剥离(IgnorePlugin)
|
||
- Source maps:生产环境禁用,开发环境使用 `eval-cheap-module-source-map`
|
||
|
||
**开发服务器:**
|
||
- 端口 3000(prestart 时杀死现有进程)
|
||
- 代理(当 MSW 禁用时):`/api` → `http://49.232.185.254:5001`
|
||
- Bundle 分析器:`ANALYZE=true npm run build:analyze`
|
||
|
||
### 构建流程
|
||
1. `npm run build` 使用 CRACO + webpack 优化编译
|
||
2. Gulp 任务(`gulp licenses`)为 JS/HTML 添加 Creative Tim 许可证头
|
||
3. 输出:`build/` 目录
|
||
|
||
**Node 兼容性:**
|
||
```bash
|
||
NODE_OPTIONS='--openssl-legacy-provider --max_old_space_size=4096'
|
||
```
|
||
|
||
## 开发工作流
|
||
|
||
### 路由开发
|
||
添加新路由的步骤:
|
||
|
||
1. 在 `src/routes/lazy-components.js` 中添加 lazy import
|
||
2. 在 `src/routes/routeConfig.js` 中添加路由配置:
|
||
- `path` - URL 路径
|
||
- `component` - 来自 lazyComponents
|
||
- `protection` - MODAL/REDIRECT/PUBLIC
|
||
- `layout` - 'main'(带导航栏)或 'none'(全屏)
|
||
3. 路由自动使用 Suspense + ErrorBoundary 渲染(由 PageTransitionWrapper 处理)
|
||
|
||
### 组件组织模式
|
||
基于最近的重构(详见 README.md):
|
||
|
||
**原子设计模式:**
|
||
- **Atoms(原子)** - 基础 UI 元素(按钮、徽章、输入框)
|
||
- **Molecules(分子)** - 原子的组合(卡片、表单)
|
||
- **Organisms(有机体)** - 复杂组件(列表、面板)
|
||
|
||
**大型组件示例结构(1000+ 行):**
|
||
```
|
||
src/views/Community/components/
|
||
├── EventCard/
|
||
│ ├── index.js - 智能包装器(路由紧凑 vs 详细视图)
|
||
│ ├── CompactEventCard.js - 紧凑视图
|
||
│ ├── DetailedEventCard.js - 详细视图
|
||
│ ├── EventTimeline.js - 原子组件
|
||
│ ├── EventImportanceBadge.js - 原子组件
|
||
│ └── ...
|
||
```
|
||
|
||
**工具提取:**
|
||
- 将可复用逻辑提取到 `src/utils/`(如 `priceFormatters.js`)
|
||
- 将共享常量提取到 `src/constants/`(如 `animations.js`)
|
||
|
||
### API 集成
|
||
**服务层**(`src/services/`):
|
||
- 使用 `src/utils/apiConfig.js` 中的 `getApiBase()` 获取基础 URL
|
||
- 示例:`${getApiBase()}/api/endpoint`
|
||
- 在 mock 模式下,MSW 拦截;在开发/生产环境下,请求后端
|
||
|
||
**添加新的 API 端点:**
|
||
1. 在 `src/services/` 中添加服务函数(或在组件中内联)
|
||
2. 如果使用 MSW:在 `src/mocks/handlers/{domain}.js` 中添加 handler
|
||
3. 在 `src/mocks/handlers/index.js` 中导入 handler
|
||
|
||
### Redux 状态管理
|
||
**现有 slices**(`src/store/slices/`):
|
||
- `authModalSlice` - 认证模态框状态
|
||
- `posthogSlice` - PostHog 分析
|
||
- `stockSlice` - 股票数据
|
||
- `industrySlice` - 行业/概念数据
|
||
- `subscriptionSlice` - 用户订阅
|
||
- `communityDataSlice` - 社区内容
|
||
|
||
**添加新 slice:**
|
||
1. 创建 `src/store/slices/yourSlice.js`
|
||
2. 在 `src/store/index.js` 中导入并添加
|
||
3. 通过 `useSelector` 访问,通过 `useDispatch` 派发
|
||
|
||
## 后端架构
|
||
|
||
### Flask 应用 (app.py)
|
||
- **认证**: Flask-Login + session 管理
|
||
- **数据库**: SQLAlchemy 模型 + ClickHouse 客户端
|
||
- **后台任务**: Celery 任务用于异步处理
|
||
- **实时通信**: Flask-SocketIO 用于 WebSocket 事件
|
||
- **交易日**: `tdays.csv` 在启动时加载到内存(全局 `trading_days` 变量)
|
||
|
||
### 后端关键模式
|
||
- **ClickHouse**: 用于高容量分析查询(股票数据、时间序列)
|
||
- **MySQL/PostgreSQL**: 用于事务性数据(用户、订单、订阅)
|
||
- **Celery**: 后台处理器在单独进程中运行(`simulation_background_processor.py`)
|
||
- **CORS**: 已启用,用于前端通信
|
||
|
||
### API 代理配置
|
||
非 mock 模式时,前端代理到后端:
|
||
- `/api` → `http://49.232.185.254:5001`(主 API)
|
||
- `/concept-api` → `http://49.232.185.254:6801`(概念分析 API)
|
||
|
||
## 重要说明
|
||
|
||
### 代码分割策略
|
||
重量级页面进行懒加载以减小初始 bundle 大小:
|
||
- Community、TradingSimulation、Company 页面使用 `React.lazy()`
|
||
- Webpack 将大型库拆分为独立 chunks
|
||
- 使用 `npm run build:analyze` 检查 bundle 大小
|
||
|
||
### 错误边界
|
||
- **布局级**:每个布局(MainLayout、Auth)都有自己的 ErrorBoundary
|
||
- **页面级**:PageTransitionWrapper 为每个路由包裹 ErrorBoundary
|
||
- **策略**:错误被隔离,防止整个应用崩溃
|
||
|
||
### PostHog 分析
|
||
- 在 Redux 中初始化(`posthogSlice`)
|
||
- 在 `App.js` 中应用启动时配置
|
||
- 用于用户行为追踪
|
||
|
||
### 性能考虑
|
||
- **大型组件**:如果组件超过 ~500 行,考虑重构(见 README.md)
|
||
- **重渲染**:对昂贵操作使用 `React.memo`、`useMemo`、`useCallback`
|
||
- **Bundle 大小**:使用 webpack-bundle-analyzer 监控
|
||
- **缓存**:Webpack 文件系统缓存显著加速重新构建
|
||
|
||
---
|
||
|
||
## 技术路径与开发指南
|
||
|
||
本章节定义了项目的技术方向、架构原则和开发标准。所有开发工作都应遵循这些指南。
|
||
|
||
### 技术栈决策与演进路线
|
||
|
||
#### 当前技术选型及理由
|
||
|
||
**前端框架栈:**
|
||
- **React 18.3.1**: 成熟的生态系统、并发渲染特性、广泛的社区支持
|
||
- **Chakra UI 2.8.2**: 主UI库,优先考虑可访问性、主题定制能力强、基于 Emotion 的样式系统
|
||
- **Ant Design**: 辅助UI库,用于复杂的数据密集型组件(表格、表单),弥补 Chakra UI 的不足
|
||
- **Redux Toolkit**: 可预测的全局状态管理、优秀的 DevTools 集成、完善的 TypeScript 支持
|
||
|
||
**构建与开发工具:**
|
||
- **CRACO**: 允许在不 eject 的情况下自定义 webpack 配置
|
||
- **MSW (Mock Service Worker)**: 在网络层进行 API mock,提供更真实的开发体验,加快开发迭代
|
||
- **Webpack 5**: 利用文件系统缓存,重新构建速度提升 50-80%
|
||
|
||
**图表库(多库策略):**
|
||
- **ApexCharts**: 主要用于金融/交易图表(K线图、折线图)
|
||
- **ECharts**: 用于复杂的交互式可视化和大数据集渲染
|
||
- **Recharts**: 轻量级选项,用于仪表板中的简单图表
|
||
- **D3.js**: 底层控制,用于自定义可视化
|
||
- **选型理由**: 不同图表类型有不同的最优库,多库策略提供灵活性
|
||
|
||
**后端技术栈:**
|
||
- **Flask + SQLAlchemy**: Python 生态系统与金融/数据科学工作流契合度高
|
||
- **ClickHouse**: 针对时序分析查询优化(股票数据、交易指标)
|
||
- **MySQL/PostgreSQL**: 传统关系型数据库,用于事务性数据,提供 ACID 保证
|
||
- **Celery + Redis**: 处理长时间运行的后台任务(交易模拟、报表生成)
|
||
|
||
#### 计划中的技术演进
|
||
|
||
**短期(未来 3-6 个月):**
|
||
- **React Query / TanStack Query**: 逐步从 Redux 迁移到 React Query 管理服务端状态
|
||
- 优势: 自动缓存、后台自动刷新、乐观更新
|
||
- 策略: 从新功能开始,然后迁移现有 API 调用
|
||
- Redux 将继续用于客户端状态(UI 状态、模态框等)
|
||
|
||
- **Vite 迁移**: 考虑从 CRACO/webpack 迁移到 Vite,提升开发体验
|
||
- 优势: HMR 速度提升 10-50 倍,配置更简单
|
||
- 风险: 可能需要大量重构构建配置
|
||
- 决策节点: React Query 迁移稳定后
|
||
|
||
**中期(6-12 个月):**
|
||
- **React 19**: 生态系统稳定后升级
|
||
- 关注点: Chakra UI 和 Ant Design 的兼容性
|
||
- 新特性利用: Server Components(如适用)、改进的 Suspense
|
||
|
||
- **TypeScript 迁移**: 逐步为关键路径添加 TypeScript
|
||
- 优先级: API 服务层 → Redux slices → 共享组件 → 视图组件
|
||
- 新文件使用 `.ts`/`.tsx`,遗留代码保持 `.js`/`.jsx`(渐进式迁移)
|
||
|
||
**长期(12+ 个月):**
|
||
- **Monorepo 结构**: 如果项目规模扩大,考虑 Nx 或 Turborepo
|
||
- **微前端架构**: 如果团队规模扩大,考虑模块联邦(Module Federation)
|
||
|
||
#### 废弃/避免使用的技术
|
||
|
||
- **Moment.js**: 正在逐步淘汰,改用 `date-fns` 或原生 `Intl.DateTimeFormat`
|
||
- 当前已配置 webpack `IgnorePlugin` 以移除 locale 文件
|
||
- 新的日期处理代码请使用 `date-fns`
|
||
|
||
- **jQuery**: 新代码中禁止使用(与 React 虚拟 DOM 冲突)
|
||
|
||
- **Class 组件**: 所有新组件必须使用函数式组件 + Hooks
|
||
|
||
### 架构设计原则
|
||
|
||
#### 1. 组件设计原则
|
||
|
||
**原子设计层级:**
|
||
```
|
||
原子组件 (Atoms, 1-50 行)
|
||
↓ 组合成
|
||
分子组件 (Molecules, 50-150 行)
|
||
↓ 组合成
|
||
有机体组件 (Organisms, 150-500 行)
|
||
↓ 组合成
|
||
模板/视图 (Templates/Views, 500+ 行,但主要是组合)
|
||
```
|
||
|
||
**单一职责原则:**
|
||
- 每个组件应该只做一件事,并做好
|
||
- 如果组件超过 500 行,很可能做了太多事情 → 需要重构
|
||
- 将逻辑提取到自定义 hooks、工具函数或子组件中
|
||
|
||
**组合优于配置:**
|
||
```jsx
|
||
// 推荐: 可组合
|
||
<Card>
|
||
<CardHeader>标题</CardHeader>
|
||
<CardBody>内容</CardBody>
|
||
</Card>
|
||
|
||
// 避免: 过多的 props
|
||
<Card title="标题" body="内容" showBorder={true} theme="dark" />
|
||
```
|
||
|
||
**就近原则(Co-location):**
|
||
```
|
||
ComponentName/
|
||
├── index.js - 主导出文件
|
||
├── ComponentName.js - 实现代码
|
||
├── ComponentName.test.js - 测试
|
||
├── hooks/ - 组件专用 hooks
|
||
│ └── useComponentLogic.js
|
||
├── utils.js - 组件专用工具函数
|
||
└── constants.js - 组件专用常量
|
||
```
|
||
|
||
#### 2. 状态管理决策树
|
||
|
||
使用此决策树确定状态应该存储在哪里:
|
||
|
||
```
|
||
是否是服务端数据(来自 API)?
|
||
├─ 是 → 使用 React Query(或暂时使用 Redux,后续迁移)
|
||
│
|
||
└─ 否 → 是否需要在多个不相关的组件间共享?
|
||
├─ 是 → 是否是 UI 状态(模态框、侧边栏开关等)?
|
||
│ ├─ 是 → Redux (authModalSlice, sidebarSlice 等)
|
||
│ └─ 否 → React Context (AuthContext, NotificationContext)
|
||
│
|
||
└─ 否 → 是否需要在父组件和多个子组件间共享?
|
||
├─ 是 → 状态提升到共同父组件,通过 props 传递
|
||
└─ 否 → 本地组件状态 (useState, useReducer)
|
||
```
|
||
|
||
**状态管理规则:**
|
||
- **Redux**: 全局 UI 状态、跨切面关注点、需要在路由切换间保持的状态
|
||
- **Context**: 依赖注入(主题、认证)、避免属性透传,适合稳定值
|
||
- **组件状态**: 表单输入、开关、本地 UI 状态(下拉菜单、标签页)
|
||
- **React Query**(未来): 所有服务端状态、API 缓存、数据变更
|
||
|
||
**性能规则:**
|
||
- 如果 Context 值频繁变化,拆分为多个 Context 或使用 Redux
|
||
- 在 Context 边界使用 `React.memo` 防止不必要的重渲染
|
||
|
||
#### 3. 代码分割策略
|
||
|
||
**路由级分割(主要策略):**
|
||
- 所有主要视图在 `src/routes/lazy-components.js` 中使用 `React.lazy()`
|
||
- 重量级页面(Community、TradingSimulation、Company)始终懒加载
|
||
- 认证页面可以懒加载(不在关键路径上)
|
||
|
||
**库级分割(webpack):**
|
||
- 已在 `craco.config.js` 中配置
|
||
- 大型库独立打包:charts、Three.js、Chakra、Ant Design
|
||
- 关键规则: 保持初始 bundle < 500KB gzipped
|
||
|
||
**组件级分割(选择性使用):**
|
||
- 仅用于真正重量级且条件渲染的组件(如 3D 可视化)
|
||
```jsx
|
||
const HeavyChart = lazy(() => import('./HeavyChart'));
|
||
// 仅在需要时渲染
|
||
{showChart && <Suspense fallback={<Spinner />}><HeavyChart /></Suspense>}
|
||
```
|
||
|
||
#### 4. API 层设计模式
|
||
|
||
**服务层架构:**
|
||
```
|
||
组件 (Component)
|
||
↓ 调用
|
||
自定义 Hook (useStockData)
|
||
↓ 使用
|
||
服务函数 (src/services/stockService.js)
|
||
↓ 调用
|
||
Axios 实例(配置了 baseURL、拦截器)
|
||
↓ 请求
|
||
后端 API 或 MSW Mock
|
||
```
|
||
|
||
**API 服务模板:**
|
||
```javascript
|
||
// src/services/exampleService.js
|
||
import axios from 'axios';
|
||
import { getApiBase } from '@utils/apiConfig';
|
||
|
||
const api = axios.create({
|
||
baseURL: getApiBase(),
|
||
timeout: 10000,
|
||
});
|
||
|
||
// 请求拦截器(添加认证 token)
|
||
api.interceptors.request.use(config => {
|
||
const token = localStorage.getItem('token');
|
||
if (token) config.headers.Authorization = `Bearer ${token}`;
|
||
return config;
|
||
});
|
||
|
||
// 响应拦截器(全局错误处理)
|
||
api.interceptors.response.use(
|
||
response => response.data,
|
||
error => {
|
||
// 全局错误处理
|
||
console.error('API Error:', error);
|
||
return Promise.reject(error);
|
||
}
|
||
);
|
||
|
||
export const fetchExample = async (id) => {
|
||
return api.get(`/api/example/${id}`);
|
||
};
|
||
```
|
||
|
||
**MSW Mock Handler 模板:**
|
||
```javascript
|
||
// src/mocks/handlers/example.js
|
||
import { http, HttpResponse } from 'msw';
|
||
|
||
export const exampleHandlers = [
|
||
http.get('/api/example/:id', ({ params }) => {
|
||
return HttpResponse.json({
|
||
id: params.id,
|
||
data: 'mock data',
|
||
});
|
||
}),
|
||
];
|
||
```
|
||
|
||
#### 5. 错误处理架构
|
||
|
||
**三层错误边界策略:**
|
||
```
|
||
App.js(根组件)
|
||
↓ 捕获致命错误(显示降级 UI,记录到监控服务)
|
||
布局 (MainLayout, AuthLayout)
|
||
↓ 捕获布局特定错误(显示错误页面,允许重试)
|
||
页面(通过 PageTransitionWrapper 包裹的各个路由)
|
||
↓ 捕获页面特定错误(显示错误消息,允许导航)
|
||
```
|
||
|
||
**API 错误处理模式:**
|
||
```javascript
|
||
try {
|
||
const data = await fetchData();
|
||
// 处理成功情况
|
||
} catch (error) {
|
||
if (error.response?.status === 401) {
|
||
// 跳转到登录页
|
||
} else if (error.response?.status === 403) {
|
||
// 显示权限错误
|
||
} else {
|
||
// 显示通用错误
|
||
showNotification('数据加载失败', 'error');
|
||
}
|
||
}
|
||
```
|
||
|
||
### 开发规范与最佳实践
|
||
|
||
#### 1. 组件开发规范
|
||
|
||
**文件命名约定:**
|
||
- 组件: `PascalCase.js` (如 `EventCard.js`)
|
||
- 工具函数: `camelCase.js` (如 `priceFormatters.js`)
|
||
- 常量: `SCREAMING_SNAKE_CASE.js` 或 `camelCase.js` (如 `API_ENDPOINTS.js`, `animations.js`)
|
||
- Hooks: `useCamelCase.js` (如 `useStockData.js`)
|
||
|
||
**组件文件结构:**
|
||
```javascript
|
||
// 1. 导入(分组并排序)
|
||
import React, { useState, useEffect } from 'react';
|
||
import { Box, Text } from '@chakra-ui/react';
|
||
import { useDispatch } from 'react-redux';
|
||
import PropTypes from 'prop-types';
|
||
import { CustomComponent } from '@components/CustomComponent';
|
||
import { useCustomHook } from '@hooks/useCustomHook';
|
||
import { helperFunction } from './utils';
|
||
|
||
// 2. 常量(组件专用)
|
||
const DEFAULT_VALUE = 10;
|
||
|
||
// 3. 组件定义
|
||
export const MyComponent = ({ prop1, prop2 }) => {
|
||
// 3a. Hooks(按类型分组)
|
||
const dispatch = useDispatch();
|
||
const [state, setState] = useState(DEFAULT_VALUE);
|
||
const customValue = useCustomHook();
|
||
|
||
// 3b. 副作用
|
||
useEffect(() => {
|
||
// 副作用逻辑
|
||
}, []);
|
||
|
||
// 3c. 事件处理器
|
||
const handleClick = () => {
|
||
setState(prev => prev + 1);
|
||
};
|
||
|
||
// 3d. 渲染逻辑
|
||
return (
|
||
<Box>
|
||
<Text>{state}</Text>
|
||
</Box>
|
||
);
|
||
};
|
||
|
||
// 4. PropTypes(或 TypeScript 类型)
|
||
MyComponent.propTypes = {
|
||
prop1: PropTypes.string.isRequired,
|
||
prop2: PropTypes.number,
|
||
};
|
||
|
||
// 5. 默认 Props
|
||
MyComponent.defaultProps = {
|
||
prop2: 0,
|
||
};
|
||
```
|
||
|
||
**Props 设计指南:**
|
||
- 在组件参数中使用对象解构
|
||
- 必需的 props 在前,可选的 props 在后
|
||
- 布尔类型 props 使用 `is`、`has`、`should` 前缀(如 `isLoading`、`hasError`)
|
||
- 回调函数使用 `onEventName` 格式(如 `onClick`、`onSubmit`)
|
||
- 避免传递整个对象,只传递需要的几个属性
|
||
|
||
**性能优化检查清单:**
|
||
- [ ] 昂贵的计算是否用 `useMemo` 包裹?
|
||
- [ ] 传递给子组件的回调函数是否用 `useCallback` 包裹?
|
||
- [ ] 列表项是否使用唯一且稳定的 `key` props(不是数组索引)?
|
||
- [ ] 大型列表是否虚拟化(react-window 或 react-virtuoso)?
|
||
- [ ] 频繁接收 prop 更新的组件是否用 `React.memo` 包裹?
|
||
- [ ] 图片是否懒加载(`loading="lazy"`)?
|
||
|
||
#### 2. Hooks 开发规范
|
||
|
||
**自定义 Hook 规则:**
|
||
- 必须以 `use` 前缀开头
|
||
- 应该在多个组件间可复用
|
||
- 应该处理一个特定关注点(数据获取、表单状态等)
|
||
- 应该返回对象或数组(不直接返回原始值)
|
||
|
||
**自定义 Hook 模板:**
|
||
```javascript
|
||
// src/hooks/useStockData.js
|
||
import { useState, useEffect } from 'react';
|
||
import { fetchStockData } from '@services/stockService';
|
||
|
||
export const useStockData = (stockId) => {
|
||
const [data, setData] = useState(null);
|
||
const [loading, setLoading] = useState(false);
|
||
const [error, setError] = useState(null);
|
||
|
||
useEffect(() => {
|
||
if (!stockId) return;
|
||
|
||
let isMounted = true;
|
||
setLoading(true);
|
||
|
||
fetchStockData(stockId)
|
||
.then(result => {
|
||
if (isMounted) {
|
||
setData(result);
|
||
setError(null);
|
||
}
|
||
})
|
||
.catch(err => {
|
||
if (isMounted) {
|
||
setError(err);
|
||
}
|
||
})
|
||
.finally(() => {
|
||
if (isMounted) setLoading(false);
|
||
});
|
||
|
||
return () => {
|
||
isMounted = false;
|
||
};
|
||
}, [stockId]);
|
||
|
||
return { data, loading, error };
|
||
};
|
||
```
|
||
|
||
#### 3. Git 工作流与提交规范
|
||
|
||
**分支命名约定:**
|
||
```
|
||
feature/简短描述 - 新功能
|
||
fix/bug描述 - Bug 修复
|
||
refactor/组件名称 - 代码重构
|
||
docs/变更内容 - 文档更新
|
||
chore/任务描述 - 维护任务
|
||
```
|
||
|
||
**提交信息格式:**
|
||
```
|
||
<类型>(<范围>): <主题>
|
||
|
||
<正文>
|
||
|
||
<脚注>
|
||
```
|
||
|
||
**类型:**
|
||
- `feat`: 新功能
|
||
- `fix`: Bug 修复
|
||
- `refactor`: 既不修复 Bug 也不添加功能的代码更改
|
||
- `style`: 代码风格更改(格式化、缺少分号等)
|
||
- `docs`: 文档更改
|
||
- `test`: 添加或更新测试
|
||
- `chore`: 维护任务(依赖、构建配置等)
|
||
|
||
**示例:**
|
||
```
|
||
feat(community): 添加按日期范围筛选事件功能
|
||
|
||
实现了日期范围选择器用于筛选事件。
|
||
添加了 Redux slice 用于筛选状态管理。
|
||
|
||
Closes #123
|
||
|
||
---
|
||
|
||
fix(trading): 修正模拟交易中的利润计算
|
||
|
||
修复了导致盈亏显示不正确的浮点精度问题。
|
||
|
||
---
|
||
|
||
refactor(components): 将 EventCard 拆分为原子组件
|
||
|
||
将 1200 行的 EventCard 拆分为:
|
||
- CompactEventCard
|
||
- DetailedEventCard
|
||
- EventTimeline (原子组件)
|
||
- EventImportanceBadge (原子组件)
|
||
```
|
||
|
||
**代码审查检查清单:**
|
||
- [ ] 代码是否遵循组件结构指南?
|
||
- [ ] 是否有超过 500 行应该拆分的组件?
|
||
- [ ] 状态管理是否合适(Redux vs Context vs Local)?
|
||
- [ ] 是否存在性能问题(不必要的重渲染、缺少记忆化)?
|
||
- [ ] 新功能是否有错误边界?
|
||
- [ ] 错误处理是否全面(API 错误、边界情况)?
|
||
- [ ] 新的 API 是否在 MSW 中 mock 以便开发?
|
||
- [ ] 是否定义了 PropTypes 或 TypeScript 类型?
|
||
- [ ] 代码是否具有可访问性(ARIA 标签、键盘导航)?
|
||
- [ ] 是否有 console 错误或警告?
|
||
|
||
### 技术债务与已知问题
|
||
|
||
本节跟踪技术债务、性能问题和计划中的重构工作。发现或解决问题时请更新此列表。
|
||
|
||
#### 高优先级技术债务
|
||
|
||
**1. Redux 到 React Query 迁移**
|
||
- **状态**: 已计划
|
||
- **影响**: 高 - 影响所有 API 调用
|
||
- **时间线**: 2025 年 Q2 开始
|
||
- **描述**: 将服务端状态从 Redux 迁移到 React Query,以获得更好的缓存、自动重新获取和减少样板代码
|
||
- **受影响文件**: `src/store/slices/*Slice.js`、整个应用中的 API 服务调用
|
||
- **迁移策略**:
|
||
1. 在 `AppProviders.js` 中设置 React Query provider
|
||
2. 创建 `src/queries/` 目录存放 query hooks
|
||
3. 一次迁移一个领域(从 Community 或 Stock 数据开始)
|
||
4. Redux 保留用于 UI 状态(模态框、侧边栏等)
|
||
|
||
**2. 大型组件重构**
|
||
- **状态**: 进行中
|
||
- **影响**: 中 - 可维护性和可读性
|
||
- **需要重构的组件**:
|
||
- 任何超过 500 行的新组件
|
||
- 审查 `src/views/` 中的组件,寻找潜在的拆分机会
|
||
- **遵循模式**: 参见上面的"组件组织模式"章节
|
||
|
||
**3. TypeScript 渐进式迁移**
|
||
- **状态**: 已计划
|
||
- **影响**: 高 - 类型安全、减少运行时错误
|
||
- **时间线**: 2025 年 Q3 开始
|
||
- **迁移顺序**:
|
||
1. `src/utils/` (工具函数 - 最容易添加类型)
|
||
2. `src/services/` (API 层 - 高价值)
|
||
3. `src/store/` (Redux slices - 中等价值)
|
||
4. `src/components/` (共享组件)
|
||
5. `src/views/` (页面组件 - 最后)
|
||
|
||
#### 中优先级技术债务
|
||
|
||
**4. Webpack 到 Vite 迁移**
|
||
- **状态**: 评估中
|
||
- **影响**: 高 - 开发体验
|
||
- **好处**: HMR 速度提升 10-50 倍,配置更简单
|
||
- **风险**: 可能需要大量重构构建配置、CRACO 自定义配置
|
||
- **决策节点**: React Query 迁移完成后
|
||
|
||
**5. Moment.js 替换**
|
||
- **状态**: 进行中(已配置移除 locale 文件)
|
||
- **影响**: 低 - bundle 大小减少(约 20KB)
|
||
- **策略**: 新代码中用 `date-fns` 替换 `moment()`,现有代码逐步迁移
|
||
- **使用 moment.js 的文件**: 搜索 `import moment` 以识别
|
||
|
||
**6. 统一错误处理**
|
||
- **状态**: 需要改进
|
||
- **影响**: 中 - 用户体验、调试
|
||
- **问题**:
|
||
- 部分 API 调用缺少错误处理
|
||
- 错误边界使用不一致
|
||
- 某些地方的错误消息对用户不友好
|
||
- **行动项**:
|
||
- 审计所有 API 调用的错误处理
|
||
- 为所有主要视图添加错误边界
|
||
- 标准化错误消息显示(NotificationContext)
|
||
|
||
#### 低优先级技术债务
|
||
|
||
**7. 测试覆盖率**
|
||
- **状态**: 不足
|
||
- **影响**: 中 - 变更信心
|
||
- **当前覆盖率**: 未知(需要测量)
|
||
- **目标**: 关键路径 60%+ 覆盖率
|
||
- **优先区域**:
|
||
1. 工具函数(易于测试、高价值)
|
||
2. Redux slices(状态管理逻辑)
|
||
3. 自定义 hooks(可复用逻辑)
|
||
4. 关键 UI 流程(认证、交易模拟)
|
||
|
||
**8. Bundle 大小优化**
|
||
- **状态**: 持续监控中
|
||
- **影响**: 低 - 加载时间
|
||
- **当前大小**: 使用 `npm run build:analyze` 检查
|
||
- **优化机会**:
|
||
- 移除未使用的依赖
|
||
- Tree-shake 大型库(lodash → lodash-es)
|
||
- 考虑懒加载 Three.js 和其他重量级库
|
||
|
||
#### 已知问题与限制
|
||
|
||
**性能:**
|
||
- **Community 视图中的大型事件列表**: 如果列表超过 100 项,考虑虚拟化(react-window)
|
||
- **图表重渲染**: ApexCharts 在大数据集时可能较慢;考虑节流数据更新
|
||
|
||
**浏览器兼容性:**
|
||
- **不支持 IE11**: 现代 JavaScript 特性需要 polyfills 才能支持旧浏览器
|
||
- **Safari 兼容性**: 某些 Chakra UI 动画在 Safari 中行为可能不同
|
||
|
||
**移动端响应式:**
|
||
- **交易模拟**: 复杂表格在移动端未完全优化
|
||
- **图表**: 可能需要改进触摸事件处理
|
||
|
||
**数据/API:**
|
||
- **实时 WebSocket**: 连接断开时不总是能优雅处理;需添加重连逻辑
|
||
- **ClickHouse 查询**: 大日期范围的某些分析查询可能较慢;考虑分页或聚合
|
||
|
||
---
|
||
|
||
## 更新本文档
|
||
|
||
本 CLAUDE.md 文件是一个持续更新的文档。在以下情况下应更新它:
|
||
- 添加新的架构模式或指南
|
||
- 发现新的最佳实践
|
||
- 解决或添加技术债务项
|
||
- 做出重要的技术决策
|
||
|
||
所有开发人员应在入职时审查本文档,并在做出架构决策时参考它。 |