Files
one-pipe-system/openspec/changes/update-series-allocation-commission/design.md
sexygoat 841cf0442b
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 3m30s
fetch(add): 订单管理-企业设备
2026-01-29 15:43:45 +08:00

5.3 KiB

Design: 套餐系列分配佣金系统重构

Context

当前系统使用简单的定价模式(pricing_mode/pricing_value)和一次性佣金(one_time_commission_*)来管理套餐系列分配。随着业务发展,需要更复杂的佣金系统:

  • 支持基础返佣(固定金额或百分比)
  • 支持梯度返佣(根据销量或销售额分档返佣)
  • 更清晰的数据模型和API接口

背景约束:

  • 前后端需要同步部署(Breaking Change)
  • 需要数据迁移方案
  • 影响现有的套餐系列分配功能

Goals / Non-Goals

Goals:

  • 实现新的佣金配置模型,支持基础返佣和梯度返佣
  • 提供清晰的UI界面让用户配置复杂的返佣规则
  • 保证数据一致性和类型安全
  • 提供良好的用户体验(表单验证、错误提示)

Non-Goals:

  • 不处理历史数据的完整性验证(由后端负责)
  • 不实现佣金计算逻辑(由后端负责)
  • 不处理佣金结算流程(属于其他模块)

Decisions

1. Data Model Design

决策: 采用嵌套对象结构表示佣金配置

理由:

  • base_commission: { mode, value } - 清晰表达基础返佣的两个维度
  • tier_config: { period_type, tier_type, tiers[] } - 梯度配置与基础配置分离,可选性强
  • tiers: [{ threshold, mode, value }] - 每个档位都有独立的返佣模式和值

替代方案考虑:

  • 平铺所有字段 - 会导致字段过多,语义不清晰
  • 使用JSON字符串存储配置 - 失去类型安全,不利于表单编辑

2. UI Design Pattern

决策: 使用渐进式表单设计

表单结构:

1. 基础返佣配置 (必填)
   - 返佣模式: 单选 (固定金额/百分比)
   - 返佣值: 数字输入

2. 梯度返佣设置 (可选)
   - 启用开关: 是/否
   - [如果启用]:
     - 周期类型: 下拉 (月度/季度/年度)
     - 梯度类型: 下拉 (销量/销售额)
     - 档位列表: 动态表单
       * 阈值
       * 返佣模式
       * 返佣值
       * [添加]/[删除] 按钮

理由:

  • 渐进式设计降低初始复杂度
  • 只有启用梯度返佣时才显示相关配置
  • 动态档位列表提供灵活性

替代方案考虑:

  • 全部平铺展示 - 对不需要梯度返佣的用户造成困扰
  • 使用向导模式 - 增加操作步骤,不适合编辑场景

3. Form Validation Strategy

决策: 分层验证 + 条件验证

验证规则:

  1. 基础返佣配置:

    • mode: 必选
    • value: 必填,>= 0
  2. 梯度返佣配置(当启用时):

    • period_type: 必选
    • tier_type: 必选
    • tiers: 至少一个档位
    • 每个档位:
      • threshold: 必填,> 0
      • mode: 必选
      • value: 必填,> 0
    • 档位阈值必须递增

实现方式:

  • 使用 Element Plus 的表单验证
  • 自定义validator处理档位阈值递增验证
  • 使用 computed 动态生成验证规则

4. API Response Handling

决策: 统一使用 list 字段名,添加适配层

理由:

  • 后端统一规范使用 list 而非 items
  • 添加 total_pages 字段提供更完整的分页信息
  • 保持前端代码与后端规范一致

迁移策略:

// Before
const res = await getShopSeriesAllocations(params)
allocationList.value = res.data.items || []

// After
const res = await getShopSeriesAllocations(params)
allocationList.value = res.data.list || []

Risks / Trade-offs

Risk 1: Breaking Change导致部署协调困难

风险: 前后端必须同时部署,否则会出现接口不兼容

缓解措施:

  • 与后端团队协调部署窗口
  • 准备回退方案(前端代码分支)
  • 在测试环境充分验证

Risk 2: 复杂表单导致用户体验问题

风险: 梯度返佣配置较复杂,用户可能不理解

缓解措施:

  • 提供清晰的字段说明
  • 添加示例或帮助文档链接
  • 使用默认值简化初次配置

Risk 3: 数据迁移可能失败

风险: 旧数据无法完全转换为新模型

缓解措施:

  • 要求后端提供数据迁移脚本和验证
  • 在迁移后检查数据完整性
  • 保留旧数据备份

Migration Plan

Phase 1: 准备阶段

  1. 与后端确认API变更细节和时间表
  2. 在开发环境实现前端变更
  3. 与后端在测试环境联调

Phase 2: 测试阶段

  1. 功能测试: 创建、编辑、删除、列表展示
  2. 集成测试: 与后端API集成
  3. 用户验收测试: 业务人员验证

Phase 3: 部署阶段

  1. 准备回退方案
  2. 与后端协调部署窗口
  3. 同步部署前后端
  4. 验证生产环境功能

Phase 4: 监控阶段

  1. 监控API错误率
  2. 收集用户反馈
  3. 修复遗留问题

Rollback Plan

如果部署后发现严重问题:

  1. 前端回退到上一版本
  2. 后端回退API(如果可能)
  3. 通知用户暂时不可用
  4. 修复问题后重新部署

Open Questions

  1. Q: 梯度返佣的档位数量是否有上限?

    • A: 待后端确认,前端可以先不限制或设置合理上限(如10个)
  2. Q: 返佣值的单位和精度如何处理?

    • A: 固定金额使用"分"为单位,百分比使用千分比(如200=20%),待后端确认
  3. Q: 是否需要在列表页显示梯度返佣信息?

    • A: 暂时只显示基础返佣,梯度信息在详情或编辑时查看
  4. Q: 旧数据如何映射到新模型?

    • A: 待后端提供迁移方案,前端需要能够正确显示迁移后的数据