doge 1 день назад
Родитель
Сommit
fc9e1b1950

+ 150 - 0
docs/前端接口/Banner/状态显示与编辑同步-前端接入说明.md

@@ -0,0 +1,150 @@
+# Banner 状态显示与编辑同步-前端接入说明
+
+本文专门处理列表状态文字、上下架按钮和编辑表单显示不一致的问题。三个位置统一使用列表接口返回的 `status`,不另建一套手动状态值。
+
+## 1. 接口与状态字段
+
+接口地址相对后台 API 域名,请求头沿用 `Authorization: Bearer <后台登录令牌>`。
+
+| 用途 | 接口 | 说明 |
+|---|---|---|
+| 列表与编辑回显数据 | `GET /admin/banner/index` | 记录位于 `data.data`,总数位于 `data.total` |
+| 列表按钮切换状态 | `POST /admin/banner/status` | 仅提交 `id` 和目标 `status` |
+| 编辑 Banner | `POST /admin/banner/update` | 提交完整基础表单及 `status` |
+
+| 列表字段 | 类型 | 前端用途 |
+|---|---|---|
+| `status` | integer,`0/1` | 唯一的当前状态值:`1` 上架、`0` 下架;列表文字、状态开关和编辑回显均读取它 |
+| `can_manual_toggle` | boolean | `true` 才允许手动切换;为 `false` 时隐藏或禁用列表操作及编辑状态控件 |
+| `offline_reason` | string 或 `null` | 下架原因,用于辅助说明,不作为状态控件的值 |
+| `manual_status` | integer 或 `null` | 兼容字段,新前端不需要读取或提交它 |
+| `effective_status` | integer,`0/1` | 兼容字段,与 `status` 相同,新前端统一读取 `status` |
+
+成功响应的业务码为 `code=0`,失败时展示实际 `msg`。不要仅根据 HTTP 状态判断保存成功。
+
+## 2. 三个位置的正确显示
+
+以下规则适用于允许手动操作的 Banner:
+
+| 接口返回的 `status` | 列表当前状态文字 | 操作按钮文字 | 点击按钮提交的目标值 | 编辑表单回显 |
+|---|---|---|---|---|
+| `1` | 上架 | 下架 | `status:0` | 上架,数字 `1` |
+| `0` | 下架 | 上架 | `status:1` | 下架,数字 `0` |
+
+按钮文字表示点击后将执行的操作。因此,“当前状态上架、按钮写下架”是正常的;同一条记录进入编辑却显示下架才是不一致。
+
+若列表使用状态开关而非动作按钮,开关当前值直接绑定 `status`,开启值为数字 `1`,关闭值为数字 `0`。编辑表单的开关或单选项同样使用数字 `1/0`,不混用字符串或布尔值。
+
+## 3. 打开编辑时的赋值
+
+每次打开编辑,都从本次选中行复制最新值,不能沿用默认的下架值或上一条记录的表单缓存。兼容旧响应字符串时,可统一转为数字:
+
+```javascript
+const status = Number(row.status);
+if (status !== 0 && status !== 1) {
+  throw new Error('Banner 状态格式错误,请重新获取列表');
+}
+editForm.status = status;
+```
+
+注意以下接法:
+
+- 列表文字根据 `Number(row.status) === 1` 显示“上架”,否则对合法的 `0` 显示“下架”。
+- 编辑表单初始化用 `row.status`,不用 `manual_status`、固定默认 `0` 或旧缓存。
+- 状态值不要用 `value || 默认值` 处理,`0` 是合法的下架值。
+- `can_manual_toggle=false` 时,编辑状态只能回显,不能修改。
+
+## 4. 列表按钮提交
+
+仅在 `can_manual_toggle=true` 时允许调用 `POST /admin/banner/status`。
+
+将当前上架的 Banner 下架:
+
+```json
+{
+  "id": 41,
+  "status": 0
+}
+```
+
+将当前下架的 Banner 上架:
+
+```json
+{
+  "id": 41,
+  "status": 1
+}
+```
+
+动作按钮提交的是目标状态,不是原状态。请求期间禁用该行操作,成功后重新请求列表;失败则恢复原显示并展示 `msg`。
+
+如果现有按钮沿用 `/admin/banner/update`,须带齐该接口的基础表单字段;不能只用 `{id,status}` 调用完整编辑接口。只切换状态时使用上面的 `/admin/banner/status`。
+
+## 5. 编辑保存
+
+`POST /admin/banner/update` 的基础必填字段为 `title`、`image`、`type`、`lang`;编辑还需提交 `id`。状态直接提交表单的 `status`:
+
+```json
+{
+  "id": 41,
+  "title": "首页推广图",
+  "image": "/uploads/banner-41.jpg",
+  "type": "pc",
+  "lang": "zh",
+  "link": null,
+  "sort": 10,
+  "status": 0
+}
+```
+
+其中 `link:null` 表示不绑定活动,编辑时省略 `link` 则保留原绑定。`type` 沿用存储值 `pc/app`,不要把列表筛选用的 `platform=h5` 写成 `type=h5`。
+
+两个保存接口均以 `status` 为优先输入。即使整行对象中残留旧 `manual_status=1`,本次提交的 `status=0` 也会生效;新前端直接不提交兼容字段即可。
+
+两个接口成功响应均如下,不直接返回保存后的 Banner:
+
+```json
+{
+  "code": 0,
+  "timestamp": 1792800000,
+  "msg": "OK",
+  "data": []
+}
+```
+
+保存成功后重新请求列表,并以新返回行替换本地旧数据;再次编辑时从刷新后的行回显。不要把旧列表对象或默认状态覆盖到新响应上。
+
+## 6. 关联活动的 Banner
+
+关联活动时 `can_manual_toggle=false`,不允许通过列表按钮或编辑表单手动上下架。当前状态自动跟随活动是否存在、是否上架、是否开始及是否结束。
+
+已结束活动对应的列表行示例:
+
+```json
+{
+  "id": 40,
+  "title": "秋季活动",
+  "image": "https://example.com/uploads/banner-40.jpg",
+  "type": "pc",
+  "lang": "zh",
+  "link": "123",
+  "status": 0,
+  "effective_status": 0,
+  "manual_status": null,
+  "can_manual_toggle": false,
+  "activity_id": "123",
+  "offline_reason": "activity_ended"
+}
+```
+
+这条记录的列表和编辑均显示“下架”,辅助原因显示“关联活动已结束”,上下架操作隐藏或禁用。不要用 `manual_status:null` 初始化一个可编辑的下架开关。
+
+活动尚未开始、下架或被删除时也不能手动覆盖;活动恢复有效后,重新获取列表会返回新的实际 `status`。关联活动记录调用状态切换接口会返回 `code=-3`。
+
+## 7. 联调验收
+
+1. 选一条 `can_manual_toggle=true`、`status=1` 的 Banner:列表显示上架,动作按钮显示下架,打开编辑回显上架。
+2. 在编辑中改为下架并保存:刷新列表后 `status=0`,状态文字为下架,动作按钮为上架,再次编辑仍回显下架。
+3. 从列表按钮上架:提交 `status=1`,刷新列表和重新打开编辑均显示上架。
+4. 换另一条 Banner 编辑,确认不会沿用上一条记录的状态。
+5. 检查关联活动的 Banner:三个位置都按返回的 `status` 显示,但不提供手动切换能力。