Files
ycc-proxy-server/代理配置表分析和优化建议.md
2025-12-02 19:57:10 +08:00

775 lines
31 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 代理配置表分析和优化建议
## 一、当前配置表结构分析
### 1.1 数据库表结构
**表名**: `agent_config`
```sql
CREATE TABLE `agent_config` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`config_key` varchar(100) NOT NULL COMMENT '配置键(唯一)',
`config_value` varchar(500) NOT NULL COMMENT '配置值',
`config_type` varchar(50) NOT NULL COMMENT '配置类型price=价格bonus=等级加成upgrade=升级费用rebate=返佣tax=税费',
`description` varchar(500) DEFAULT NULL COMMENT '配置描述',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`delete_time` datetime DEFAULT NULL,
`del_state` tinyint NOT NULL DEFAULT 0,
`version` bigint NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_config_key` (`config_key`),
KEY `idx_config_type` (`config_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```
### 1.2 配置表设计评估
**优点**
**键值对存储灵活**:使用 `config_key``config_value` 的键值对模式,易于扩展新配置项
**类型分类清晰**`config_type` 字段将配置分为 price、bonus、upgrade、rebate、tax 等类型,便于管理
**唯一索引合理**`config_key` 的唯一索引确保配置键不重复
**版本控制**:包含 `version` 字段支持乐观锁,适合配置更新场景
**软删除支持**:支持软删除,保留历史配置记录
**缺点/问题**
**配置值类型限制**`config_value``varchar(500)`,所有值都存储为字符串,需要在使用时转换
**缺少验证机制**:数据库层面无法验证配置值的格式和范围
**配置值长度限制**对于复杂配置如JSON对象500字符可能不够
---
## 二、当前配置项清单
### 2.1 SQL初始化脚本中的配置项
根据 `agent_system_migration.sql` 文件,当前初始化的配置项:
| 配置键 | 配置值 | 类型 | 说明 |
| ------------------------------- | ------- | ------- | ------------------------ |
| `base_price` | 0.00 | price | 系统基础底价 |
| `system_max_price` | 9999.99 | price | 系统价格上限 |
| `price_threshold` | 0.00 | price | 提价标准阈值 |
| `price_fee_rate` | 0.0000 | price | 提价手续费比例 |
| `level_bonus_normal` | 6.00 | bonus | 普通代理等级加成 |
| `level_bonus_gold` | 3.00 | bonus | 黄金代理等级加成 |
| `level_bonus_diamond` | 0.00 | bonus | 钻石代理等级加成 |
| `upgrade_fee_normal_to_gold` | 199.00 | upgrade | 普通→黄金升级费用 |
| `upgrade_fee_to_diamond` | 980.00 | upgrade | 升级为钻石费用 |
| `upgrade_rebate_normal_to_gold` | 139.00 | upgrade | 普通→黄金返佣金额 |
| `upgrade_rebate_to_diamond` | 680.00 | upgrade | 升级为钻石返佣金额 |
| `direct_parent_amount_diamond` | 6.00 | rebate | 直接上级是钻石的返佣金额 |
| `direct_parent_amount_gold` | 3.00 | rebate | 直接上级是黄金的返佣金额 |
| `direct_parent_amount_normal` | 2.00 | rebate | 直接上级是普通的返佣金额 |
| `max_gold_rebate_amount` | 3.00 | rebate | 黄金代理最大返佣金额 |
| `tax_rate` | 0.0600 | tax | 提现税率6% |
**共15个配置项**
### 2.2 代码中使用的配置键
#### 2.2.1 AgentService 中使用的配置键
- `base_price` - 基础底价 ✅
- `price_threshold` - 提价标准阈值 ✅
- `price_fee_rate` - 提价手续费比例 ✅
- `level_bonus` - **硬编码,未从配置表读取**
#### 2.2.2 AdminGetAgentConfigLogic 中使用的配置键
- `level_1_bonus` - 普通代理等级加成 ❌ **配置键不匹配**
- `level_2_bonus` - 黄金代理等级加成 ❌ **配置键不匹配**
- `level_3_bonus` - 钻石代理等级加成 ❌ **配置键不匹配**
- `upgrade_to_gold_fee` - 升级为黄金费用 ❌ **配置键不匹配**
- `upgrade_to_diamond_fee` - 升级为钻石费用 ❌ **配置键不匹配**
- `upgrade_to_gold_rebate` - 升级为黄金返佣 ❌ **配置键不匹配**
- `upgrade_to_diamond_rebate` - 升级为钻石返佣 ❌ **配置键不匹配**
- `tax_rate` - 税率 ✅
- `tax_exemption_amount` - 免税额度 ❌ **配置项缺失**
---
## 三、发现的问题
### 3.1 🔴 严重问题:价格配置不应在系统配置表中
**问题描述**
价格相关配置(底价、上限、提价阈值、手续费比例)应该按产品配置,而不是全局系统配置。当前这些配置同时存在于 `agent_config``agent_product_config` 表中,但代码只从系统配置表读取,没有实现产品级别的配置覆盖。
**问题影响**
- ❌ 不同产品无法设置不同的底价和价格策略
- ❌ 代码中只读取系统配置,忽略了产品配置(`AgentService.AgentProcess``PaymentLogic`
- ❌ 产品配置表虽然存在,但在订单处理逻辑中未被使用
**应该移除的系统配置项**
- `base_price` - 应该只在产品配置表中
- `system_max_price` - 应该只在产品配置表中
- `price_threshold` - 应该只在产品配置表中(可选)
- `price_fee_rate` - 应该只在产品配置表中(可选)
**正确的设计**
- ✅ 所有价格相关配置都应该在 `agent_product_config` 表中按产品配置
- ✅ 系统配置表只保留全局配置(等级加成、升级费用、税费等)
- ✅ 代码应该优先从产品配置读取,如果产品未配置,则使用默认值
### 3.2 🔴 严重问题:配置键命名不一致
**问题描述**
SQL初始化脚本和代码逻辑中使用的配置键命名不一致导致配置无法正确读取。
**具体情况**
| 配置项 | SQL初始化脚本 | 代码逻辑期望 | 状态 |
| ---------------- | ------------------------------- | --------------------------- | -------- |
| 普通代理等级加成 | `level_bonus_normal` | `level_1_bonus` | ❌ 不匹配 |
| 黄金代理等级加成 | `level_bonus_gold` | `level_2_bonus` | ❌ 不匹配 |
| 钻石代理等级加成 | `level_bonus_diamond` | `level_3_bonus` | ❌ 不匹配 |
| 升级为黄金费用 | `upgrade_fee_normal_to_gold` | `upgrade_to_gold_fee` | ❌ 不匹配 |
| 升级为钻石费用 | `upgrade_fee_to_diamond` | `upgrade_to_diamond_fee` | ❌ 不匹配 |
| 升级为黄金返佣 | `upgrade_rebate_normal_to_gold` | `upgrade_to_gold_rebate` | ❌ 不匹配 |
| 升级为钻石返佣 | `upgrade_rebate_to_diamond` | `upgrade_to_diamond_rebate` | ❌ 不匹配 |
**影响**
- 后台管理系统无法正确读取和显示配置值
- 配置更新可能无法正常工作
### 3.3 🔴 严重问题:代码中硬编码等级加成
**问题位置**
```go
// agentService.go:144-155
func (s *AgentService) getLevelBonus(level int64) int64 {
switch level {
case 1: // 普通
return 6 // ❌ 硬编码,应该从配置表读取
case 2: // 黄金
return 3 // ❌ 硬编码,应该从配置表读取
case 3: // 钻石
return 0 // ❌ 硬编码,应该从配置表读取
default:
return 0
}
}
```
**问题影响**
- 等级加成值无法通过后台配置动态调整
- 必须修改代码才能更改等级加成
- 违反了配置化的设计原则
### 3.4 🟡 中等问题:缺少配置项
**缺失的配置项**
1. `tax_exemption_amount` - 免税额度前端接口需要但SQL初始化脚本中未包含
2. `upgrade_fee_gold_to_diamond` - 黄金→钻石升级费用(如果独立配置)
### 3.5 🟡 中等问题:配置键命名规范不统一
**当前问题**
- 部分使用下划线分隔:`level_bonus_normal`
- 部分使用数字后缀:`level_1_bonus`
- 部分使用驼峰式:`upgrade_fee_normal_to_gold`
**建议**:统一命名规范
### 3.6 🟢 轻微问题:配置值存储方式
**当前方式**:所有配置值以字符串形式存储,需要在使用时转换
- `strconv.ParseFloat()` 转换为浮点数
- `strconv.ParseInt()` 转换为整数
**影响**:每次读取都需要类型转换,性能影响较小,但容易出错
---
## 四、配置使用情况分析
### 4.1 实际使用的配置项
**在业务逻辑中使用的配置**
1.`base_price` - 订单处理时使用
2.`price_threshold` - 计算提价成本时使用
3.`price_fee_rate` - 计算提价成本时使用
4.`level_bonus_*` - **未使用,代码中硬编码**
**在后台管理中使用的配置**
1.`level_1_bonus` - 读取配置(但键名不匹配)
2.`level_2_bonus` - 读取配置(但键名不匹配)
3.`level_3_bonus` - 读取配置(但键名不匹配)
4.`upgrade_to_gold_fee` - 读取配置(但键名不匹配)
5.`upgrade_to_diamond_fee` - 读取配置(但键名不匹配)
6.`upgrade_to_gold_rebate` - 读取配置(但键名不匹配)
7.`upgrade_to_diamond_rebate` - 读取配置(但键名不匹配)
8.`tax_rate` - 读取配置
9.`tax_exemption_amount` - 读取配置(但配置项缺失)
### 4.2 未使用的配置项
以下配置项在SQL中初始化了但在代码中**似乎未使用**
- `direct_parent_amount_diamond` - 直接上级是钻石的返佣金额
- `direct_parent_amount_gold` - 直接上级是黄金的返佣金额
- `direct_parent_amount_normal` - 直接上级是普通的返佣金额
- `max_gold_rebate_amount` - 黄金代理最大返佣金额
**说明**:这些配置项可能被硬编码在 `distributeNormalAgentBonus` 等函数中,需要确认是否需要配置化。
---
## 五、优化建议
### 5.1 🔴 立即修复:移除系统配置表中的价格配置
**问题**
价格相关配置(`base_price``system_max_price``price_threshold``price_fee_rate`)应该完全由产品配置表管理,系统配置表中不应该存在这些配置。
**修复步骤**
1. **从系统配置表中删除价格相关配置**
```sql
-- 删除系统配置表中的价格相关配置
DELETE FROM `agent_config` WHERE `config_key` IN (
'base_price',
'system_max_price',
'price_threshold',
'price_fee_rate'
);
```
2. **修改订单处理逻辑,从产品配置表读取**
需要修改的文件:
- `app/main/api/internal/service/agentService.go` - `AgentProcess` 方法
- `app/main/api/internal/logic/pay/paymentlogic.go` - 创建订单时的价格计算
**示例代码修改**`agentService.go`
```go
// AgentProcess 处理代理订单(新系统)
func (s *AgentService) AgentProcess(ctx context.Context, order *model.Order) error {
// ... 前面的代码不变 ...
// 4. 获取产品配置(优先使用产品配置,如果不存在则使用默认值)
productConfig, err := s.AgentProductConfigModel.FindOneByProductId(ctx, order.ProductId)
if err != nil && !errors.Is(err, model.ErrNotFound) {
return errors.Wrapf(err, "查询产品配置失败, productId: %d", order.ProductId)
}
// 使用产品配置的底价如果产品未配置则使用默认值0
basePrice := 0.0
if productConfig != nil {
basePrice = productConfig.BasePrice
}
// ... 使用basePrice计算实际底价 ...
// 6.2 计算提价成本(使用产品配置)
priceThreshold := 0.0
priceFeeRate := 0.0
if productConfig != nil {
if productConfig.PriceThreshold.Valid {
priceThreshold = productConfig.PriceThreshold.Float64
}
if productConfig.PriceFeeRate.Valid {
priceFeeRate = productConfig.PriceFeeRate.Float64
}
}
priceCost := s.calculatePriceCost(agentOrder.SetPrice, priceThreshold, priceFeeRate)
// ... 后续代码 ...
}
```
3. **更新后台管理系统**
- 移除系统配置页面中的价格相关配置项
- 确保产品配置页面可以正确配置这些价格参数
### 5.2 🔴 立即修复:统一配置键命名
**方案一修改SQL初始化脚本使用代码期望的键名**
```sql
-- 修改等级加成配置键
UPDATE `agent_config` SET `config_key` = 'level_1_bonus' WHERE `config_key` = 'level_bonus_normal';
UPDATE `agent_config` SET `config_key` = 'level_2_bonus' WHERE `config_key` = 'level_bonus_gold';
UPDATE `agent_config` SET `config_key` = 'level_3_bonus' WHERE `config_key` = 'level_bonus_diamond';
-- 修改升级费用配置键
UPDATE `agent_config` SET `config_key` = 'upgrade_to_gold_fee' WHERE `config_key` = 'upgrade_fee_normal_to_gold';
UPDATE `agent_config` SET `config_key` = 'upgrade_to_diamond_fee' WHERE `config_key` = 'upgrade_fee_to_diamond';
-- 修改升级返佣配置键
UPDATE `agent_config` SET `config_key` = 'upgrade_to_gold_rebate' WHERE `config_key` = 'upgrade_rebate_normal_to_gold';
UPDATE `agent_config` SET `config_key` = 'upgrade_to_diamond_rebate' WHERE `config_key` = 'upgrade_rebate_to_diamond';
```
**方案二修改代码逻辑使用SQL中的键名**
需要修改的文件:
- `app/main/api/internal/logic/admin_agent/admingetagentconfiglogic.go`
- `app/main/api/internal/logic/admin_agent/adminupdateagentconfiglogic.go`
**推荐方案一**,因为:
- 代码中的命名更清晰(`level_1_bonus``level_bonus_normal` 更直观)
- 数字后缀与等级数字1/2/3对应易于理解
### 5.3 🔴 立即修复:从配置表读取等级加成
**修改 `agentService.go` 中的 `getLevelBonus` 函数**
```go
// getLevelBonus 获取等级加成(从配置表读取)
func (s *AgentService) getLevelBonus(ctx context.Context, level int64) (int64, error) {
var configKey string
switch level {
case 1:
configKey = "level_1_bonus"
case 2:
configKey = "level_2_bonus"
case 3:
configKey = "level_3_bonus"
default:
return 0, nil
}
bonus, err := s.getConfigFloat(ctx, configKey)
if err != nil {
// 配置不存在时返回默认值
switch level {
case 1:
return 6, nil
case 2:
return 3, nil
case 3:
return 0, nil
}
return 0, nil
}
return int64(bonus), nil
}
```
**修改调用处**
```go
// agentService.go:108
levelBonus, err := s.getLevelBonus(ctx, agent.Level)
if err != nil {
return errors.Wrapf(err, "获取等级加成配置失败")
}
actualBasePrice := basePrice + float64(levelBonus)
```
### 5.4 🟡 补充缺失的配置项
**添加 `tax_exemption_amount` 配置**
```sql
INSERT INTO `agent_config` (`config_key`, `config_value`, `config_type`, `description`)
VALUES ('tax_exemption_amount', '0.00', 'tax', '提现免税额度默认0');
```
### 5.5 🟡 规范化配置键命名
**建议统一使用以下命名规范**
```
{类型}_{编号/级别}_{属性}
```
**示例**
-`level_1_bonus` - 等级1的加成
-`level_2_bonus` - 等级2的加成
-`level_3_bonus` - 等级3的加成
-`upgrade_to_gold_fee` - 升级到黄金的费用
-`upgrade_to_diamond_fee` - 升级到钻石的费用
-`upgrade_to_gold_rebate` - 升级到黄金的返佣
-`upgrade_to_diamond_rebate` - 升级到钻石的返佣
### 5.6 🟢 优化建议:添加配置验证
**在更新配置时添加验证逻辑**
```go
// 验证配置值的合理性
func validateConfigValue(key string, value float64) error {
switch key {
case "tax_rate":
if value < 0 || value > 1 {
return errors.New("税率必须在0-1之间")
}
case "price_fee_rate":
if value < 0 || value > 1 {
return errors.New("提价费率必须在0-1之间")
}
case "base_price", "system_max_price":
if value < 0 {
return errors.New("价格配置不能为负数")
}
}
return nil
}
```
---
## 六、配置项完整清单(修正后)
### 6.1 价格相关配置(应移除,改为产品配置)
**⚠️ 重要说明**:以下配置项应该从系统配置表(`agent_config`)中移除,改为在产品配置表(`agent_product_config`)中按产品配置。
| 配置键 | 说明 | 配置位置 |
| ---------------------- | ----------------------------- | ----------------------------- |
| ~~`base_price`~~ | ~~系统基础底价~~ | ✅ 应在 `agent_product_config` |
| ~~`system_max_price`~~ | ~~系统价格上限~~ | ✅ 应在 `agent_product_config` |
| ~~`price_threshold`~~ | ~~提价标准阈值~~ | ✅ 应在 `agent_product_config` |
| ~~`price_fee_rate`~~ | ~~提价手续费比例0-1之间~~ | ✅ 应在 `agent_product_config` |
**产品配置表结构**`agent_product_config`
- `base_price` - 产品基础底价(必填)
- `system_max_price` - 产品价格上限(必填)
- `price_threshold` - 提价标准阈值可选NULL时表示不设阈值
- `price_fee_rate` - 提价手续费比例可选NULL时表示不收费
### 6.2 等级加成配置bonus类型
| 配置键 | 默认值 | 说明 |
| --------------- | ------ | ---------------------- |
| `level_1_bonus` | 6.00 | 普通代理等级加成(元) |
| `level_2_bonus` | 3.00 | 黄金代理等级加成(元) |
| `level_3_bonus` | 0.00 | 钻石代理等级加成(元) |
### 6.3 升级费用配置upgrade类型
| 配置键 | 默认值 | 说明 |
| --------------------------- | ------ | ------------------------ |
| `upgrade_to_gold_fee` | 199.00 | 普通→黄金升级费用(元) |
| `upgrade_to_diamond_fee` | 980.00 | 升级为钻石费用(元) |
| `upgrade_to_gold_rebate` | 139.00 | 普通→黄金返佣金额(元) |
| `upgrade_to_diamond_rebate` | 680.00 | 升级为钻石返佣金额(元) |
**注意**`gold_to_diamond` 的费用和返佣可以通过计算得出:
- 费用:`upgrade_to_diamond_fee - upgrade_to_gold_fee = 980 - 199 = 781元`
- 返佣:可以通过前端或后端计算,不单独存储
### 6.4 返佣规则配置rebate类型
| 配置键 | 默认值 | 说明 |
| ------------------------------ | ------ | ------------------------------ |
| `direct_parent_amount_diamond` | 6.00 | 直接上级是钻石的返佣金额(元) |
| `direct_parent_amount_gold` | 3.00 | 直接上级是黄金的返佣金额(元) |
| `direct_parent_amount_normal` | 2.00 | 直接上级是普通的返佣金额(元) |
| `max_gold_rebate_amount` | 3.00 | 黄金代理最大返佣金额(元) |
**建议**:这些配置项目前在代码中硬编码,建议配置化。
### 6.5 税费配置tax类型
| 配置键 | 默认值 | 说明 |
| ---------------------- | ------ | ---------------------- |
| `tax_rate` | 0.0600 | 提现税率6%即0.06 |
| `tax_exemption_amount` | 0.00 | 免税额度默认0 |
---
## 七、配置表的合理性评估
### 7.1 表结构设计
| 评估项 | 评分 | 说明 |
| ------------ | ----- | ---------------------------- |
| **灵活性** | ⭐⭐⭐⭐⭐ | 键值对设计非常灵活,易于扩展 |
| **可维护性** | ⭐⭐⭐⭐ | 类型分类清晰,便于管理 |
| **性能** | ⭐⭐⭐⭐ | 唯一索引优化查询,缓存支持 |
| **类型安全** | ⭐⭐⭐ | 所有值都是字符串,需要转换 |
| **验证机制** | ⭐⭐ | 缺少数据库层面的验证 |
### 7.2 总体评价
**设计优点**
✅ 采用键值对存储,扩展性强
✅ 类型分类清晰,便于管理
✅ 支持版本控制和软删除
**存在的问题**
**价格配置应该在产品配置表,而不是系统配置表**(严重设计问题)
❌ 配置键命名不一致(严重)
❌ 部分配置硬编码(严重)
❌ 缺少部分配置项(中等)
❌ 缺少配置验证机制(中等)
**总体评分**⭐⭐⭐3/5
**结论**:配置表的设计思路基本合理,但存在**价格配置位置设计错误**的严重问题。价格相关配置应该完全由产品配置表管理,系统配置表只应该包含全局配置(等级加成、升级费用、税费等)。修复这些问题后,配置表设计将更加完善和符合项目规范。
---
## 八、修复后的完整配置SQL
```sql
-- ============================================
-- 代理系统配置初始化(修正版)
-- ============================================
-- 删除价格相关配置(应该在产品配置表中)
DELETE FROM `agent_config` WHERE `config_key` IN (
'base_price',
'system_max_price',
'price_threshold',
'price_fee_rate'
);
-- 删除旧的不一致配置(如果存在)
DELETE FROM `agent_config` WHERE `config_key` IN (
'level_bonus_normal',
'level_bonus_gold',
'level_bonus_diamond',
'upgrade_fee_normal_to_gold',
'upgrade_fee_to_diamond',
'upgrade_rebate_normal_to_gold',
'upgrade_rebate_to_diamond'
);
-- 插入修正后的配置项
INSERT INTO `agent_config` (`config_key`, `config_value`, `config_type`, `description`) VALUES
-- 注意价格相关配置base_price, system_max_price, price_threshold, price_fee_rate
-- 已从系统配置表中移除改为在产品配置表agent_product_config中按产品配置
-- 等级加成配置(修正键名)
('level_1_bonus', '6.00', 'bonus', '普通代理等级加成6元'),
('level_2_bonus', '3.00', 'bonus', '黄金代理等级加成3元'),
('level_3_bonus', '0.00', 'bonus', '钻石代理等级加成0元'),
-- 升级费用配置(修正键名)
('upgrade_to_gold_fee', '199.00', 'upgrade', '普通→黄金升级费用199元'),
('upgrade_to_diamond_fee', '980.00', 'upgrade', '升级为钻石费用980元'),
-- 升级返佣配置(修正键名)
('upgrade_to_gold_rebate', '139.00', 'upgrade', '普通→黄金返佣金额139元'),
('upgrade_to_diamond_rebate', '680.00', 'upgrade', '升级为钻石返佣金额680元'),
-- 返佣规则配置
('direct_parent_amount_diamond', '6.00', 'rebate', '直接上级是钻石的返佣金额6元'),
('direct_parent_amount_gold', '3.00', 'rebate', '直接上级是黄金的返佣金额3元'),
('direct_parent_amount_normal', '2.00', 'rebate', '直接上级是普通的返佣金额2元'),
('max_gold_rebate_amount', '3.00', 'rebate', '黄金代理最大返佣金额3元'),
-- 税费配置
('tax_rate', '0.0600', 'tax', '提现税率6%即0.06'),
('tax_exemption_amount', '0.00', 'tax', '提现免税额度默认0')
ON DUPLICATE KEY UPDATE
`config_value` = VALUES(`config_value`),
`update_time` = NOW();
```
---
## 九、建议的改进方案
### 方案A保持当前键值对设计推荐
**优点**
- 灵活性强,易于扩展
- 不需要修改表结构
- 符合项目当前架构
**需要做的修改**
1. 统一配置键命名
2. 修复代码硬编码问题
3. 补充缺失的配置项
4. 添加配置验证逻辑
### 方案B改为结构化JSON配置可选
**如果配置项继续增长,可以考虑**
- 将相关配置组合成JSON对象存储在 `config_value`
- 例如:`level_bonus_config` 存储 `{"1": 6, "2": 3, "3": 0}`
**缺点**
- 需要修改所有读取配置的代码
- 不利于单个配置项的独立更新
**建议**当前配置项数量不多约15个保持键值对设计更合适。
---
## 十、总结
### 当前状态
- ✅ 配置表设计思路合理
-**价格配置设计错误**(应该在产品配置表,不在系统配置表)
- ❌ 配置键命名不一致(需要立即修复)
- ❌ 部分配置硬编码(需要立即修复)
- ⚠️ 缺少部分配置项(需要补充)
### 修复优先级
1. **P0紧急**:移除系统配置表中的价格配置,改为完全由产品配置表管理
2. **P0紧急**:修改订单处理逻辑,从产品配置表读取价格参数
3. **P0紧急**:统一配置键命名,修复不一致问题
4. **P0紧急**:修改代码,从配置表读取等级加成,移除硬编码
5. **P1重要**:补充缺失的配置项(`tax_exemption_amount`
6. **P2建议**:添加配置验证逻辑
7. **P2建议**:将返佣规则配置化(当前硬编码)
### 是否符合项目
**配置表设计**:✅ 基本符合,但价格配置的位置设计错误
**存在的问题**
1.**价格配置应该在产品配置表中,而不是系统配置表**(严重设计问题)
2. ❌ 配置键命名不一致
3. ❌ 部分配置硬编码
4. ⚠️ 缺少部分配置项
**结论**:需要修复上述问题后才能完全符合项目的配置化设计理念。**最重要的是将价格配置从系统配置表移除,改为完全由产品配置表管理。**
---
## 十一、产品配置表使用规范
### 11.1 产品配置表结构
**表名**: `agent_product_config`
每个产品都应该有对应的配置记录,包含以下字段:
| 字段 | 类型 | 必填 | 说明 |
| ------------------ | ------------- | ---- | ----------------------------------------- |
| `product_id` | bigint | ✅ 是 | 产品ID唯一 |
| `product_name` | varchar(100) | ✅ 是 | 产品名称 |
| `base_price` | decimal(10,2) | ✅ 是 | 产品基础底价 |
| `system_max_price` | decimal(10,2) | ✅ 是 | 产品价格上限 |
| `price_threshold` | decimal(10,2) | ❌ 否 | 提价标准阈值NULL表示不设阈值 |
| `price_fee_rate` | decimal(5,4) | ❌ 否 | 提价手续费比例NULL表示不收费0-1之间 |
### 11.2 配置优先级和默认值
**规则**
1. 所有价格参数必须从产品配置表读取
2. 如果产品配置记录不存在,应该报错或使用合理的默认值(建议报错,强制每个产品必须配置)
3. 可选字段(`price_threshold``price_fee_rate`如果为NULL表示不启用该功能
- `price_threshold = NULL` → 不设提价阈值
- `price_fee_rate = NULL` → 不收取提价手续费
### 11.3 代码修改示例
#### 修改 AgentService.AgentProcess 方法
```go
// AgentProcess 处理代理订单(新系统)
func (s *AgentService) AgentProcess(ctx context.Context, order *model.Order) error {
// 1-3. 前面的代码不变...
// 4. 获取产品配置(必须存在)
productConfig, err := s.AgentProductConfigModel.FindOneByProductId(ctx, order.ProductId)
if err != nil {
if errors.Is(err, model.ErrNotFound) {
return errors.Wrapf(err, "产品配置不存在, productId: %d请先在后台配置产品价格参数", order.ProductId)
}
return errors.Wrapf(err, "查询产品配置失败, productId: %d", order.ProductId)
}
// 使用产品配置的底价
basePrice := productConfig.BasePrice
// 6. 使用事务处理订单
return s.AgentWalletModel.Trans(ctx, func(transCtx context.Context, session sqlx.Session) error {
// 6.1 计算实际底价和代理收益
levelBonus, err := s.getLevelBonus(ctx, agent.Level)
if err != nil {
return errors.Wrapf(err, "获取等级加成配置失败")
}
actualBasePrice := basePrice + float64(levelBonus)
// 6.2 计算提价成本(使用产品配置)
priceThreshold := 0.0
priceFeeRate := 0.0
if productConfig.PriceThreshold.Valid {
priceThreshold = productConfig.PriceThreshold.Float64
}
if productConfig.PriceFeeRate.Valid {
priceFeeRate = productConfig.PriceFeeRate.Float64
}
priceCost := s.calculatePriceCost(agentOrder.SetPrice, priceThreshold, priceFeeRate)
// 6.3 计算代理收益
agentProfit := agentOrder.SetPrice - actualBasePrice - priceCost
// ... 后续代码不变 ...
})
}
```
#### 修改 PaymentLogic 创建订单时的价格计算
```go
// 如果是代理推广订单,创建完整的代理订单记录
if data.AgentIdentifier != "" && agentLinkModel != nil {
// ... 获取代理信息 ...
// 获取产品配置(必须存在)
productConfig, err := l.svcCtx.AgentProductConfigModel.FindOneByProductId(l.ctx, product.Id)
if err != nil {
if errors.Is(err, model.ErrNotFound) {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
"生成订单失败,产品配置不存在, productId: %d请先在后台配置产品价格参数", product.Id)
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
"生成订单, 查询产品配置失败: %+v", err)
}
// 使用产品配置的底价
basePrice := productConfig.BasePrice
// 计算实际底价(基础底价+等级加成)
levelBonus, _ := l.getLevelBonus(agent.Level)
actualBasePrice := basePrice + float64(levelBonus)
// 计算提价成本(使用产品配置)
priceThreshold := 0.0
priceFeeRate := 0.0
if productConfig.PriceThreshold.Valid {
priceThreshold = productConfig.PriceThreshold.Float64
}
if productConfig.PriceFeeRate.Valid {
priceFeeRate = productConfig.PriceFeeRate.Float64
}
priceCost := 0.0
if agentLinkModel.SetPrice > priceThreshold {
priceCost = (agentLinkModel.SetPrice - priceThreshold) * priceFeeRate
}
// 计算代理收益
agentProfit := agentLinkModel.SetPrice - actualBasePrice - priceCost
// ... 创建代理订单记录 ...
}
```
### 11.4 需要修改的文件清单
需要修改以支持产品配置的代码文件:
1. **`app/main/api/internal/service/agentService.go`**
- `AgentProcess()` 方法:从产品配置表读取价格参数
2. **`app/main/api/internal/logic/pay/paymentlogic.go`**
- 创建订单时的价格计算:从产品配置表读取价格参数
3. **`app/main/api/internal/logic/agent/getagentproductconfiglogic.go`**
- 移除从系统配置表读取价格参数的逻辑(只保留从产品配置表读取)
4. **`app/main/api/internal/logic/admin_agent/admingetagentconfiglogic.go`**
- 移除价格相关配置项的返回
5. **`app/main/api/internal/logic/admin_agent/adminupdateagentconfiglogic.go`**
- 移除价格相关配置项的更新逻辑
6. **后台管理系统前端**
- 系统配置页面:移除价格相关配置项
- 产品配置页面:确保可以正确配置所有价格参数