# 会员内容上新弹窗接口 ## 一、业务流程 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 条, 合法范围为 1~20。修改数量会改变 `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 内容下发逻辑。