518 lines
13 KiB
Markdown
518 lines
13 KiB
Markdown
# CLAUDE.md
|
||
|
||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||
|
||
---
|
||
|
||
# React Arco Design Pro 项目指南
|
||
|
||
## 项目概述
|
||
|
||
这是一个基于 React 17 + Arco Design + TypeScript + Vite 的企业级中后台管理系统模板项目。项目采用前后端分离架构,使用 Redux 进行状态管理,使用 Mock.js 模拟后端数据。
|
||
|
||
## 常用命令
|
||
|
||
### 开发与构建
|
||
|
||
```bash
|
||
# 启动开发服务器(推荐)
|
||
npm run dev
|
||
# 或
|
||
npm start
|
||
|
||
# 生产环境构建
|
||
npm run build
|
||
|
||
# 预览生产构建
|
||
npm run preview
|
||
```
|
||
|
||
### 代码质量检查
|
||
|
||
```bash
|
||
# ESLint 检查并自动修复
|
||
npm run eslint
|
||
|
||
# Stylelint 检查并自动修复
|
||
npm run stylelint
|
||
|
||
# Git 提交前检查(自动执行)
|
||
npm run pre-commit
|
||
```
|
||
|
||
**注意**: 建议在 `.eslintrc.js` 中配置规则,禁止在响应码判断时使用严格相等:
|
||
|
||
```javascript
|
||
// 可选:配置 ESLint 规则提醒
|
||
rules: {
|
||
// 其他规则...
|
||
// 在代码审查时人工检查响应码判断逻辑
|
||
}
|
||
```
|
||
|
||
### 包管理
|
||
|
||
项目使用 pnpm 作为包管理器,但 npm/yarn 也兼容。建议使用 pnpm 以保持依赖一致性。
|
||
|
||
## 核心架构设计
|
||
|
||
### 技术栈核心
|
||
|
||
- **构建工具**: Vite 2.6.14(快速 HMR,基于 ESM)
|
||
- **UI 框架**: React 17.0.2
|
||
- **UI 组件库**: @arco-design/web-react 2.32.2(字节跳动开源)
|
||
- **状态管理**: Redux 4.1.2(传统模式,非 Redux Toolkit)
|
||
- **路由**: React Router 5.2.0
|
||
- **HTTP 客户端**: Axios 0.24.0
|
||
- **CSS 预处理**: Less 4.1.2
|
||
- **类型系统**: TypeScript 4.5.2(strict: false)
|
||
|
||
### 架构分层
|
||
|
||
```
|
||
src/
|
||
├── pages/ # 页面组件(按功能模块组织,支持懒加载)
|
||
├── components/ # 公共组件(NavBar, TabBar, Footer 等)
|
||
├── layout.tsx # 主布局组件(侧边栏、标签页、内容区)
|
||
├── routes.ts # 路由配置 + 权限过滤逻辑
|
||
├── store/ # Redux 状态管理(settings, userInfo, tabs)
|
||
├── utils/ # 工具函数(认证、主题、国际化等)
|
||
├── mock/ # Mock.js 数据模拟
|
||
├── locale/ # 国际化资源文件
|
||
└── main.tsx # 应用入口
|
||
```
|
||
|
||
### 关键架构模式
|
||
|
||
#### 1. 路由懒加载机制
|
||
|
||
- 使用 `import.meta.glob()` 动态导入页面组件
|
||
- 通过 `@loadable/component` 实现代码分割
|
||
- 路由配置在 `src/routes.ts`,约定式路由:`./pages/${route.key}/index.tsx`
|
||
|
||
#### 2. 权限控制系统
|
||
|
||
- **路由级权限**: `routes.ts` 中的 `useRoute` Hook 根据用户权限过滤路由
|
||
- **组件级权限**: 使用 `<PermissionWrapper>` 组件包裹需要权限控制的元素
|
||
- **权限验证**: `utils/authentication.ts` 提供权限判断逻辑
|
||
- **角色系统**: 简单的 Admin/User 角色,权限存储在 Redux Store
|
||
|
||
#### 3. 状态管理架构
|
||
|
||
Redux Store 管理三类全局状态:
|
||
|
||
```typescript
|
||
// src/store/index.ts
|
||
GlobalState {
|
||
settings: { // 系统设置(主题色、布局配置)
|
||
themeColor,
|
||
navbar,
|
||
menu,
|
||
footer
|
||
},
|
||
userInfo: { // 用户信息
|
||
name,
|
||
avatar,
|
||
permissions // 权限映射表
|
||
},
|
||
tabs: { // 多标签页状态
|
||
activeKey,
|
||
tabs[]
|
||
}
|
||
}
|
||
```
|
||
|
||
**重要**: Redux 使用传统模式(非 Redux Toolkit),所有 Action 通过字符串类型派发。
|
||
|
||
#### 4. 主题系统
|
||
|
||
- **主题配置**: `src/settings.json` 定义默认主题色
|
||
- **主题切换**: `utils/changeTheme.ts` 切换明暗模式
|
||
- **色值计算**: `utils/initThemeColor.ts` 根据主题色自动生成 10 个梯度色
|
||
- **Vite 集成**: `vite.config.ts` 通过 `@arco-plugins/vite-react` 注入主题变量
|
||
|
||
#### 5. 多标签页系统
|
||
|
||
标签页状态由 Redux 管理,支持:
|
||
|
||
- 添加/关闭标签页(`tabs/addTab`, `tabs/removeTab`)
|
||
- 切换标签页(`tabs/setActiveTab`)
|
||
- 右键菜单操作(关闭左侧/右侧/其他)
|
||
|
||
标签页与路由联动,在 `layout.tsx` 中实现。
|
||
|
||
### 数据流设计
|
||
|
||
```
|
||
用户交互 → Component
|
||
↓
|
||
dispatch Redux Action
|
||
↓
|
||
Reducer 更新 Store
|
||
↓
|
||
useSelector 订阅变化
|
||
↓
|
||
Component 重新渲染
|
||
```
|
||
|
||
HTTP 请求流:
|
||
|
||
```
|
||
Component → axios → Mock.js (开发环境) / Backend API (生产环境) → Component State/Redux
|
||
```
|
||
|
||
### 路径别名配置
|
||
|
||
```typescript
|
||
// 在代码中使用 @/ 代替 src/
|
||
import utils from '@/utils/xxx';
|
||
```
|
||
|
||
配置位置:
|
||
|
||
- `tsconfig.json`: `"@/*": ["src/*"]`
|
||
- `vite.config.ts`: `alias: [{ find: '@', replacement: '/src' }]`
|
||
|
||
## API 开发规范
|
||
|
||
### 响应码处理规范
|
||
|
||
**【重要】必须使用宽松相等判断响应码,避免类型不一致问题**
|
||
|
||
#### 问题背景
|
||
|
||
后端不同接口可能返回不同类型的响应码:
|
||
|
||
- 部分接口返回字符串 `"0"`
|
||
- 部分接口返回数字 `0`
|
||
|
||
使用严格相等 `===` 判断时会导致类型不匹配,即使业务成功也会被判断为失败。
|
||
|
||
#### 强制规范
|
||
|
||
**1. 在所有业务代码中判断响应码时,必须使用宽松相等 `==`**
|
||
|
||
```typescript
|
||
// ✅ 正确:使用宽松相等
|
||
if (result.code == SUCCESS_CODE) {
|
||
// 处理成功逻辑
|
||
}
|
||
|
||
if (result.code == 0) {
|
||
// 处理成功逻辑
|
||
}
|
||
|
||
// ❌ 错误:使用严格相等
|
||
if (result.code === SUCCESS_CODE) {
|
||
// 可能导致字符串 "0" !== 数字 0
|
||
// 处理成功逻辑
|
||
}
|
||
```
|
||
|
||
**2. 响应拦截器中必须使用宽松相等**
|
||
|
||
在 `src/utils/request.ts` 响应拦截器中:
|
||
|
||
```typescript
|
||
// ✅ 正确
|
||
if (data.code == SUCCESS_CODE) {
|
||
return response;
|
||
}
|
||
|
||
// ❌ 错误
|
||
if (data.code === SUCCESS_CODE) {
|
||
return response;
|
||
}
|
||
```
|
||
|
||
**3. 类型守卫函数中必须使用宽松相等**
|
||
|
||
在 `src/types/api.ts` 中:
|
||
|
||
```typescript
|
||
// ✅ 正确
|
||
export function isSuccessResponse<T>(response: R<T>): boolean {
|
||
return response.code == 0;
|
||
}
|
||
|
||
// ❌ 错误
|
||
export function isSuccessResponse<T>(response: R<T>): boolean {
|
||
return response.code === 0;
|
||
}
|
||
```
|
||
|
||
#### 适用范围
|
||
|
||
以下场景必须遵守此规范:
|
||
|
||
1. **登录处理** (`src/pages/login/form.tsx`)
|
||
2. **用户信息页面** (`src/pages/user-info/index.tsx`)
|
||
3. **用户管理页面** (`src/pages/user-management/`)
|
||
4. **所有调用后端 API 的业务代码**
|
||
5. **所有自定义的响应处理工具函数**
|
||
|
||
#### 常量定义
|
||
|
||
在 `src/constants/index.ts` 中:
|
||
|
||
```typescript
|
||
// 响应码定义为数字类型(推荐)
|
||
export const SUCCESS_CODE = 0;
|
||
export const ERROR_CODE = 1;
|
||
```
|
||
|
||
#### 检查清单
|
||
|
||
在编写或修改 API 调用代码时,必须检查:
|
||
|
||
- [ ] 所有 `result.code === xxx` 改为 `result.code == xxx`
|
||
- [ ] 所有 `response.code === xxx` 改为 `response.code == xxx`
|
||
- [ ] 响应拦截器使用宽松相等判断
|
||
- [ ] 工具函数使用宽松相等判断
|
||
|
||
#### 历史问题记录
|
||
|
||
**问题日期**: 2025-11-17
|
||
|
||
**问题描述**: 登录功能失效,用户管理页面空白
|
||
|
||
**根本原因**:
|
||
|
||
- 后端登录接口返回 `code: "0"` (字符串)
|
||
- 前端使用 `result.code === 0` (严格相等判断数字)
|
||
- 导致 `"0" !== 0`,成功响应被判断为失败
|
||
|
||
**解决方案**:
|
||
|
||
1. 将所有 `===` 改为 `==` 进行宽松相等判断
|
||
2. 修改了以下文件:
|
||
- `src/utils/request.ts`
|
||
- `src/pages/login/form.tsx`
|
||
- `src/pages/user-info/index.tsx`
|
||
- `src/pages/user-management/UserFormModal.tsx`
|
||
- `src/pages/user-management/index.tsx`
|
||
- `src/types/api.ts`
|
||
|
||
**预防措施**: 制定本规范文档,在代码审查时强制检查
|
||
|
||
### API 调用最佳实践
|
||
|
||
```typescript
|
||
// 1. 标准 API 调用模式
|
||
async function fetchData() {
|
||
try {
|
||
const result = await apiFunction(params);
|
||
|
||
// ✅ 使用宽松相等判断
|
||
if (result.code == SUCCESS_CODE) {
|
||
// 处理成功逻辑
|
||
setData(result.data);
|
||
}
|
||
// 错误消息已在拦截器中显示,无需额外处理
|
||
} catch (error) {
|
||
console.error('请求失败:', error);
|
||
// 异常已在拦截器中提示,此处仅需记录日志
|
||
}
|
||
}
|
||
|
||
// 2. 带加载状态的 API 调用
|
||
async function handleSubmit() {
|
||
try {
|
||
setLoading(true);
|
||
const result = await apiFunction(params);
|
||
|
||
if (result.code == SUCCESS_CODE) {
|
||
Message.success('操作成功');
|
||
onSuccess();
|
||
}
|
||
} catch (error) {
|
||
console.error('操作失败:', error);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
}
|
||
```
|
||
|
||
## 关键开发约定
|
||
|
||
### 页面组件开发
|
||
|
||
1. **文件位置**: 所有页面放在 `src/pages/{module-name}/index.tsx`
|
||
2. **路由注册**: 在 `src/routes.ts` 的 `routes` 数组中添加路由配置
|
||
3. **权限控制**: 通过 `requiredPermissions` 和 `oneOfPerm` 配置权限
|
||
4. **国际化**: 页面标题使用 `locale` 多语言 key
|
||
|
||
示例:
|
||
|
||
```typescript
|
||
// src/routes.ts
|
||
{
|
||
name: 'menu.moduleName', // 国际化 key
|
||
key: 'module-name', // 对应 pages/module-name/index.tsx
|
||
requiredPermissions: [ // 可选:需要的权限
|
||
{ resource: 'module', actions: ['read'] }
|
||
]
|
||
}
|
||
```
|
||
|
||
### Redux 状态操作
|
||
|
||
```typescript
|
||
// 获取状态
|
||
import { useSelector } from 'react-redux';
|
||
const { userInfo, settings } = useSelector((state: GlobalState) => state);
|
||
|
||
// 更新状态
|
||
import { useDispatch } from 'react-redux';
|
||
const dispatch = useDispatch();
|
||
dispatch({
|
||
type: 'update-userInfo',
|
||
payload: { userInfo: newUserInfo },
|
||
});
|
||
```
|
||
|
||
### 国际化使用
|
||
|
||
```typescript
|
||
// 在组件中使用国际化
|
||
import useLocale from '@/utils/useLocale';
|
||
import locale from './locale'; // 本地语言文件
|
||
|
||
function MyComponent() {
|
||
const t = useLocale(locale);
|
||
return <div>{t['key.name']}</div>;
|
||
}
|
||
```
|
||
|
||
### 主题色动态修改
|
||
|
||
```typescript
|
||
// 修改主题色(自动生成 10 个梯度色 CSS 变量)
|
||
import initThemeColor from '@/utils/initThemeColor';
|
||
|
||
initThemeColor('#026166', false); // (颜色值, 是否暗色模式)
|
||
```
|
||
|
||
## Mock 数据开发
|
||
|
||
- Mock 文件位置: `src/mock/`
|
||
- 使用 Mock.js 拦截 axios 请求
|
||
- 在 `src/main.tsx` 中导入: `import './mock'`
|
||
- 生产环境需移除 mock 导入
|
||
|
||
## 已知技术债务
|
||
|
||
1. **TypeScript 严格模式未开启**: `tsconfig.json` 中 `strict: false`,建议开启以提升类型安全
|
||
2. **依赖版本较旧**:
|
||
- React 17(建议升级到 18)
|
||
- axios 0.24.0(存在安全漏洞,建议立即升级)
|
||
- React Router 5(建议升级到 v6)
|
||
3. **缺少测试**: 项目无单元测试和集成测试
|
||
4. **Redux 传统模式**: 代码冗长,建议迁移到 Redux Toolkit
|
||
5. **安全防护不足**:
|
||
- localStorage 明文存储敏感信息
|
||
- 缺少 CSRF 防护
|
||
- 缺少输入验证和清洗
|
||
|
||
## 常见问题排查
|
||
|
||
### API 响应成功但业务逻辑未执行
|
||
|
||
**症状**:
|
||
|
||
- API 请求返回成功(控制台显示 `code: "0"` 或 `code: 0`)
|
||
- 但成功回调未执行,数据未更新
|
||
- 或登录成功但未跳转
|
||
|
||
**原因**:
|
||
使用了严格相等 `===` 判断响应码,导致字符串 `"0"` 和数字 `0` 类型不匹配
|
||
|
||
**排查步骤**:
|
||
|
||
1. 打开浏览器开发者工具的 Network 标签页
|
||
2. 查看 API 响应中的 `code` 字段类型(字符串还是数字)
|
||
3. 检查业务代码中是否使用了 `result.code === xxx`
|
||
4. 将所有 `===` 改为 `==`
|
||
|
||
**解决方案**:
|
||
|
||
```typescript
|
||
// ❌ 错误写法
|
||
if (result.code === SUCCESS_CODE) { ... }
|
||
if (result.code === 0) { ... }
|
||
|
||
// ✅ 正确写法
|
||
if (result.code == SUCCESS_CODE) { ... }
|
||
if (result.code == 0) { ... }
|
||
```
|
||
|
||
**预防措施**:
|
||
|
||
- 遵守 [API 开发规范](#api-开发规范) 中的响应码处理规范
|
||
- 代码审查时检查所有响应码判断逻辑
|
||
|
||
### 路由懒加载失败
|
||
|
||
检查页面组件路径是否符合约定:`src/pages/{route.key}/index.tsx`
|
||
|
||
### 权限控制不生效
|
||
|
||
1. 检查 Redux Store 中的 `userInfo.permissions` 是否正确
|
||
2. 检查路由配置中的 `requiredPermissions` 格式
|
||
3. 检查 `utils/authentication.ts` 的权限判断逻辑
|
||
|
||
### 主题色不生效
|
||
|
||
1. 检查 `src/settings.json` 中的 `themeColor` 配置
|
||
2. 确保在应用启动时调用了 `initThemeColor()`(位于 `src/main.tsx:64-70`)
|
||
3. 明暗模式切换时需重新调用 `initThemeColor()`
|
||
|
||
### Vite 构建失败
|
||
|
||
1. 检查 TypeScript 类型错误(虽然 noEmit: true,但仍需类型正确)
|
||
2. 检查 Less 语法错误
|
||
3. 检查路径别名配置是否正确
|
||
|
||
## 性能优化建议
|
||
|
||
- 大数据量表格使用虚拟滚动
|
||
- 图片较多时使用懒加载
|
||
- 搜索、滚动等高频操作添加防抖节流
|
||
- 使用 `rollup-plugin-visualizer` 分析打包产物
|
||
|
||
## 安全注意事项
|
||
|
||
- 敏感信息(Token、用户数据)应加密后再存储到 localStorage
|
||
- 所有用户输入需进行验证和清洗
|
||
- 生产环境强制使用 HTTPS
|
||
- 定期运行 `npm audit` 检查依赖漏洞
|
||
|
||
## 扩展开发指引
|
||
|
||
### 添加新页面
|
||
|
||
1. 创建页面组件: `src/pages/new-page/index.tsx`
|
||
2. 添加路由配置: `src/routes.ts`
|
||
3. 添加国际化: `src/locale/zh-CN.ts` 和 `en-US.ts`
|
||
4. 如需权限控制,配置 `requiredPermissions`
|
||
|
||
### 添加新组件
|
||
|
||
- 业务组件: `src/pages/{module}/components/`
|
||
- 公共组件: `src/components/`
|
||
- 组件应包含独立的样式文件(`.module.less`)
|
||
|
||
### 添加新的 Redux 状态
|
||
|
||
在 `src/store/index.ts` 中:
|
||
|
||
1. 扩展 `GlobalState` 接口
|
||
2. 更新 `initialState`
|
||
3. 在 `reducer` 中添加新的 case
|
||
|
||
## 参考文档
|
||
|
||
- [Arco Design 官方文档](https://arco.design/)
|
||
- [Vite 官方文档](https://vitejs.dev/)
|
||
- [React Router v5 文档](https://v5.reactrouter.com/)
|