feat: 新增整屏推荐页配置功能
- 7 个固定槽位(1920×1080 两行网格),槽位定义/校验/橘视厅元数据同步 - 海报按槽位自动选:竖图槽取 posterimg、横图槽取 thumbimg,支持自定义覆盖 - 一键导出 zip 交付包:海报按槽位精确尺寸居中裁剪 + config.json + README(am start 拉起命令) - 管理后台接口 6 个(/manage/recommend-page/*),前端对接文档 FE-RECOMMEND-GUIDE.md
This commit is contained in:
248
FE-RECOMMEND-GUIDE.md
Normal file
248
FE-RECOMMEND-GUIDE.md
Normal file
@@ -0,0 +1,248 @@
|
||||
# 推荐页配置 · 前端对接文档
|
||||
|
||||
> 功能:设备厂商 1920×1080 整屏电影推荐页,运营在后台选片配置 7 个固定槽位,一键导出 zip 交付包发给厂商。
|
||||
> 后端已上线,本文档为前端实施所需全部信息。
|
||||
|
||||
---
|
||||
|
||||
## 1. 通用约定
|
||||
|
||||
- **鉴权**:所有接口走管理后台 JWT,请求头带 `token`(与现有 /manage 接口一致)
|
||||
- **返回格式**:`{ code: 0, msg: "", data: {...} }`,code=0 成功,非 0 失败(msg 为错误信息)
|
||||
- **新增菜单**:「媒资管理 → 推荐页配置」,路由 `manage/recommend-page`(后台 sys_menu 已配置 id=126,超管自动可见,其他角色需在角色管理勾选)
|
||||
|
||||
---
|
||||
|
||||
## 2. 槽位定义(固定 7 个,不可增减)
|
||||
|
||||
整屏排版(1920×1080 两行网格,槽位间距 20px,左右边距 70px):
|
||||
|
||||
```
|
||||
┌────────────────┐ ┌─────┐ ┌─────┐ ┌─────┐
|
||||
│ slot_01 │ │slot_02│ │slot_03│ │slot_04│ ← 上行
|
||||
│ 700×400 │ │340×440│ │340×440│ │340×440│
|
||||
└────────────────┘ └─────┘ └─────┘ └─────┘
|
||||
┌──────────────┐ ┌──────────────┐ ┌─────────┐
|
||||
│ slot_05 │ │ slot_06 │ │ slot_07 │ ← 下行
|
||||
│ 700×300 │ │ 700×300 │ │ 340×300 │
|
||||
└──────────────┘ └──────────────┘ └─────────┘
|
||||
```
|
||||
|
||||
| 槽位 | 类型 | 尺寸 | 说明 | 影片 |
|
||||
|---|---|---|---|---|
|
||||
| slot_01 | MAIN 主推 | 700×400 | 横图 | 必填 contentcode |
|
||||
| slot_02 | PORTRAIT 竖图 | 340×440 | 竖图 | 必填 |
|
||||
| slot_03 | PORTRAIT 竖图 | 340×440 | 竖图 | 必填 |
|
||||
| slot_04 | PORTRAIT 竖图 | 340×440 | 竖图 | 必填 |
|
||||
| slot_05 | LANDSCAPE 横图 | 700×300 | 横图 | 必填 |
|
||||
| slot_06 | LANDSCAPE 横图 | 700×300 | 横图 | 必填 |
|
||||
| slot_07 | MORE 更多入口 | 340×300 | 无影片,点击拉起橘视厅 | 不填,必填海报 URL |
|
||||
|
||||
**编辑页建议**:按 0.25 倍缩放渲染线框(175×100 / 85×110 / 175×75 / 85×75),每槽位显示海报缩略图 + 影片名 + 尺寸标注。
|
||||
|
||||
---
|
||||
|
||||
## 3. 接口清单
|
||||
|
||||
Base:`/manage/recommend-page`
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | `/list` | 分页列表,参数 `page`、`limit`、`name`(可选) |
|
||||
| GET | `/info/{id}` | 详情(slots 已解析为数组) |
|
||||
| GET | `/slot-definitions` | 槽位定义(渲染线框用,见 §3.1) |
|
||||
| POST | `/save` | 新建或更新(有 id 更新,无 id 新建) |
|
||||
| POST | `/delete` | 软删除,body: `[1, 2]`(id 数组) |
|
||||
| GET | `/export/{id}` | 导出 zip 交付包(**必须 blob 方式下载,见 §6**) |
|
||||
|
||||
### 3.1 槽位定义 GET `/slot-definitions`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"slots": {
|
||||
"slot_01": { "slotCode": "slot_01", "slotType": "MAIN", "width": 700, "height": 400,
|
||||
"defaultActionType": "DETAIL", "mediaRequired": true, "posterField": "thumbimg" },
|
||||
"slot_02": { "slotCode": "slot_02", "slotType": "PORTRAIT", "width": 340, "height": 440,
|
||||
"defaultActionType": "DETAIL", "mediaRequired": true, "posterField": "posterimg" }
|
||||
// ... slot_03~07
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 列表 GET `/list?page=1&limit=10`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"page": {
|
||||
"totalCount": 5, "pageSize": 10, "currPage": 1, "totalPage": 1,
|
||||
"list": [
|
||||
{ "id": 1, "name": "2026年10月推荐", "remark": "备注", "deleteFlag": "UNDEL",
|
||||
"createdAt": "2026-09-26 15:00:00", "updatedAt": "2026-09-26 15:00:00" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 详情 GET `/info/{id}`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"recommendPage": { "id": 1, "name": "2026年10月推荐", "remark": "", "slots": "[...原始JSON字符串...]", "createdAt": "..." },
|
||||
"slots": [
|
||||
{
|
||||
"slotCode": "slot_01",
|
||||
"slotType": "MAIN",
|
||||
"width": 700, "height": 400,
|
||||
"contentcode": "23010012026061709581101832",
|
||||
"mediaName": "影片名(后端从橘视厅同步)",
|
||||
"posterUrl": "https://imgcms.jetsenx.huashi.tv/.../448x252_xxx.png",
|
||||
"customPoster": false,
|
||||
"actionType": "DETAIL",
|
||||
"actionParam": "am start -n tv.huashi.jetsenx.jetsenfilx.jsttv.home/com.pukka.jiecheng.MainActivity --es media_id \"{contentcode}\"",
|
||||
"rawMedia": { "...橘视厅完整元数据(posterimg/thumbimg/description等)..." }
|
||||
},
|
||||
{
|
||||
"slotCode": "slot_07",
|
||||
"slotType": "MORE",
|
||||
"width": 340, "height": 300,
|
||||
"contentcode": null,
|
||||
"mediaName": "更多影片",
|
||||
"posterUrl": "https://.../more.jpg",
|
||||
"customPoster": true,
|
||||
"actionType": "LAUNCH",
|
||||
"actionParam": "am start -n tv.huashi.jetsenx.jetsenfilx.jsttv.home/com.pukka.jiecheng.MainActivity",
|
||||
"rawMedia": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 前端渲染用 `data.slots`(已解析),按 slotCode 匹配到线框位置。
|
||||
|
||||
### 3.4 保存 POST `/save`
|
||||
|
||||
**前端只需传必要字段,影片名/海报由后端从橘视厅自动同步:**
|
||||
|
||||
```json
|
||||
{
|
||||
"id": null,
|
||||
"name": "2026年10月推荐",
|
||||
"remark": "备注(可选)",
|
||||
"slots": [
|
||||
{ "slotCode": "slot_01", "contentcode": "23010012026061709581101832" },
|
||||
{ "slotCode": "slot_02", "contentcode": "..." },
|
||||
{ "slotCode": "slot_03", "contentcode": "..." },
|
||||
{ "slotCode": "slot_04", "contentcode": "..." },
|
||||
{ "slotCode": "slot_05", "contentcode": "..." },
|
||||
{ "slotCode": "slot_06", "contentcode": "..." },
|
||||
{ "slotCode": "slot_07", "posterUrl": "https://.../more.jpg" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**槽位可选字段:**
|
||||
|
||||
| 字段 | 说明 |
|
||||
|---|---|
|
||||
| `posterUrl` | 自定义海报 URL。横图槽位(slot_01/05/06/07)默认用橘视厅横版图,效果不佳时运营可手动填横图 URL 覆盖 |
|
||||
| `actionParam` | 自定义拉起命令(一般不填,用后端默认值) |
|
||||
|
||||
**后端校验规则(错误信息会原样返回 msg):**
|
||||
- 期名 name 必填
|
||||
- slots 必须 7 个、slotCode 齐全不重复
|
||||
- slot_01~06 contentcode 必填;无效 contentcode 报错 `contentcode 无效: xxx`(保存时后端实时调橘视厅校验)
|
||||
- slot_07 必填 posterUrl
|
||||
- 影片无海报时报错 `影片 xxx 无可用海报`
|
||||
|
||||
成功返回:`{ code: 0, data: { recommendPage: { id: 1, ... } } }`
|
||||
|
||||
---
|
||||
|
||||
## 4. 选片弹窗(复用已有媒资接口)
|
||||
|
||||
**搜索**:`GET /manage/jetsen-media/search?keyword=xxx&pageindex=1&pagesize=20`(已存在的接口)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"list": [
|
||||
{ "contentcode": "23010022026090109192132084", "name": "后悔没有好好爱过你",
|
||||
"posterimg": "https://...", "categoryname": "电影", "score": "8.0",
|
||||
"releaseyear": "2026", "originalcountry": "中国大陆" }
|
||||
],
|
||||
"totalCount": 100, "currPage": 1, "pageSize": 20, "totalPage": 5
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
弹窗交互:搜索框 → 结果列表(海报缩略图 + 片名 + contentcode)→ 选中回填槽位。
|
||||
槽位预览图可直接用选中结果的 `posterimg`(保存后以 info 接口返回的 posterUrl 为准)。
|
||||
|
||||
---
|
||||
|
||||
## 5. 页面结构
|
||||
|
||||
### 5.1 列表页 `/recommend`(路由建议)
|
||||
|
||||
| 列 | 说明 |
|
||||
|---|---|
|
||||
| 期名 | name |
|
||||
| 备注 | remark |
|
||||
| 创建时间 | createdAt |
|
||||
| 操作 | 编辑 / **复制新一期** / 导出zip / 删除 |
|
||||
|
||||
**复制新一期**:调 `info/{id}` 取 slots 预填新建表单(id 置 null),运营只改差异影片。
|
||||
|
||||
### 5.2 编辑页
|
||||
|
||||
- 顶部表单:期名(必填)、备注
|
||||
- 槽位线框区(§2 尺寸 × 0.25 缩放)
|
||||
- slot_01~06:点槽位 → 打开选片弹窗 → 回填 contentcode + 预览图
|
||||
- 每个槽位可展开「自定义海报 URL」输入框(可选,横图槽位补横版图用)
|
||||
- slot_07:仅海报 URL 输入(必填)+ 可选拉起参数
|
||||
- 工具栏:保存、导出 zip(保存后才可导出,需有 id)
|
||||
|
||||
**前端预校验**(7 槽位齐、slot_01~06 contentcode 齐、slot_07 海报齐),后端保存时再校验一遍。
|
||||
|
||||
---
|
||||
|
||||
## 6. 导出下载(重要:不能用 window.open)
|
||||
|
||||
导出接口走 JWT 请求头,`window.open` / `<a href>` 无法带 token,**必须用 axios blob 方式**:
|
||||
|
||||
```javascript
|
||||
axios.get(`/manage/recommend-page/export/${id}`, {
|
||||
responseType: 'blob',
|
||||
headers: { token: getToken() }
|
||||
}).then(res => {
|
||||
const url = window.URL.createObjectURL(new Blob([res.data]))
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.download = `推荐页_${name}.zip`
|
||||
link.click()
|
||||
window.URL.revokeObjectURL(url)
|
||||
})
|
||||
```
|
||||
|
||||
注意:导出需实时下载 7 张海报并裁剪,耗时约 5~15 秒,建议按钮加 loading 态。失败时(如某海报下载失败)返回 JSON 错误而非 zip,前端可判断 `res.data.type === 'application/json'` 提示错误。
|
||||
|
||||
---
|
||||
|
||||
## 7. zip 交付包结构(导出结果,无需前端处理,仅供了解)
|
||||
|
||||
```
|
||||
推荐页_2026年10月推荐.zip
|
||||
├── images/slot_01.png ~ slot_07.png # 已按槽位精确尺寸居中裁剪
|
||||
├── recommend_config.json # contentcode + actionType + actionParam(占位符已替换真实值)
|
||||
└── README.txt # 排版与拉起规则说明
|
||||
```
|
||||
Reference in New Issue
Block a user