Initial commit

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 13:57:10 +08:00
co-authored by Claude Opus 5
commit 8679200f41
1897 changed files with 257900 additions and 0 deletions
+258
View File
@@ -0,0 +1,258 @@
# 会员内容上新弹窗接口
## 一、业务流程
1. App 使用达到产品规定时长后,回到首页时请求“获取会员内容上新弹窗”接口。
2. 后端判断当前用户是否需要展示弹窗:
- 存在尚未展示过的最新 VIP 内容版本时,返回 `show=true`
- 当前内容版本已经展示过,或没有可用配置时,返回 `show=false`
3. `show=true` 时,前端直接使用响应中的 `videos` 渲染最新内容,数量由后台配置。
4. 弹窗实际展示成功后,前端调用“上报弹窗已展示”接口。
5. 上报成功后,同一用户再次请求相同内容版本时返回 `show=false`
6. 后续有新的 VIP 内容上架、内容版本变化后,该用户可以再次收到弹窗。
## 二、获取会员内容上新弹窗
### 请求
```http
GET /api/app/payment/guide?scene=VIP_CONTENT_UPDATE
Authorization: <Token>
```
### Query 参数
| 参数 | 类型 | 是否必传 | 说明 |
| --- | --- | --- | --- |
| `scene` | String | 是 | 固定传 `VIP_CONTENT_UPDATE` |
### `show=true` 返回示例
```json
{
"code": 200,
"msg": "success",
"data": {
"show": true,
"configId": "6889f6d34a4fcb5012345678",
"contentVersion": "4a7cbdb742c44a47",
"segment": "OLD_NEVER_PAID",
"style": "BOTTOM_SHEET",
"title": "VIP会员特享内容更新上架啦",
"description": "精彩内容抢先看",
"cover": "",
"videos": [
{
"id": "6889f1014a4fcb5012340001",
"title": "视频标题1",
"cover": "https://example.com/video-1.jpg",
"coverThumb": "https://example.com/video-1-thumb.jpg",
"playTime": 1384,
"playCount": 12000
},
{
"id": "6889f1024a4fcb5012340002",
"title": "视频标题2",
"cover": "https://example.com/video-2.jpg",
"coverThumb": "https://example.com/video-2-thumb.jpg",
"playTime": 1062,
"playCount": 9850
},
{
"id": "6889f1034a4fcb5012340003",
"title": "视频标题3",
"cover": "https://example.com/video-3.jpg",
"coverThumb": "https://example.com/video-3-thumb.jpg",
"playTime": 926,
"playCount": 8160
},
{
"id": "6889f1044a4fcb5012340004",
"title": "视频标题4",
"cover": "https://example.com/video-4.jpg",
"coverThumb": "https://example.com/video-4-thumb.jpg",
"playTime": 745,
"playCount": 6300
}
],
"productId": "6889f2014a4fcb5012349999",
"durationSeconds": 0,
"action": {
"type": "VIP_PRODUCT",
"value": "6889f2014a4fcb5012349999"
}
}
}
```
### `show=false` 返回示例
```json
{
"code": 200,
"msg": "success",
"data": {
"show": false,
"segment": "OLD_NEVER_PAID"
}
}
```
### 响应字段
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `show` | Boolean | 是否展示弹窗;为 `false` 时前端不展示 |
| `configId` | String | 当前弹窗配置 ID`show=true` 时返回 |
| `contentVersion` | String | 当前最新内容版本;展示回执时原样传回 |
| `segment` | String | 当前用户所属分层 |
| `style` | String | 弹窗样式 |
| `title` | String | 弹窗标题 |
| `description` | String | 弹窗描述 |
| `cover` | String | 弹窗整体封面,没有配置时为空字符串 |
| `videos` | Object[] | 前端渲染使用的最新 VIP 内容列表,数量由后台配置 |
| `productId` | String | 会员商品 ID |
| `durationSeconds` | Integer | 配置的持续时间,单位为秒 |
| `action` | Object | 弹窗按钮操作配置 |
### `videos` 字段
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `id` | String | 视频 ID |
| `title` | String | 视频标题 |
| `cover` | String | 视频封面 |
| `coverThumb` | String | 视频缩略图;优先用于列表展示,为空时使用 `cover` |
| `playTime` | Integer | 视频时长,单位为秒 |
| `playCount` | Integer | 视频展示播放量 |
### 内容筛选和排序
- 仅返回审核通过的 VIP 视频内容。
- 排除免费专区内容。
- 排除金币付费内容。
- 排除不可推荐内容。
- 排除业务配置中不参与该弹窗的模块。
- 按审核通过时间倒序排列。
- 返回数量由付费引导配置的 `videoLimit` 控制;未配置或传 `0` 时默认 4 条,最大 20 条。
- 前端不需要再次排序;如果可用内容不足配置数量,按实际数量返回。
## 三、上报弹窗已展示
### 请求
```http
POST /api/app/payment/guide/impression
Authorization: <Token>
Content-Type: application/json
```
### 请求体
```json
{
"configId": "6889f6d34a4fcb5012345678",
"scene": "VIP_CONTENT_UPDATE",
"contentVersion": "4a7cbdb742c44a47",
"requestId": "550e8400-e29b-41d4-a716-446655440000"
}
```
### 请求参数
| 参数 | 类型 | 是否必传 | 说明 |
| --- | --- | --- | --- |
| `configId` | String | 是 | 获取接口返回的 `configId` |
| `scene` | String | 是 | 固定传 `VIP_CONTENT_UPDATE` |
| `contentVersion` | String | 是 | 获取接口返回的 `contentVersion`,原样传回 |
| `requestId` | String | 是 | 客户端每次展示生成的 UUID,用于请求幂等 |
| `videoId` | String | 否 | 用户点击或当前展示的视频 ID |
### 成功返回
```json
{
"code": 200,
"msg": "success",
"data": ""
}
```
### 调用时机
- 只有弹窗已经实际展示成功时才调用。
- 仅获取数据但未展示弹窗时,不调用展示回执。
- 回执请求失败时可以使用相同的 `requestId` 重试。
## 四、前端处理规则
- `show=false`:不展示弹窗,不调用展示回执。
- `show=true`:使用 `videos` 渲染内容卡片。
- 视频封面优先使用 `coverThumb`,为空时回退到 `cover`
- `playTime` 单位为秒,由前端格式化为 `mm:ss``hh:mm:ss`
- `playCount` 由前端按现有规则格式化,例如 `12000` 显示为 `1.2W`
- 用户点击视频时,使用对应的 `id` 跳转视频详情。
- 用户点击开通会员时,按 `action.type``action.value` 执行跳转。
- 弹窗展示成功后,将 `configId``scene``contentVersion` 和新生成的 `requestId` 上报。
## 五、重复请求行为
| 场景 | 返回结果 |
| --- | --- |
| 同一内容版本尚未上报展示 | 重复请求仍返回 `show=true` 和相同内容 |
| 同一内容版本已经上报展示 | 返回 `show=false` |
| 后续上架新 VIP 内容,内容版本发生变化 | 返回 `show=true` 和新的 `contentVersion` |
| 没有有效弹窗配置 | 返回 `show=false` |
| 没有符合条件的 VIP 内容 | 返回 `show=false` |
## 六、后台返回数量和批量场景配置
付费引导新增、编辑接口的配置对象支持:
```json
{
"scene": "VIP_CONTENT_UPDATE",
"videoLimit": 20
}
```
`videoLimit` 仅用于 `VIP_CONTENT_UPDATE` 场景;不传或传 `0` 时默认 4 条,
合法范围为 120。修改数量会改变 `contentVersion`,已经看过旧内容版本的
用户会按新版本再次满足展示条件。
后台需要将同一份配置一次应用到多个场景时,调用:
```http
POST /api/web/admin/payment-guide/add
Content-Type: application/json
```
```json
{
"scenes": [
"HOME_NEW_USER",
"VIP_CONTENT_UPDATE"
],
"config": {
"segments": [],
"style": "BOTTOM_SHEET",
"title": "VIP会员内容更新上架啦",
"description": "精彩内容抢先看",
"cover": "",
"videoIds": [],
"videoLimit": 4,
"productId": "6889f2014a4fcb5012349999",
"durationSeconds": 0,
"action": {
"type": "VIP_PRODUCT",
"value": "6889f2014a4fcb5012349999"
},
"enable": true,
"sort": 100
}
}
```
`scenes` 支持当前全部合法场景,单次最多 6 个,不允许重复。后台会为每个场景
生成独立的配置 ID,整批成功或整批回滚。该接口只批量复制配置,不会改变
各场景原有的 App 内容下发逻辑。