0327eaffe3
后端: - 为 copy_trading 表添加 max_market_end_date 字段(毫秒时间戳) - 为 markets 表添加 end_date 字段,迁移时清空已有数据 - 实现市场截止时间过滤逻辑(仅跟单截止时间小于设置时间的订单) - 更新 CopyTradingService 支持 maxMarketEndDate 的创建和更新 - 更新 FilterResult 添加 FAILED_MARKET_END_DATE 状态 - 更新 CopyOrderTrackingService 传递 marketEndDate 参数 前端: - 添加市场截止时间筛选 UI(支持小时和天两种单位) - 输入限制:仅支持整数输入(precision=0) - 更新 AddModal 和 EditModal 支持市场截止时间配置 - 更新过滤类型显示映射(MARKET_END_DATE) - 添加多语言支持(中文、英文、繁体中文) 数据库迁移: - V22: 合并添加 max_market_end_date 和 end_date 字段 - 迁移时清空 markets 表数据,确保所有数据都包含 end_date
215 lines
4.5 KiB
Plaintext
215 lines
4.5 KiB
Plaintext
---
|
||
alwaysApply: true
|
||
path: frontend/**
|
||
---
|
||
|
||
# 前端开发规范
|
||
|
||
## 核心原则
|
||
- **禁止**在代码中添加 TODO/FIXME/XXX 注释
|
||
- **禁止**使用 `any` 类型
|
||
- **禁止**硬编码中文或英文文本
|
||
- **必须**支持移动端和桌面端
|
||
|
||
## 技术栈
|
||
- **框架**: React + TypeScript
|
||
- **UI 库**: Ant Design(移动端使用 Ant Design Mobile)
|
||
- **HTTP 客户端**: axios
|
||
- **状态管理**: Zustand
|
||
- **国际化**: react-i18next
|
||
|
||
## 移动端适配
|
||
|
||
### 响应式断点
|
||
- **移动端**: < 768px
|
||
- **平板**: 768px - 1024px
|
||
- **桌面端**: > 1024px
|
||
|
||
### 适配要求
|
||
- 使用响应式布局(Mobile First)
|
||
- 导航栏:移动端抽屉菜单,桌面端顶部导航
|
||
- 列表:移动端卡片布局,桌面端表格布局
|
||
- 按钮:移动端不小于 44x44px
|
||
- 支持触摸操作和手势
|
||
|
||
### 性能优化
|
||
- 图片懒加载
|
||
- 代码分割(Code Splitting)
|
||
- 移动端减少动画效果
|
||
|
||
## 代码规范
|
||
|
||
### 组件
|
||
- 使用函数式组件
|
||
- 使用 TypeScript 类型定义
|
||
- 组件文件使用 PascalCase 命名
|
||
|
||
```typescript
|
||
// ✅ 正确
|
||
interface MarketProps {
|
||
marketId: string;
|
||
platform: string;
|
||
}
|
||
|
||
export const MarketCard: React.FC<MarketProps> = ({ marketId, platform }) => {
|
||
// ...
|
||
};
|
||
|
||
// ❌ 错误
|
||
export const marketCard = (props: any) => { }
|
||
```
|
||
|
||
### API 调用
|
||
- 使用 axios
|
||
- 统一错误处理
|
||
- 使用 TypeScript 定义响应类型
|
||
|
||
```typescript
|
||
interface Market {
|
||
id: string;
|
||
marketId: string;
|
||
title: string;
|
||
}
|
||
|
||
export const marketService = {
|
||
getMarkets: async (): Promise<Market[]> => {
|
||
const response = await axios.get<Market[]>('/api/markets');
|
||
return response.data;
|
||
}
|
||
};
|
||
```
|
||
|
||
### 状态管理
|
||
- 全局状态使用 Zustand
|
||
- 本地状态使用 `useState`
|
||
- 复杂状态使用 `useReducer`
|
||
|
||
```typescript
|
||
interface MarketStore {
|
||
markets: Market[];
|
||
setMarkets: (markets: Market[]) => void;
|
||
}
|
||
|
||
export const useMarketStore = create<MarketStore>((set) => ({
|
||
markets: [],
|
||
setMarkets: (markets) => set({ markets }),
|
||
}));
|
||
```
|
||
|
||
### USDC 金额格式化
|
||
**必须**使用 `formatUSDC` 函数(从 `../utils` 导入)
|
||
|
||
```typescript
|
||
import { formatUSDC } from '../utils'
|
||
|
||
// ✅ 正确
|
||
<Statistic
|
||
title="总盈亏"
|
||
value={formatUSDC(stats?.totalPnl || '0')}
|
||
suffix="USDC"
|
||
/>
|
||
|
||
// ❌ 错误
|
||
const balance = parseFloat(value).toFixed(4)
|
||
```
|
||
|
||
**格式化规则**:
|
||
- 最多显示 4 位小数(截断,不四舍五入)
|
||
- 自动去除尾随零
|
||
- 空值返回 `'-'`
|
||
|
||
## 多语言规范
|
||
|
||
### 使用方式
|
||
**必须**使用 `useTranslation` Hook
|
||
|
||
```typescript
|
||
// ✅ 正确
|
||
import { useTranslation } from 'react-i18next'
|
||
|
||
const MyComponent: React.FC = () => {
|
||
const { t } = useTranslation()
|
||
|
||
return (
|
||
<div>
|
||
<h1>{t('page.title')}</h1>
|
||
<Button>{t('common.save')}</Button>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
// ❌ 错误:硬编码文本
|
||
<h1>页面标题</h1>
|
||
<Button>保存</Button>
|
||
```
|
||
|
||
### 语言文件
|
||
- 位置: `src/locales/{locale}/common.json`
|
||
- 支持: `zh-CN`、`zh-TW`、`en`
|
||
- 键名: 点号分隔的层级结构(如 `notificationSettings.title`)
|
||
|
||
### 添加新翻译
|
||
1. 在 `src/locales/zh-CN/common.json` 添加中文
|
||
2. 在 `src/locales/zh-TW/common.json` 添加繁体
|
||
3. 在 `src/locales/en/common.json` 添加英文
|
||
4. 在组件中使用 `t('key')`
|
||
|
||
## 移动端适配示例
|
||
|
||
### 响应式布局
|
||
```typescript
|
||
import { useMediaQuery } from 'react-responsive';
|
||
|
||
const MyComponent: React.FC = () => {
|
||
const isMobile = useMediaQuery({ maxWidth: 768 });
|
||
|
||
return (
|
||
<div className={isMobile ? 'mobile-layout' : 'desktop-layout'}>
|
||
{isMobile ? <MobileView /> : <DesktopView />}
|
||
</div>
|
||
);
|
||
};
|
||
```
|
||
|
||
### 响应式表格
|
||
```typescript
|
||
import { Table } from 'antd';
|
||
|
||
const ResponsiveTable: React.FC = () => {
|
||
const isMobile = useMediaQuery({ maxWidth: 768 });
|
||
|
||
return (
|
||
<Table
|
||
dataSource={data}
|
||
columns={columns}
|
||
scroll={{ x: isMobile ? 600 : 'auto' }}
|
||
pagination={{
|
||
pageSize: isMobile ? 10 : 20,
|
||
showSizeChanger: !isMobile
|
||
}}
|
||
/>
|
||
);
|
||
};
|
||
```
|
||
|
||
## 禁止事项
|
||
|
||
### 代码质量
|
||
- ❌ 禁止使用 `any` 类型
|
||
- ❌ 禁止忽略错误处理
|
||
- ❌ 禁止硬编码 API 地址
|
||
- ❌ 禁止在组件中直接使用 `fetch`
|
||
- ❌ 禁止忽略移动端适配
|
||
|
||
### 类型安全
|
||
- ❌ 禁止使用 `@ts-ignore` 除非有明确原因
|
||
|
||
### 移动端适配
|
||
- ❌ 禁止固定宽度布局
|
||
- ❌ 禁止使用过小的触摸目标(< 44x44px)
|
||
- ❌ 禁止使用桌面端专用交互(如 hover)
|
||
|
||
### 多语言
|
||
- ❌ 禁止硬编码中文或英文文本
|
||
- ❌ 禁止绕过 `useTranslation` 直接显示文本
|