fetch(modify):修改套餐接口
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 4m40s

This commit is contained in:
sexygoat
2026-02-04 18:14:52 +08:00
parent 20e8c13e61
commit d97dc5f007
12 changed files with 979 additions and 452 deletions

View File

@@ -0,0 +1,140 @@
# Package Series Management Specification Delta
## MODIFIED Requirements
### Requirement: Package Series Data Model
套餐系列的数据模型SHALL支持一次性佣金配置包括固定佣金、梯度佣金、强制充值、时效类型等高级功能。
**字段定义**:
- `id` (number) - 系列ID
- `series_code` (string) - 系列编码,唯一标识
- `series_name` (string) - 系列名称
- `description` (string, optional) - 系列描述
- `enable_one_time_commission` (boolean) - 是否启用一次性佣金
- `one_time_commission_config` (SeriesOneTimeCommissionConfig, optional) - 一次性佣金配置对象
- `status` (number) - 状态 (1:启用, 2:禁用)
- `created_at` (string) - 创建时间
- `updated_at` (string) - 更新时间
**一次性佣金配置结构** (`SeriesOneTimeCommissionConfig`):
- `enable` (boolean) - 是否启用一次性佣金
- `commission_type` (string) - 佣金类型: "fixed"(固定) | "tiered"(梯度)
- `commission_amount` (number, optional) - 固定佣金金额commission_type=fixed时使用
- `threshold` (number) - 触发阈值(分)
- `trigger_type` (string) - 触发类型: "first_recharge"(首次充值) | "accumulated_recharge"(累计充值)
- `tiers` (OneTimeCommissionTier[], optional) - 梯度配置列表commission_type=tiered时使用
- `enable_force_recharge` (boolean) - 是否启用强充
- `force_amount` (number, optional) - 强充金额(分)
- `force_calc_type` (string, optional) - 强充计算类型: "fixed"(固定) | "dynamic"(动态)
- `validity_type` (string) - 时效类型: "permanent"(永久) | "fixed_date"(固定日期) | "relative"(相对时长)
- `validity_value` (string, optional) - 时效值(日期字符串或月数)
**梯度档位结构** (`OneTimeCommissionTier`):
- `threshold` (number) - 达标阈值
- `dimension` (string) - 统计维度: "sales_count"(销量) | "sales_amount"(销售额)
- `amount` (number) - 佣金金额(分)
- `stat_scope` (string, optional) - 统计范围: "self"(仅自己) | "self_and_sub"(自己+下级)
#### Scenario: 创建套餐系列并启用固定一次性佣金
- **GIVEN** 管理员登录系统
- **WHEN** 创建套餐系列时提供以下配置:
- `series_code`: "SERIES001"
- `series_name`: "标准流量系列"
- `enable_one_time_commission`: true
- `one_time_commission_config`:
- `enable`: true
- `commission_type`: "fixed"
- `commission_amount`: 5000 (50元)
- `threshold`: 10000 (100元)
- `trigger_type`: "first_recharge"
- `validity_type`: "permanent"
- **THEN** 系统SHALL创建套餐系列并保存一次性佣金配置
#### Scenario: 创建套餐系列并启用梯度一次性佣金
- **GIVEN** 管理员登录系统
- **WHEN** 创建套餐系列时提供以下配置:
- `series_code`: "SERIES002"
- `series_name`: "高级流量系列"
- `enable_one_time_commission`: true
- `one_time_commission_config`:
- `enable`: true
- `commission_type`: "tiered"
- `threshold`: 5000
- `trigger_type`: "accumulated_recharge"
- `tiers`: [
{ threshold: 10, dimension: "sales_count", amount: 3000 },
{ threshold: 50, dimension: "sales_count", amount: 8000 }
]
- `validity_type`: "relative"
- `validity_value`: "12" (12个月)
- **THEN** 系统SHALL创建套餐系列并保存梯度佣金配置
#### Scenario: 查询启用一次性佣金的套餐系列
- **GIVEN** 系统中存在多个套餐系列,部分启用了一次性佣金
- **WHEN** 使用查询参数 `enable_one_time_commission=true` 查询列表
- **THEN** 系统SHALL返回所有启用一次性佣金的套餐系列
#### Scenario: 更新套餐系列的一次性佣金配置
- **GIVEN** 系统中存在ID为1的套餐系列
- **WHEN** 更新该系列时提供新的一次性佣金配置:
- `one_time_commission_config.commission_amount`: 8000 (从5000更新到8000)
- `one_time_commission_config.enable_force_recharge`: true
- `one_time_commission_config.force_amount`: 20000
- `one_time_commission_config.force_calc_type`: "fixed"
- **THEN** 系统SHALL更新套餐系列的一次性佣金配置并返回更新后的数据
#### Scenario: 获取套餐系列详情时包含完整的一次性佣金配置
- **GIVEN** 系统中存在ID为1的套餐系列已配置一次性佣金
- **WHEN** 请求获取该系列的详情 (GET /api/admin/package-series/1)
- **THEN** 系统SHALL返回包含完整 `one_time_commission_config` 对象的响应数据
## ADDED Requirements
### Requirement: One-Time Commission Query Filter
系统SHALL支持按一次性佣金启用状态筛选套餐系列列表。
#### Scenario: 按一次性佣金启用状态筛选
- **GIVEN** 系统中存在多个套餐系列
- **WHEN** 使用查询参数 `enable_one_time_commission=true`
- **THEN** 系统SHALL只返回 `enable_one_time_commission` 为 true 的套餐系列
- **AND** 分页信息正确反映筛选后的结果数量
### Requirement: One-Time Commission Configuration Validation
系统SHALL验证一次性佣金配置的完整性和逻辑一致性。
#### Scenario: 固定佣金模式的验证
- **GIVEN** 管理员创建套餐系列
- **WHEN** `commission_type` 为 "fixed"
- **THEN** 系统SHALL要求 `commission_amount` 字段必填
- **AND** `tiers` 字段不应被使用
#### Scenario: 梯度佣金模式的验证
- **GIVEN** 管理员创建套餐系列
- **WHEN** `commission_type` 为 "tiered"
- **THEN** 系统SHALL要求 `tiers` 数组不为空
- **AND** 每个梯度档位的 `threshold`, `dimension`, `amount` 字段必填
#### Scenario: 强制充值配置的验证
- **GIVEN** 管理员创建套餐系列
- **WHEN** `enable_force_recharge` 为 true
- **THEN** 系统SHALL要求 `force_amount``force_calc_type` 字段必填
#### Scenario: 时效配置的验证
- **GIVEN** 管理员创建套餐系列
- **WHEN** `validity_type` 为 "fixed_date"
- **THEN** 系统SHALL要求 `validity_value` 字段必填,且格式为有效的日期字符串
- **WHEN** `validity_type` 为 "relative"
- **THEN** 系统SHALL要求 `validity_value` 字段必填,且为表示月数的数字字符串

