## 实施计划:GMV 支付方式拆分展示 ### 需求分析 当前渠道统计只展示一个"累计实付金额"(GMV 总数),用户无法看到这笔钱的构成。需要拆分为: - **现金支付** (`actual_amount`) — 用户通过微信支付的真金白银 - **优惠券抵扣** (`discount_amount`) — 优惠券抵扣部分 - **积分抵扣** (`points_amount`) — 积分抵扣部分(当前数据为0,但字段已预留) 验证:`total_amount = actual_amount + discount_amount + points_amount` 在所有订单上完全成立(0条不等式)。 ### 数据现状(dev 环境) | 支付方式 | 订单数 | 金额(元) | 占比 | |---------|--------|---------|------| | GMV 总额 | 3,595 | 124,526.80 | 100% | | 现金 | 3,595 | 90,067.85 | 72.3% | | 优惠券 | 1,896 | 34,458.95 | 27.7% | | 积分 | 0 | 0.00 | 0% | ### 技术方案 orders 表已有完整的拆分字段,**无需新建表或字段**,只需在查询和展示层增加维度。 ### 实施步骤 #### Step 1: 后端 — 扩展数据结构 文件:`internal/service/channel/channel.go` 1.1 `StatsOverview` 结构体新增字段: ```go CashCents int64 `json:"cash_cents"` // 现金支付(分) CouponCents int64 `json:"coupon_cents"` // 优惠券抵扣(分) PointsCents int64 `json:"points_cents"` // 积分抵扣(分) ``` 1.2 `StatsDailyItem` 结构体新增字段: ```go CashCents int64 `json:"cash_cents"` CouponCents int64 `json:"coupon_cents"` PointsCents int64 `json:"points_cents"` ``` #### Step 2: 后端 — 修改 GMV 查询方法 文件:`internal/service/channel/channel.go` 2.1 `calcGMVByTotalAmount` 改为同时返回 actual_amount / discount_amount / points_amount 的分组统计: ```go type GMVBreakdown struct { Total int64 Cash int64 Coupon int64 Points int64 } func calcGMVByTotalAmount(...) (GMVBreakdown, map[string]GMVBreakdown) ``` 查询 SELECT 增加:`orders.actual_amount, orders.discount_amount, orders.points_amount` 2.2 `GetStats` 方法中将拆分数据写入 Overview 和 Daily: ```go out.Overview.CashCents = breakdown.Cash out.Overview.CouponCents = breakdown.Coupon out.Overview.PointsCents = breakdown.Points ``` #### Step 3: 后端 — List 接口也返回拆分数据(可选) 文件:`internal/service/channel/channel.go` `ChannelWithStat` 结构体和 `List` 方法中的 GMV 查询也增加拆分统计,用于渠道列表页 tooltip 展示。 #### Step 4: 前端 — API 类型更新 文件:`web/admin/src/api/channels.ts` ```ts interface StatsOverview { // ... existing fields cash_cents?: number coupon_cents?: number points_cents?: number } interface StatsDailyItem { // ... existing fields cash_cents?: number coupon_cents?: number points_cents?: number } ``` #### Step 5: 前端 — Stats 概览卡片展示 文件:`web/admin/src/views/operations/channels/index.vue` 在"累计实付金额"卡片下方或旁边展示支付构成: - 显示 3 个子指标:现金 / 优惠券 / 积分 - 各自显示金额和占比百分比 - 积分为 0 时可隐藏或灰显 #### Step 6: 前端 — 每日趋势图支持 文件:`web/admin/src/views/operations/channels/index.vue` 在 revenue tab 的折线图中,可以选择查看: - GMV 总额(默认) - 现金 / 优惠券 / 积分 分层堆叠 #### Step 7: 测试 文件:`internal/service/channel/channel_stats_test.go` 更新测试用例,验证 GMV 拆分字段的正确性。 ### 关键文件 | 文件 | 操作 | 说明 | |------|------|------| | `internal/service/channel/channel.go` | 修改 | 数据结构 + 查询逻辑 | | `internal/service/channel/channel_stats_test.go` | 修改 | 测试覆盖拆分字段 | | `web/admin/src/api/channels.ts` | 修改 | API 类型定义 | | `web/admin/src/views/operations/channels/index.vue` | 修改 | 概览卡片 + 图表展示 | ### 风险与缓解 | 风险 | 缓解措施 | |------|----------| | 旧版前端未适配新字段 | 新字段均为可选,不影响旧版展示 | | 积分字段当前全为0 | 字段预留,后续开启积分抵扣时自动生效 | | 查询性能 | 无额外 JOIN,只增加 3 个 SUM 列,影响可忽略 |