Files
huang b18ecfeb55
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m29s
refactor: 一次性佣金配置从套餐级别提升到系列级别
主要变更:
- 新增 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)
- 删除过时的单元测试(已被验收测试覆盖)
2026-02-04 14:28:44 +08:00

396 lines
10 KiB
Markdown
Raw Permalink 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.
# 套餐与佣金模型重构 - 前端接口迁移指南
> 版本: 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 类型定义
---
## 九、联系方式
如有疑问,请联系后端开发团队。