View File

@@ -0,0 +1,158 @@
# Shop Package Allocation Specification Delta
## MODIFIED Requirements
### Requirement: Shop Package Allocation Data Model
单套餐分配的数据模型SHALL新增系列关联字段和分配者信息字段以支持更完整的分配关系追溯。
**字段定义**:
- `id` (number) - 分配ID
- `package_id` (number) - 套餐ID
- `package_code` (string) - 套餐编码
- `package_name` (string) - 套餐名称
- `series_id` (number) - 套餐系列ID
- `series_name` (string) - 套餐系列名称
- `shop_id` (number) - 被分配的店铺ID
- `shop_name` (string) - 被分配的店铺名称
- `allocator_shop_id` (number) - 分配者店铺ID0表示平台分配
- `allocator_shop_name` (string) - 分配者店铺名称
- `series_allocation_id` (number, nullable) - 关联的系列分配ID可选
- `cost_price` (number) - 该代理的成本价(分)
- `status` (number) - 状态 (1:启用, 2:禁用)
- `created_at` (string) - 创建时间
- `updated_at` (string) - 更新时间
**查询参数** (`ShopPackageAllocationQueryParams`):
- `page` (number, optional) - 页码
- `page_size` (number, optional) - 每页数量
- `shop_id` (number, optional) - 被分配的店铺ID
- `package_id` (number, optional) - 套餐ID
- `series_allocation_id` (number, optional) - 系列分配ID
- `allocator_shop_id` (number, optional) - 分配者店铺ID
- `status` (number, optional) - 状态
#### Scenario: 创建单套餐分配时包含系列信息
- **GIVEN** 平台管理员登录系统
- **AND** 系统中存在ID为10的套餐该套餐属于系列ID为2系列名称为"标准流量系列"
- **AND** 系统中存在ID为100的店铺
- **WHEN** 创建单套餐分配:
- `package_id`: 10
- `shop_id`: 100
- `cost_price`: 15000
- **THEN** 系统SHALL创建单套餐分配记录
- **AND** 响应数据中自动填充 `series_id` 为 2
- **AND** 响应数据中自动填充 `series_name` 为 "标准流量系列"
- **AND** 响应数据中 `allocator_shop_id` 为 0平台分配
#### Scenario: 创建单套餐分配并关联系列分配
- **GIVEN** 系统中存在ID为20的系列分配关联系列ID为2店铺ID为100
- **AND** 系列2下存在套餐ID为10
- **WHEN** 为店铺100创建套餐10的分配
- **THEN** 系统MAY自动关联系列分配设置 `series_allocation_id` 为 20
#### Scenario: 查询单套餐分配列表并显示完整关联信息
- **GIVEN** 系统中存在多个单套餐分配
- **WHEN** 查询单套餐分配列表 (GET /api/admin/shop-package-allocations)
- **THEN** 系统SHALL返回所有分配记录
- **AND** 每条记录包含 `series_id`, `series_name`, `allocator_shop_id`, `allocator_shop_name`
- **AND** 如果存在关联的系列分配,`series_allocation_id` 不为空
#### Scenario: 按系列分配ID筛选单套餐分配
- **GIVEN** 系统中存在多个单套餐分配部分关联了系列分配ID为20的系列分配
- **WHEN** 使用查询参数 `series_allocation_id=20`
- **THEN** 系统SHALL返回所有 `series_allocation_id` 为 20 的单套餐分配记录
#### Scenario: 按分配者店铺ID筛选单套餐分配
- **GIVEN** 系统中存在多个单套餐分配
- **WHEN** 使用查询参数 `allocator_shop_id=50`
- **THEN** 系统SHALL返回所有由店铺ID为50的代理商创建的单套餐分配记录
#### Scenario: 获取单套餐分配详情时显示完整信息
- **GIVEN** 系统中存在ID为100的单套餐分配
- **WHEN** 请求获取该分配的详情 (GET /api/admin/shop-package-allocations/100)
- **THEN** 响应数据SHALL包含所有字段包括:
- `series_id`, `series_name` - 套餐所属系列信息
- `allocator_shop_id`, `allocator_shop_name` - 分配者信息
- `series_allocation_id` - 关联的系列分配ID如果存在
## RENAMED Requirements
- FROM: `allocation_id`
- TO: `series_allocation_id`
**说明**: 将字段名从 `allocation_id` 重命名为 `series_allocation_id`使其语义更加明确表示关联的系列分配ID。
## REMOVED Requirements
### Requirement: Calculated Cost Price Field
旧版的 `calculated_cost_price` 字段已被移除。
**Reason**: 该字段仅用于参考,增加了数据模型的复杂性,且前端很少使用。成本价信息应直接使用 `cost_price` 字段。
**Migration**: 移除所有使用 `calculated_cost_price` 字段的代码。如果需要查看原始成本价信息,可以通过关联的系列分配或套餐系列获取。
## ADDED Requirements
### Requirement: Series Information in Package Allocation
系统SHALL在单套餐分配响应数据中包含套餐所属系列的ID和名称。
#### Scenario: 创建分配时自动关联系列信息
- **GIVEN** 系统中存在套餐,且该套餐属于某个系列
- **WHEN** 创建单套餐分配
- **THEN** 系统SHALL自动从套餐数据中获取 `series_id``series_name`
- **AND** 填充到分配响应数据中
### Requirement: Allocator Information Tracking in Package Allocation
系统SHALL记录单套餐分配的创建者分配者信息包括分配者店铺ID和名称。
#### Scenario: 平台创建的单套餐分配标记为平台分配
- **GIVEN** 平台管理员登录系统
- **WHEN** 创建单套餐分配
- **THEN** 系统SHALL自动设置 `allocator_shop_id` 为 0
- **AND** `allocator_shop_name` 为 "平台" 或相应的平台标识
#### Scenario: 代理商创建的单套餐分配记录代理商信息
- **GIVEN** 代理商A登录系统shop_id为50shop_name为"代理商A"
- **WHEN** 创建单套餐分配给下级代理
- **THEN** 系统SHALL自动设置 `allocator_shop_id` 为 50
- **AND** `allocator_shop_name` 为 "代理商A"
### Requirement: Query by Allocator Shop ID
系统SHALL支持按分配者店铺ID筛选单套餐分配列表。
#### Scenario: 查看平台创建的所有分配
- **GIVEN** 系统中存在多个单套餐分配
- **WHEN** 使用查询参数 `allocator_shop_id=0`
- **THEN** 系统SHALL返回所有由平台创建的单套餐分配记录
#### Scenario: 查看特定代理商创建的所有分配
- **GIVEN** 系统中存在多个单套餐分配
- **WHEN** 使用查询参数 `allocator_shop_id=50`
- **THEN** 系统SHALL返回所有由店铺ID为50的代理商创建的单套餐分配记录
### Requirement: Query by Series Allocation ID
系统SHALL支持按系列分配ID筛选单套餐分配列表以便查找由特定系列分配派生的所有单套餐分配。
#### Scenario: 查找系列分配的所有派生单套餐分配
- **GIVEN** 系统中存在系列分配ID为20的系列分配
- **AND** 该系列分配下有多个单套餐分配
- **WHEN** 使用查询参数 `series_allocation_id=20`
- **THEN** 系统SHALL返回所有关联该系列分配的单套餐分配记录

