234 lines
6.0 KiB
Markdown
234 lines
6.0 KiB
Markdown
# 配置值格式统一方案(简化版)
|
||
|
||
## 🎯 统一原则
|
||
|
||
**核心原则**:前端和后端使用相同的值(比例形式),只在显示时转换
|
||
|
||
### 数据格式
|
||
|
||
- **数据库存储**:比例形式(0.30表示30%)
|
||
- **前端显示**:百分比形式(30%,用户看到)
|
||
- **前端存储**:比例形式(0.30,直接存储,不做转换)
|
||
- **后端使用**:比例形式(0.30,直接使用,不做转换)
|
||
|
||
---
|
||
|
||
## 🔧 当前前端逻辑分析
|
||
|
||
### ConfigPanel.jsx
|
||
|
||
**显示逻辑**(`getInitialDisplayValue`):
|
||
```javascript
|
||
// 从数据库读取0.30,显示为30%
|
||
const percent = numVal <= 1 ? numVal * 100 : numVal
|
||
return formatPercent(percent) // 显示30
|
||
```
|
||
|
||
**存储逻辑**(`handleSave`):
|
||
```javascript
|
||
// 用户输入30,转换为0.30存储
|
||
if (processedValue < 0 || processedValue > 100) {
|
||
return
|
||
}
|
||
processedValue = processedValue / 100 // 30 -> 0.30
|
||
onUpdate(processedValue) // 存储0.30
|
||
```
|
||
|
||
**问题**:
|
||
- ✅ 显示逻辑:正确(0.30 -> 30%)
|
||
- ✅ 存储逻辑:正确(30 -> 0.30)
|
||
- ⚠️ 但代码中有 `numVal <= 1 ? numVal * 100 : numVal` 的逻辑,如果数据库中有旧数据(30),会显示为30而不是3000
|
||
|
||
---
|
||
|
||
## ✅ 简化方案
|
||
|
||
### 方案:统一为比例形式,前端只做显示转换
|
||
|
||
**原则**:
|
||
1. **数据库统一存储比例形式**(0.30表示30%)
|
||
2. **前端显示时转换**(0.30 -> 30%,用户看到30%)
|
||
3. **前端输入时转换**(用户输入30 -> 0.30存储)
|
||
4. **后端直接使用**(0.30,不需要转换)
|
||
|
||
**优势**:
|
||
- ✅ 数据格式统一(数据库、前端、后端都是0.30)
|
||
- ✅ 代码逻辑简单(不需要到处做格式转换)
|
||
- ✅ 减少出错(避免格式不一致)
|
||
|
||
---
|
||
|
||
## 🔧 需要修改的地方
|
||
|
||
### 1. 前端显示逻辑(保持不变)
|
||
|
||
**当前逻辑**:
|
||
```javascript
|
||
// 从数据库读取0.30,显示为30%
|
||
const percent = numVal <= 1 ? numVal * 100 : numVal
|
||
return formatPercent(percent)
|
||
```
|
||
|
||
**说明**:
|
||
- ✅ 如果数据库存储0.30,显示为30%(正确)
|
||
- ⚠️ 如果数据库存储30(旧数据),显示为30(需要数据迁移)
|
||
|
||
---
|
||
|
||
### 2. 前端存储逻辑(保持不变)
|
||
|
||
**当前逻辑**:
|
||
```javascript
|
||
// 用户输入30,转换为0.30存储
|
||
if (processedValue < 0 || processedValue > 100) {
|
||
return
|
||
}
|
||
processedValue = processedValue / 100 // 30 -> 0.30
|
||
onUpdate(processedValue) // 存储0.30
|
||
```
|
||
|
||
**说明**:
|
||
- ✅ 用户输入30,转换为0.30存储(正确)
|
||
- ✅ 后端验证:只接受0-1之间的值(正确)
|
||
|
||
---
|
||
|
||
### 3. 后端代码(移除格式转换)
|
||
|
||
**当前代码**(`backend/config_manager.py:735-758`):
|
||
```python
|
||
# ⚠️ 关键修复:百分比配置值格式转换
|
||
if isinstance(value, (int, float)) and value is not None:
|
||
if key in percent_keys:
|
||
if value > 1:
|
||
value = value / 100.0 # 格式转换
|
||
```
|
||
|
||
**建议**:
|
||
- 数据迁移完成后,可以移除格式转换逻辑
|
||
- 或者保留作为兼容性处理(标记为临时方案)
|
||
|
||
---
|
||
|
||
### 4. 数据迁移(必须执行)
|
||
|
||
**目的**:将数据库中的百分比形式(30)转换为比例形式(0.30)
|
||
|
||
**脚本**:`backend/database/migrate_percent_configs_to_ratio.sql`
|
||
|
||
**执行后**:
|
||
- 数据库统一存储比例形式(0.30)
|
||
- 前端显示为30%(用户看到)
|
||
- 前端存储为0.30(直接存储)
|
||
- 后端使用0.30(直接使用)
|
||
|
||
---
|
||
|
||
## 📊 数据流
|
||
|
||
### 当前流程(有格式转换)
|
||
|
||
```
|
||
用户输入30
|
||
↓
|
||
前端转换:30 -> 0.30
|
||
↓
|
||
存储到数据库:0.30
|
||
↓
|
||
后端读取:0.30
|
||
↓
|
||
代码中格式转换:0.30 -> 0.30(如果>1才转换)
|
||
↓
|
||
使用:0.30
|
||
```
|
||
|
||
### 统一后流程(无格式转换)
|
||
|
||
```
|
||
用户输入30
|
||
↓
|
||
前端转换:30 -> 0.30(仅前端输入时转换)
|
||
↓
|
||
存储到数据库:0.30
|
||
↓
|
||
后端读取:0.30
|
||
↓
|
||
直接使用:0.30(不需要转换)
|
||
```
|
||
|
||
---
|
||
|
||
## ✅ 实施步骤
|
||
|
||
### 步骤1:执行数据迁移
|
||
|
||
```bash
|
||
# 执行SQL迁移脚本
|
||
mysql -u username -p database_name < backend/database/migrate_percent_configs_to_ratio.sql
|
||
```
|
||
|
||
### 步骤2:清除Redis缓存
|
||
|
||
```bash
|
||
# 清除Redis缓存,让系统重新加载配置
|
||
redis-cli DEL "config:trading_config:*"
|
||
redis-cli DEL "config:global_strategy_config:*"
|
||
```
|
||
|
||
### 步骤3:验证数据格式
|
||
|
||
```sql
|
||
-- 验证:所有百分比配置项应该在0-1之间
|
||
SELECT config_key, config_value
|
||
FROM trading_config
|
||
WHERE config_key IN (
|
||
'TRAILING_STOP_ACTIVATION',
|
||
'TRAILING_STOP_PROTECT',
|
||
'MIN_VOLATILITY',
|
||
'TAKE_PROFIT_PERCENT',
|
||
'STOP_LOSS_PERCENT'
|
||
)
|
||
AND config_type = 'number'
|
||
AND (CAST(config_value AS DECIMAL(10, 4)) < 0 OR CAST(config_value AS DECIMAL(10, 4)) > 1);
|
||
-- 应该返回0行
|
||
```
|
||
|
||
### 步骤4:保留格式转换作为兼容性处理(可选)
|
||
|
||
**建议**:数据迁移完成后,保留格式转换逻辑作为兼容性处理,但标记为临时方案
|
||
|
||
**代码**:
|
||
```python
|
||
# ⚠️ 临时兼容性处理:如果数据库中有旧数据(百分比形式),自动转换
|
||
# 数据迁移完成后,可以移除此逻辑
|
||
if isinstance(value, (int, float)) and value is not None:
|
||
if key in percent_keys:
|
||
if value > 1:
|
||
value = value / 100.0
|
||
logger.warning(f"配置值格式转换(临时兼容): {key} = {value*100:.2f}% (从百分比形式转换为比例形式)")
|
||
```
|
||
|
||
---
|
||
|
||
## 📝 总结
|
||
|
||
### 统一方案
|
||
|
||
1. **数据库存储**:比例形式(0.30表示30%)
|
||
2. **前端显示**:百分比形式(30%,用户看到)
|
||
3. **前端存储**:比例形式(0.30,直接存储)
|
||
4. **后端使用**:比例形式(0.30,直接使用)
|
||
|
||
### 优势
|
||
|
||
- ✅ **数据格式统一**:数据库、前端、后端都是0.30
|
||
- ✅ **代码逻辑简单**:不需要到处做格式转换
|
||
- ✅ **减少出错**:避免格式不一致导致的bug
|
||
- ✅ **易于维护**:统一的格式,更容易理解和维护
|
||
|
||
### 实施建议
|
||
|
||
1. **立即执行数据迁移**:统一数据格式
|
||
2. **保留格式转换作为兼容性处理**:标记为临时方案
|
||
3. **后续可以移除格式转换**:数据格式统一后,可以移除
|