3e265bd837
- 还原 /v1/public/user/invite_sales 接口及 /invite/sales 别名(与 invite_records 并存) 逻辑/handler/types 与197fed7d删除前版本完全一致,按fefbd4f5新 routes 结构注册 - 新增迁移 02155_promo_schema_fix: 幂等修复 subscribe_promo / order 列类型与索引偏差 - 同步 etc/ppanel.yaml 数据库连接配置 - 补齐相关需求与设计文档
560 lines
12 KiB
Markdown
560 lines
12 KiB
Markdown
# App 邀请列表与商品套餐折扣需求梳理
|
|
|
|
本文基于当前 `ppanel-server` 代码现状,对以下两个需求做整理:
|
|
|
|
1. App 需要一个“邀请列表/邀请记录”接口。
|
|
2. 商品套餐需要补充“折扣信息”,当存在折扣时,App 需要做样式展示,并支持用户继续下单购买。
|
|
|
|
目标是帮助产品、前端、后端快速统一口径,明确:
|
|
|
|
- 现在已有哪些接口可以复用
|
|
- 哪些地方确实需要新增
|
|
- “接口增加三个字段”更适合加在哪一层
|
|
|
|
---
|
|
|
|
## 1. 需求结论
|
|
|
|
### 1.1 邀请列表
|
|
|
|
当前公开侧已经有一部分邀请能力,但**没有一个完全匹配“App 邀请记录列表”语义的公开接口**。
|
|
|
|
现状:
|
|
|
|
- 已有 `GET /v1/public/user/affiliate/list`
|
|
- 能返回“我邀请了哪些用户”
|
|
- 但字段较少,只包含基础信息
|
|
- 已有 `GET /v1/public/user/invite_sales`
|
|
- 返回的是“被邀请用户的成交订单记录”
|
|
- 不是“邀请用户记录列表”
|
|
- 已有 `GET /v1/public/user/invite_stats`
|
|
- 返回邀请统计
|
|
- 不是列表
|
|
|
|
结论:
|
|
|
|
- 如果 App 只是要展示“我邀请了哪些人”,`/affiliate/list` 可以复用。
|
|
- 如果 App 需要展示“邀请时间、是否购买、购买次数、带来的佣金/赠送天数”等完整邀请记录,则**建议新增一个公开接口**。
|
|
|
|
### 1.2 商品套餐折扣
|
|
|
|
当前公开侧套餐列表接口 `GET /v1/public/subscribe/list` **已经返回 `discount` 字段**,下单预览接口 `POST /v1/public/order/pre` 也已经支持折扣计算。
|
|
|
|
现状:
|
|
|
|
- 套餐列表已有折扣规则数组 `discount`
|
|
- 预下单接口已有:
|
|
- 原价 `price`
|
|
- 实付 `amount`
|
|
- 折扣金额 `discount`
|
|
- 活动优惠 `promo_discount`
|
|
- 优惠券减免 `coupon_discount`
|
|
- 手续费 `fee_amount`
|
|
|
|
结论:
|
|
|
|
- 后端**不是完全没有折扣能力**,而是“已经有计算能力,但 App 展示层使用起来不够直接”。
|
|
- 如果需求明确要求“接口增加三个字段”,**更推荐补在套餐列表返回的 `discount[]` 子项里**,而不是直接加在下单接口里。
|
|
|
|
---
|
|
|
|
## 2. 当前代码现状
|
|
|
|
## 2.1 邀请相关
|
|
|
|
### 2.1.1 已有公开接口
|
|
|
|
#### A. 邀请基础列表
|
|
|
|
接口:
|
|
|
|
- `GET /v1/public/user/affiliate/list`
|
|
|
|
请求:
|
|
|
|
- `page`
|
|
- `size`
|
|
|
|
返回结构:
|
|
|
|
- `total`
|
|
- `list[]`
|
|
- `identifier`
|
|
- `avatar`
|
|
- `registered_at`
|
|
- `enable`
|
|
|
|
特点:
|
|
|
|
- 能表达“我邀请了谁”
|
|
- 不能表达“是否购买 / 购买次数 / 给我带来多少收益”
|
|
|
|
对应代码:
|
|
|
|
- `apis/public/user.api`
|
|
- `internal/logic/public/user/queryUserAffiliateListLogic.go`
|
|
|
|
#### B. 邀请成交记录
|
|
|
|
接口:
|
|
|
|
- `GET /v1/public/user/invite_sales`
|
|
|
|
返回结构:
|
|
|
|
- `total`
|
|
- `list[]`
|
|
- `amount`
|
|
- `updated_at`
|
|
- `user_hash`
|
|
- `product_name`
|
|
|
|
特点:
|
|
|
|
- 更像“邀请带来的订单流水”
|
|
- 不是邀请用户列表
|
|
|
|
对应代码:
|
|
|
|
- `internal/logic/public/user/getInviteSalesLogic.go`
|
|
|
|
#### C. 邀请统计
|
|
|
|
接口:
|
|
|
|
- `GET /v1/public/user/invite_stats`
|
|
|
|
返回结构:
|
|
|
|
- `friendly_count`
|
|
- `history_count`
|
|
|
|
特点:
|
|
|
|
- 只适合头部统计卡片
|
|
- 不适合列表页
|
|
|
|
对应代码:
|
|
|
|
- `internal/logic/public/user/getUserInviteStatsLogic.go`
|
|
|
|
### 2.1.2 已有后台接口
|
|
|
|
后台已经有更完整的邀请记录能力,可以直接参考:
|
|
|
|
- `GetAdminUserInviteList`
|
|
- `GetInviteManageList`
|
|
|
|
这些接口已经能返回:
|
|
|
|
- 邀请时间
|
|
- 是否购买
|
|
- 购买次数
|
|
- 邀请人佣金
|
|
- 邀请人赠送天数
|
|
- 被邀请人赠送天数
|
|
|
|
对应代码:
|
|
|
|
- `internal/logic/admin/user/getAdminUserInviteListLogic.go`
|
|
- `internal/logic/admin/invite/getInviteManageListLogic.go`
|
|
|
|
结论:
|
|
|
|
- 邀请记录的统计逻辑后端已经有现成实现思路。
|
|
- 新增 App 公开接口时,建议复用这部分逻辑,不要从零再写一套。
|
|
|
|
---
|
|
|
|
## 2.2 套餐折扣相关
|
|
|
|
### 2.2.1 套餐列表接口已有折扣规则
|
|
|
|
接口:
|
|
|
|
- `GET /v1/public/subscribe/list`
|
|
|
|
当前返回的套餐结构 `Subscribe` 中已包含:
|
|
|
|
- `unit_price`
|
|
- `discount []SubscribeDiscount`
|
|
|
|
其中 `SubscribeDiscount` 当前字段为:
|
|
|
|
- `quantity`
|
|
- `discount`
|
|
- `new_user_only`
|
|
- `map_apple`
|
|
- `promo`
|
|
|
|
对应代码:
|
|
|
|
- `apis/public/subscribe.api`
|
|
- `internal/logic/public/subscribe/querySubscribeListLogic.go`
|
|
- `internal/types/types.go`
|
|
|
|
说明:
|
|
|
|
- `discount` 是按购买数量 `quantity` 生效的阶梯折扣
|
|
- 不是单个套餐固定只有一个折扣值
|
|
|
|
### 2.2.2 预下单接口已有价格计算结果
|
|
|
|
接口:
|
|
|
|
- `POST /v1/public/order/pre`
|
|
|
|
当前已返回:
|
|
|
|
- `price`:原价
|
|
- `amount`:最终应付
|
|
- `discount`:折扣减免金额
|
|
- `promo_discount`:活动优惠金额
|
|
- `gift_amount`:礼品余额抵扣
|
|
- `coupon_discount`:优惠券减免
|
|
- `fee_amount`:手续费
|
|
|
|
对应代码:
|
|
|
|
- `apis/public/order.api`
|
|
- `internal/logic/public/order/preCreateOrderLogic.go`
|
|
|
|
说明:
|
|
|
|
- 只要 App 知道 `subscribe_id + quantity [+ coupon] [+ payment]`,就已经能拿到准确的下单金额
|
|
- 所以“下单购买”这件事本身,后端主链路已经具备
|
|
|
|
---
|
|
|
|
## 3. 差距分析
|
|
|
|
## 3.1 邀请列表的真实缺口
|
|
|
|
如果产品要的是“邀请记录页”,通常至少会关心以下内容:
|
|
|
|
- 被邀请用户
|
|
- 邀请时间
|
|
- 是否已购买
|
|
- 购买次数
|
|
- 给邀请人带来的佣金
|
|
- 双方赠送天数
|
|
|
|
而当前:
|
|
|
|
- `/affiliate/list` 只有基础用户列表
|
|
- `/invite_sales` 是订单成交记录
|
|
- `/invite_stats` 是统计值
|
|
|
|
所以当前公开侧缺一个“**邀请关系维度的邀请记录列表**”。
|
|
|
|
## 3.2 套餐折扣的真实缺口
|
|
|
|
后端目前的主要问题不是“不会算折扣”,而是:
|
|
|
|
- `discount[]` 更偏规则定义
|
|
- App 如果只想直接展示“折后价 / 优惠金额 / 折扣标签”,还需要自己再算一层
|
|
- 这会增加前端理解成本,也容易和后端口径不一致
|
|
|
|
所以当前更合理的改法是:
|
|
|
|
- 保留现有折扣规则
|
|
- 再额外补充几个**面向展示的字段**
|
|
|
|
---
|
|
|
|
## 4. 推荐方案
|
|
|
|
## 4.1 邀请记录接口
|
|
|
|
### 方案建议
|
|
|
|
新增一个公开接口,例如:
|
|
|
|
- `GET /v1/public/user/invite_records`
|
|
|
|
说明:
|
|
|
|
- 从登录态中取当前用户 ID
|
|
- 不从前端传 `user_id`
|
|
- 只查“当前用户邀请的记录”
|
|
|
|
### 请求参数建议
|
|
|
|
```json
|
|
{
|
|
"page": 1,
|
|
"size": 10
|
|
}
|
|
```
|
|
|
|
### 返回字段建议
|
|
|
|
```json
|
|
{
|
|
"total": 2,
|
|
"list": [
|
|
{
|
|
"invitee_id": 1001,
|
|
"invitee_identifier": "138****8888",
|
|
"invitee_avatar": "https://...",
|
|
"invitee_enable": true,
|
|
"invited_at": 1716800000,
|
|
"order_count": 3,
|
|
"has_purchased": true,
|
|
"inviter_commission": 1200,
|
|
"inviter_gift_days": 30,
|
|
"invitee_gift_days": 7
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### 字段说明
|
|
|
|
- `invitee_id`:被邀请用户 ID
|
|
- `invitee_identifier`:被邀请用户展示账号
|
|
- `invitee_avatar`:头像
|
|
- `invitee_enable`:是否启用
|
|
- `invited_at`:邀请时间
|
|
- `order_count`:该被邀请用户产生的有效订单数
|
|
- `has_purchased`:是否已购买
|
|
- `inviter_commission`:给邀请人带来的佣金,单位建议继续沿用分
|
|
- `inviter_gift_days`:邀请人获赠天数
|
|
- `invitee_gift_days`:被邀请人获赠天数
|
|
|
|
### 实现建议
|
|
|
|
优先复用现有后台逻辑思路:
|
|
|
|
- 参考 `internal/logic/admin/user/getAdminUserInviteListLogic.go`
|
|
- 或参考 `internal/logic/admin/invite/getInviteManageListLogic.go`
|
|
|
|
公开接口与后台接口的主要差异只有两点:
|
|
|
|
- 公开接口不允许前端指定 `user_id`
|
|
- 公开接口按当前登录用户本人维度返回
|
|
|
|
### 是否可以不新增接口
|
|
|
|
可以,但前提是 App 接受以下拆分:
|
|
|
|
- 列表页用 `/affiliate/list`
|
|
- 顶部统计用 `/invite_stats`
|
|
- 订单流水页用 `/invite_sales`
|
|
|
|
如果产品要的是一个完整“邀请记录页”,不建议这样拆三次请求,前端维护成本偏高。
|
|
|
|
---
|
|
|
|
## 4.2 套餐折扣字段建议
|
|
|
|
### 核心建议
|
|
|
|
“接口增加三个字段”建议**加在 `SubscribeDiscount` 子项里**,不要直接加在 `Subscribe` 顶层。
|
|
|
|
原因:
|
|
|
|
- 折扣是按 `quantity` 生效的
|
|
- 一个套餐可能有多个折扣档位
|
|
- 如果加在套餐顶层,很难表达“买 1 个月”和“买 12 个月”对应不同折扣
|
|
|
|
### 推荐新增字段
|
|
|
|
建议在 `SubscribeDiscount` 中增加以下三个展示字段:
|
|
|
|
- `discount_price`
|
|
- `discount_amount`
|
|
- `discount_desc`
|
|
|
|
推荐结构如下:
|
|
|
|
```json
|
|
{
|
|
"quantity": 12,
|
|
"discount": 80,
|
|
"new_user_only": false,
|
|
"map_apple": "",
|
|
"promo": null,
|
|
"discount_price": 9600,
|
|
"discount_amount": 2400,
|
|
"discount_desc": "年付8折"
|
|
}
|
|
```
|
|
|
|
### 三个字段的含义
|
|
|
|
#### 1. `discount_price`
|
|
|
|
- 含义:该档位折后总价
|
|
- 计算建议:`unit_price * quantity * discount / 100`
|
|
- 单位:分
|
|
|
|
作用:
|
|
|
|
- App 可直接展示“折后价”
|
|
- 下单时直接把该项的 `quantity` 带入 `/order/pre` 或 `/order/purchase`
|
|
|
|
#### 2. `discount_amount`
|
|
|
|
- 含义:该档位比原价便宜多少钱
|
|
- 计算建议:`unit_price * quantity - discount_price`
|
|
- 单位:分
|
|
|
|
作用:
|
|
|
|
- App 可直接展示“立省 xx”
|
|
|
|
#### 3. `discount_desc`
|
|
|
|
- 含义:折扣展示文案
|
|
- 示例:
|
|
- `年付8折`
|
|
- `季付9折`
|
|
- `新用户首单8折`
|
|
|
|
作用:
|
|
|
|
- App 可直接做角标、标签、促销文案展示
|
|
|
|
### 为什么不推荐这三个字段加在下单接口
|
|
|
|
因为下单接口本来就是“结果型接口”,它已经能返回:
|
|
|
|
- 原价
|
|
- 折扣金额
|
|
- 实付金额
|
|
|
|
如果只是为了 App 卡片展示,再去每个套餐都调一次 `/order/pre`,成本会比较高:
|
|
|
|
- 请求次数多
|
|
- 页面首屏会更慢
|
|
- 前端链路更复杂
|
|
|
|
更合适的做法是:
|
|
|
|
- 套餐列表接口负责“展示友好”
|
|
- 预下单接口负责“结算准确”
|
|
|
|
---
|
|
|
|
## 5. 推荐改动清单
|
|
|
|
## 5.1 邀请列表
|
|
|
|
建议新增:
|
|
|
|
- 新接口:`GET /v1/public/user/invite_records`
|
|
|
|
建议新增类型:
|
|
|
|
- `GetUserInviteRecordsRequest`
|
|
- `UserInviteRecord`
|
|
- `GetUserInviteRecordsResponse`
|
|
|
|
建议实现位置:
|
|
|
|
- `apis/public/user.api`
|
|
- `internal/types/types.go`
|
|
- `internal/handler/public/user/`
|
|
- `internal/logic/public/user/`
|
|
|
|
## 5.2 套餐折扣
|
|
|
|
建议调整:
|
|
|
|
- `SubscribeDiscount` 增加 3 个字段:
|
|
- `discount_price`
|
|
- `discount_amount`
|
|
- `discount_desc`
|
|
|
|
建议实现位置:
|
|
|
|
- `apis/types.api`
|
|
- `internal/types/types.go`
|
|
- `internal/logic/public/subscribe/querySubscribeListLogic.go`
|
|
|
|
---
|
|
|
|
## 6. 前后端协作建议
|
|
|
|
## 6.1 App 侧调用建议
|
|
|
|
邀请页建议:
|
|
|
|
- 头部统计:`/v1/public/user/invite_stats`
|
|
- 邀请记录列表:`/v1/public/user/invite_records`
|
|
- 如果还要看成交流水:`/v1/public/user/invite_sales`
|
|
|
|
套餐页建议:
|
|
|
|
- 先调 `/v1/public/subscribe/list` 渲染套餐和折扣标签
|
|
- 用户点某个折扣档位时,带 `subscribe_id + quantity` 调 `/v1/public/order/pre`
|
|
- 用户确认后再调 `/v1/public/order/purchase`
|
|
|
|
## 6.2 单位口径建议
|
|
|
|
建议继续保持后端金额统一为“分”:
|
|
|
|
- `unit_price`
|
|
- `discount_price`
|
|
- `discount_amount`
|
|
- `amount`
|
|
- `coupon_discount`
|
|
|
|
这样可以避免前后端出现小数精度问题。
|
|
|
|
---
|
|
|
|
## 7. 最终建议
|
|
|
|
### 建议一
|
|
|
|
如果你们只是要“邀请用户名单”,可直接复用:
|
|
|
|
- `GET /v1/public/user/affiliate/list`
|
|
|
|
### 建议二
|
|
|
|
如果你们要的是完整“邀请记录”,建议新增:
|
|
|
|
- `GET /v1/public/user/invite_records`
|
|
|
|
这是本次需求里更合理的新增接口。
|
|
|
|
### 建议三
|
|
|
|
商品套餐“折扣信息”不建议重新设计一整套下单逻辑。
|
|
|
|
当前后端已经具备:
|
|
|
|
- 套餐折扣规则
|
|
- 预下单价格计算
|
|
- 正式下单购买
|
|
|
|
更推荐做法是:
|
|
|
|
- 在 `SubscribeDiscount` 里补 3 个展示字段:
|
|
- `discount_price`
|
|
- `discount_amount`
|
|
- `discount_desc`
|
|
|
|
这样改动最小,也最贴近 App 展示场景。
|
|
|
|
---
|
|
|
|
## 8. 相关代码位置
|
|
|
|
- `internal/logic/public/user/queryUserAffiliateListLogic.go`
|
|
- `internal/logic/public/user/getInviteSalesLogic.go`
|
|
- `internal/logic/public/user/getUserInviteStatsLogic.go`
|
|
- `internal/logic/admin/user/getAdminUserInviteListLogic.go`
|
|
- `internal/logic/admin/invite/getInviteManageListLogic.go`
|
|
- `internal/logic/public/subscribe/querySubscribeListLogic.go`
|
|
- `internal/logic/public/order/preCreateOrderLogic.go`
|
|
- `internal/logic/public/order/purchaseLogic.go`
|
|
- `internal/types/types.go`
|
|
- `apis/public/user.api`
|
|
- `apis/public/subscribe.api`
|
|
- `apis/public/order.api`
|
|
|