View File

@@ -0,0 +1,162 @@
# Shop Series Allocation Specification Delta
## MODIFIED Requirements
### Requirement: Shop Series Allocation Data Model
套餐系列分配的数据模型SHALL重构为更细粒度的佣金配置结构移除旧的 `base_commission` 模式,采用独立的一次性佣金和强制充值配置字段。
**字段定义**:
- `id` (number) - 分配ID
- `series_id` (number) - 套餐系列ID
- `series_name` (string) - 套餐系列名称
- `series_code` (string) - 套餐系列编码
- `shop_id` (number) - 被分配的店铺ID
- `shop_name` (string) - 被分配的店铺名称
- `allocator_shop_id` (number) - 分配者店铺ID0表示平台分配
- `allocator_shop_name` (string) - 分配者店铺名称
- `enable_one_time_commission` (boolean) - 是否启用一次性佣金
- `one_time_commission_amount` (number) - 该代理能拿的一次性佣金金额上限(分)
- `one_time_commission_threshold` (number, optional) - 一次性佣金触发阈值(分)
- `one_time_commission_trigger` (string, optional) - 一次性佣金触发类型: "first_recharge" | "accumulated_recharge"
- `enable_force_recharge` (boolean) - 是否启用强制充值
- `force_recharge_amount` (number, optional) - 强制充值金额(分)
- `force_recharge_trigger_type` (number, optional) - 强充触发类型: 1(单次充值) | 2(累计充值)
- `status` (number) - 状态 (1:启用, 2:禁用)
- `created_at` (string) - 创建时间
- `updated_at` (string) - 更新时间
**创建请求字段** (`CreateShopSeriesAllocationRequest`):
- `series_id` (number, required) - 套餐系列ID
- `shop_id` (number, required) - 被分配的店铺ID
- `one_time_commission_amount` (number, required) - 一次性佣金金额上限(分)
- `enable_one_time_commission` (boolean, optional) - 是否启用一次性佣金
- `one_time_commission_threshold` (number, optional) - 一次性佣金触发阈值(分)
- `one_time_commission_trigger` (string, optional) - 一次性佣金触发类型
- `enable_force_recharge` (boolean, optional) - 是否启用强制充值
- `force_recharge_amount` (number, optional) - 强制充值金额(分)
- `force_recharge_trigger_type` (number, optional) - 强充触发类型
**更新请求字段** (`UpdateShopSeriesAllocationRequest`):
- 所有字段均为可选,允许部分更新
- `enable_one_time_commission` (boolean, optional)
- `one_time_commission_amount` (number, optional)
- `one_time_commission_threshold` (number, optional)
- `one_time_commission_trigger` (string, optional)
- `enable_force_recharge` (boolean, optional)
- `force_recharge_amount` (number, optional)
- `force_recharge_trigger_type` (number, optional)
- `status` (number, optional)
#### Scenario: 创建系列分配并启用一次性佣金
- **GIVEN** 平台管理员登录系统
- **AND** 系统中存在ID为1的套餐系列和ID为100的店铺
- **WHEN** 创建系列分配时提供以下配置:
- `series_id`: 1
- `shop_id`: 100
- `one_time_commission_amount`: 5000
- `enable_one_time_commission`: true
- `one_time_commission_threshold`: 10000
- `one_time_commission_trigger`: "first_recharge"
- **THEN** 系统SHALL创建系列分配记录
- **AND** 响应数据中 `allocator_shop_id` 为 0平台分配
- **AND** 响应数据中包含所有一次性佣金配置字段
#### Scenario: 创建系列分配并启用强制充值
- **GIVEN** 代理商A登录系统shop_id为50
- **AND** 系统中存在ID为2的套餐系列和ID为101的下级代理店铺
- **WHEN** 创建系列分配时提供以下配置:
- `series_id`: 2
- `shop_id`: 101
- `one_time_commission_amount`: 3000
- `enable_force_recharge`: true
- `force_recharge_amount`: 15000
- `force_recharge_trigger_type`: 1 (单次充值)
- **THEN** 系统SHALL创建系列分配记录
- **AND** 响应数据中 `allocator_shop_id` 为 50代理商A
- **AND** 响应数据中包含所有强制充值配置字段
#### Scenario: 更新系列分配的一次性佣金配置
- **GIVEN** 系统中存在ID为10的系列分配
- **WHEN** 更新该分配时提供以下字段:
- `one_time_commission_amount`: 8000 (从5000更新到8000)
- `one_time_commission_threshold`: 20000
- **THEN** 系统SHALL更新指定字段
- **AND** 其他字段保持不变
- **AND** 响应数据中 `updated_at` 字段更新为当前时间
#### Scenario: 更新系列分配的强制充值配置
- **GIVEN** 系统中存在ID为10的系列分配
- **WHEN** 更新该分配时提供以下字段:
- `enable_force_recharge`: true
- `force_recharge_amount`: 25000
- `force_recharge_trigger_type`: 2 (累计充值)
- **THEN** 系统SHALL更新强制充值配置
- **AND** 响应数据中包含更新后的强制充值字段
#### Scenario: 查询系列分配列表并显示分配者信息
- **GIVEN** 系统中存在多个系列分配,部分由平台创建,部分由代理商创建
- **WHEN** 查询系列分配列表 (GET /api/admin/shop-series-allocations)
- **THEN** 系统SHALL返回所有分配记录
- **AND** 每条记录包含 `allocator_shop_id``allocator_shop_name`
- **AND** 平台创建的分配记录中 `allocator_shop_id` 为 0
#### Scenario: 按分配者店铺ID筛选系列分配
- **GIVEN** 系统中存在多个系列分配
- **WHEN** 使用查询参数 `allocator_shop_id=50`
- **THEN** 系统SHALL返回所有由店铺ID为50的代理商创建的分配记录
## REMOVED Requirements
### Requirement: Base Commission Configuration
旧版的 `base_commission` 配置模式已被移除,不再使用 `BaseCommissionConfig` 类型。
**Reason**: 新的佣金配置模型更加灵活和细粒度,将一次性佣金配置分散到独立字段中,便于查询和管理。
**Migration**: 现有使用 `base_commission` 字段的代码需要迁移到新的字段结构。如果有历史数据,需要后端提供数据迁移方案。
### Requirement: Tiered Commission Configuration
旧版的 `TierCommissionConfig` (周期性梯度返佣) 配置已被移除。
**Reason**: 系列分配层面不再支持复杂的梯度返佣配置,改为在系列级别统一配置一次性佣金梯度。
**Migration**: 梯度佣金配置现在在套餐系列级别 (`PackageSeries.one_time_commission_config.tiers`) 进行管理。
## ADDED Requirements
### Requirement: Allocator Information Tracking
系统SHALL记录系列分配的创建者分配者信息包括分配者店铺ID和名称。
#### Scenario: 平台创建的分配标记为平台分配
- **GIVEN** 平台管理员登录系统
- **WHEN** 创建系列分配
- **THEN** 系统SHALL自动设置 `allocator_shop_id` 为 0
- **AND** `allocator_shop_name` 为 "平台" 或相应的平台标识
#### Scenario: 代理商创建的分配记录代理商信息
- **GIVEN** 代理商A登录系统shop_id为50shop_name为"代理商A"
- **WHEN** 创建系列分配给下级代理
- **THEN** 系统SHALL自动设置 `allocator_shop_id` 为 50
- **AND** `allocator_shop_name` 为 "代理商A"
### Requirement: Series Code in Allocation Response
系统SHALL在系列分配响应数据中包含套餐系列编码 (`series_code`)。
#### Scenario: 获取系列分配详情时包含系列编码
- **GIVEN** 系统中存在ID为10的系列分配关联系列编码为"SERIES001"
- **WHEN** 请求获取该分配的详情 (GET /api/admin/shop-series-allocations/10)
- **THEN** 响应数据中SHALL包含 `series_code` 字段
- **AND** 其值为 "SERIES001"