All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m29s
主要变更: - 新增 tb_shop_series_allocation 表,存储系列级别的一次性佣金配置 - ShopPackageAllocation 移除 one_time_commission_amount 字段 - PackageSeries 新增 enable_one_time_commission 字段控制是否启用一次性佣金 - 新增 /api/admin/shop-series-allocations CRUD 接口 - 佣金计算逻辑改为从 ShopSeriesAllocation 获取一次性佣金金额 - 删除废弃的 ShopSeriesOneTimeCommissionTier 模型 - OpenAPI Tag '系列分配' 和 '单套餐分配' 合并为 '套餐分配' 迁移脚本: - 000042: 重构佣金套餐模型 - 000043: 简化佣金分配 - 000044: 一次性佣金分配重构 - 000045: PackageSeries 添加 enable_one_time_commission 字段 测试: - 新增验收测试 (shop_series_allocation, commission_calculation) - 新增流程测试 (one_time_commission_chain) - 删除过时的单元测试(已被验收测试覆盖)
396 lines
10 KiB
Markdown
396 lines
10 KiB
Markdown
# 套餐与佣金模型重构 - 前端接口迁移指南
|
||
|
||
> 版本: v1.1
|
||
> 更新日期: 2026-02-03
|
||
> 影响范围: 套餐管理、系列管理、分配管理相关接口
|
||
|
||
---
|
||
|
||
## 一、变更概述
|
||
|
||
本次重构主要目标:
|
||
1. 简化套餐价格字段(移除语义不清的字段)
|
||
2. 支持真流量/虚流量共存机制
|
||
3. 实现一次性佣金链式分配(上级给下级设置金额)
|
||
4. 统一分配模型
|
||
|
||
### ⚠️ 重要:废弃内容汇总
|
||
|
||
**请确保前端代码中不再使用以下内容:**
|
||
|
||
#### 已废弃的枚举值
|
||
|
||
| 旧值 | 新值 | 说明 |
|
||
|------|------|------|
|
||
| `single_recharge` | `first_recharge` | 触发类型:单次充值 → 首充 |
|
||
|
||
#### 已废弃的请求字段(系列分配接口)
|
||
|
||
以下字段在系列分配接口中**已完全移除**,前端不应再传递:
|
||
|
||
```json
|
||
// ❌ 以下字段已废弃,请勿使用
|
||
{
|
||
"enable_one_time_commission": true, // 已废弃
|
||
"one_time_commission_type": "fixed", // 已废弃
|
||
"one_time_commission_trigger": "...", // 已废弃
|
||
"one_time_commission_threshold": 10000, // 已废弃
|
||
"one_time_commission_mode": "fixed", // 已废弃
|
||
"one_time_commission_value": 5000, // 已废弃
|
||
"enable_force_recharge": false, // 已废弃
|
||
"force_recharge_amount": 0 // 已废弃
|
||
}
|
||
```
|
||
|
||
**替代方案**:一次性佣金规则现在在**套餐系列**中配置,系列分配只需设置 `one_time_commission_amount`。
|
||
|
||
#### 已废弃的响应字段
|
||
|
||
系列分配响应中不再返回以下字段:
|
||
- `one_time_commission_type`
|
||
- `one_time_commission_trigger`
|
||
- `one_time_commission_threshold`
|
||
- `one_time_commission_mode`
|
||
- `one_time_commission_value`
|
||
- `enable_force_recharge`
|
||
- `force_recharge_amount`
|
||
- `force_recharge_trigger_type`
|
||
- `one_time_commission_tiers`(完整梯度配置)
|
||
|
||
---
|
||
|
||
## 二、套餐接口变更
|
||
|
||
### 2.1 创建套餐 `POST /api/admin/packages`
|
||
|
||
**❌ 移除字段**:
|
||
```json
|
||
{
|
||
"price": 9900, // 已移除
|
||
"data_type": "real", // 已移除
|
||
"data_amount_mb": 1024 // 已移除
|
||
}
|
||
```
|
||
|
||
**✅ 新增字段**:
|
||
```json
|
||
{
|
||
"enable_virtual_data": true, // 是否启用虚流量
|
||
"real_data_mb": 1024, // 真流量额度(MB) - 必填
|
||
"virtual_data_mb": 512, // 虚流量额度(MB) - 启用虚流量时必填
|
||
"cost_price": 5000 // 成本价(分) - 必填
|
||
}
|
||
```
|
||
|
||
**完整请求示例**:
|
||
```json
|
||
{
|
||
"package_code": "PKG_001",
|
||
"package_name": "月度套餐",
|
||
"series_id": 1,
|
||
"package_type": "formal",
|
||
"duration_months": 1,
|
||
"real_data_mb": 1024,
|
||
"virtual_data_mb": 512,
|
||
"enable_virtual_data": true,
|
||
"cost_price": 5000,
|
||
"suggested_retail_price": 9900
|
||
}
|
||
```
|
||
|
||
**校验规则**:
|
||
- 启用虚流量时 (`enable_virtual_data: true`):
|
||
- `virtual_data_mb` 必须 > 0
|
||
- `virtual_data_mb` 必须 ≤ `real_data_mb`
|
||
|
||
---
|
||
|
||
### 2.2 更新套餐 `PUT /api/admin/packages/:id`
|
||
|
||
字段变更同上,所有字段均为可选。
|
||
|
||
---
|
||
|
||
### 2.3 套餐列表/详情响应变更
|
||
|
||
**✅ 新增字段**(代理用户可见):
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"package_code": "PKG_001",
|
||
"package_name": "月度套餐",
|
||
"real_data_mb": 1024,
|
||
"virtual_data_mb": 512,
|
||
"enable_virtual_data": true,
|
||
"cost_price": 5000,
|
||
"suggested_retail_price": 9900,
|
||
|
||
// 以下字段仅代理用户可见
|
||
"one_time_commission_amount": 1000, // 该代理能拿到的一次性佣金(分)
|
||
"profit_margin": 4900, // 利润空间(分)
|
||
"current_commission_rate": "5.00元/单",
|
||
"tier_info": {
|
||
"current_rate": "5.00元/单",
|
||
"next_threshold": 100,
|
||
"next_rate": "8.00元/单"
|
||
}
|
||
}
|
||
```
|
||
|
||
**说明**:
|
||
- `cost_price`: 对于平台/平台用户是基础成本价,对于代理用户是该代理的成本价(从分配关系中获取)
|
||
- `one_time_commission_amount`: 该代理能拿到的一次性佣金金额
|
||
|
||
---
|
||
|
||
## 三、套餐系列接口变更
|
||
|
||
### 3.1 创建/更新套餐系列
|
||
|
||
**✅ 新增嵌套结构 `one_time_commission_config`**:
|
||
|
||
```json
|
||
{
|
||
"series_code": "SERIES_001",
|
||
"series_name": "标准套餐系列",
|
||
"description": "包含所有标准流量套餐",
|
||
"one_time_commission_config": {
|
||
"enable": true,
|
||
"trigger_type": "first_recharge",
|
||
"threshold": 10000,
|
||
"commission_type": "fixed",
|
||
"commission_amount": 5000,
|
||
"validity_type": "permanent",
|
||
"validity_value": "",
|
||
"enable_force_recharge": false,
|
||
"force_calc_type": "fixed",
|
||
"force_amount": 0
|
||
}
|
||
}
|
||
```
|
||
|
||
**字段说明**:
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `enable` | boolean | 是否启用一次性佣金 |
|
||
| `trigger_type` | string | 触发类型: `first_recharge`(首充) / `accumulated_recharge`(累计充值) |
|
||
| `threshold` | int64 | 触发阈值(分) |
|
||
| `commission_type` | string | 佣金类型: `fixed`(固定) / `tiered`(梯度) |
|
||
| `commission_amount` | int64 | 固定佣金金额(分),`commission_type=fixed` 时使用 |
|
||
| `validity_type` | string | 时效类型: `permanent`(永久) / `fixed_date`(固定日期) / `relative`(相对时长) |
|
||
| `validity_value` | string | 时效值: 日期(2026-12-31) 或 月数(12) |
|
||
| `enable_force_recharge` | boolean | 是否启用强充 |
|
||
| `force_calc_type` | string | 强充计算类型: `fixed`(固定) / `dynamic`(动态) |
|
||
| `force_amount` | int64 | 强充金额(分),`force_calc_type=fixed` 时使用 |
|
||
|
||
---
|
||
|
||
## 四、系列分配接口变更
|
||
|
||
### 4.1 创建系列分配 `POST /api/admin/shop-series-allocations`
|
||
|
||
**❌ 移除字段**(旧接口中的一次性佣金完整配置):
|
||
```json
|
||
{
|
||
"enable_one_time_commission": true,
|
||
"one_time_commission_type": "fixed",
|
||
"one_time_commission_trigger": "single_recharge",
|
||
"one_time_commission_threshold": 10000,
|
||
"one_time_commission_mode": "fixed",
|
||
"one_time_commission_value": 5000,
|
||
"enable_force_recharge": false,
|
||
"force_recharge_amount": 0
|
||
}
|
||
```
|
||
|
||
**✅ 新增字段**:
|
||
```json
|
||
{
|
||
"shop_id": 10,
|
||
"series_id": 1,
|
||
"base_commission": {
|
||
"mode": "fixed",
|
||
"value": 500
|
||
},
|
||
"one_time_commission_amount": 5000 // 给被分配店铺的一次性佣金金额(分)
|
||
}
|
||
```
|
||
|
||
**说明**:
|
||
- 一次性佣金的规则(触发条件、阈值、时效等)现在在**套餐系列**中统一配置
|
||
- 系列分配只需要设置**给下级的金额**
|
||
|
||
---
|
||
|
||
### 4.2 系列分配响应
|
||
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"shop_id": 10,
|
||
"shop_name": "测试店铺",
|
||
"series_id": 1,
|
||
"series_name": "标准套餐系列",
|
||
"allocator_shop_id": 5,
|
||
"allocator_shop_name": "上级店铺",
|
||
"base_commission": {
|
||
"mode": "fixed",
|
||
"value": 500
|
||
},
|
||
"one_time_commission_amount": 5000,
|
||
"status": 1,
|
||
"created_at": "2026-02-03T10:00:00Z",
|
||
"updated_at": "2026-02-03T10:00:00Z"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 五、套餐分配接口变更
|
||
|
||
### 5.1 创建/更新套餐分配
|
||
|
||
**✅ 新增字段**:
|
||
```json
|
||
{
|
||
"shop_id": 10,
|
||
"package_id": 1,
|
||
"cost_price": 6000,
|
||
"one_time_commission_amount": 3000 // 给下级的一次性佣金金额(分)
|
||
}
|
||
```
|
||
|
||
**校验规则**:
|
||
- `one_time_commission_amount` 必须 ≥ 0
|
||
- `one_time_commission_amount` 不能超过上级能拿到的金额
|
||
- 平台用户不受金额限制
|
||
|
||
---
|
||
|
||
### 5.2 套餐分配响应
|
||
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"shop_id": 10,
|
||
"shop_name": "下级店铺",
|
||
"package_id": 1,
|
||
"package_name": "月度套餐",
|
||
"package_code": "PKG_001",
|
||
"allocation_id": 5,
|
||
"cost_price": 6000,
|
||
"calculated_cost_price": 5500,
|
||
"one_time_commission_amount": 3000,
|
||
"status": 1,
|
||
"created_at": "2026-02-03T10:00:00Z",
|
||
"updated_at": "2026-02-03T10:00:00Z"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 六、一次性佣金链式分配说明
|
||
|
||
### 6.1 概念
|
||
|
||
```
|
||
平台设置系列一次性佣金规则:首充 100 元返 50 元
|
||
|
||
平台 → 一级代理 A(给 A 设置 40 元)
|
||
↓
|
||
一级代理 A → 二级代理 B(给 B 设置 25 元)
|
||
↓
|
||
二级代理 B → 三级代理 C(给 C 设置 10 元)
|
||
```
|
||
|
||
当三级代理 C 的客户首充 100 元时:
|
||
- 三级代理 C 获得: 10 元
|
||
- 二级代理 B 获得: 25 - 10 = 15 元
|
||
- 一级代理 A 获得: 40 - 25 = 15 元
|
||
- 平台获得: 50 - 40 = 10 元
|
||
|
||
### 6.2 前端展示建议
|
||
|
||
在分配界面展示:
|
||
- "上级能拿到的一次性佣金: 40 元"
|
||
- "给下级设置的一次性佣金: [输入框,最大 40 元]"
|
||
- "自己实际获得: [自动计算] 元"
|
||
|
||
---
|
||
|
||
## 七、枚举值参考
|
||
|
||
### 触发类型 (trigger_type)
|
||
| 值 | 说明 |
|
||
|----|------|
|
||
| `first_recharge` | 首充触发 |
|
||
| `accumulated_recharge` | 累计充值触发 |
|
||
|
||
### 佣金类型 (commission_type)
|
||
| 值 | 说明 |
|
||
|----|------|
|
||
| `fixed` | 固定金额 |
|
||
| `tiered` | 梯度(根据销量/销售额) |
|
||
|
||
### 时效类型 (validity_type)
|
||
| 值 | 说明 | validity_value 格式 |
|
||
|----|------|---------------------|
|
||
| `permanent` | 永久有效 | 空 |
|
||
| `fixed_date` | 固定到期日 | `2026-12-31` |
|
||
| `relative` | 相对时长(激活后N月) | `12` |
|
||
|
||
### 强充计算类型 (force_calc_type)
|
||
| 值 | 说明 |
|
||
|----|------|
|
||
| `fixed` | 固定金额 |
|
||
| `dynamic` | 动态计算(max(首充要求, 套餐售价)) |
|
||
|
||
---
|
||
|
||
## 八、迁移检查清单
|
||
|
||
### 🔴 必须删除的代码
|
||
|
||
**请搜索并删除以下内容:**
|
||
|
||
```bash
|
||
# 搜索废弃的枚举值
|
||
grep -r "single_recharge" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.vue"
|
||
|
||
# 搜索废弃的字段名
|
||
grep -r "one_time_commission_type\|one_time_commission_trigger\|one_time_commission_threshold\|one_time_commission_mode\|one_time_commission_value\|enable_one_time_commission\|force_recharge_amount\|enable_force_recharge" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.vue"
|
||
```
|
||
|
||
### 套餐管理页面
|
||
- [ ] 移除 `price`、`data_type`、`data_amount_mb` 字段
|
||
- [ ] 新增 `enable_virtual_data` 开关
|
||
- [ ] 新增虚流量校验逻辑(≤ 真流量)
|
||
- [ ] 代理视角显示 `one_time_commission_amount`
|
||
|
||
### 套餐系列管理页面
|
||
- [ ] 新增一次性佣金规则配置表单
|
||
- [ ] 支持时效类型选择和值输入
|
||
- [ ] 触发类型使用 `first_recharge`(不是旧的 `single_recharge`)
|
||
|
||
### 系列分配页面
|
||
- [ ] **删除**旧的一次性佣金完整配置表单(8个字段)
|
||
- [ ] **删除**梯度配置表单
|
||
- [ ] 新增 `one_time_commission_amount` 输入(金额字段)
|
||
- [ ] 显示上级能拿到的最大金额作为输入上限
|
||
|
||
### 套餐分配页面
|
||
- [ ] 新增 `one_time_commission_amount` 输入
|
||
- [ ] 显示校验错误(超过上级金额限制)
|
||
|
||
### 全局检查
|
||
- [ ] 将所有 `single_recharge` 替换为 `first_recharge`
|
||
- [ ] 移除系列分配相关的废弃字段引用
|
||
- [ ] 更新 TypeScript 类型定义
|
||
|
||
---
|
||
|
||
## 九、联系方式
|
||
|
||
如有疑问,请联系后端开发团队。
|