# 草原指南字段级操作记录与分页接口

> 日期：2026-07-14
>
> 后端 Issue：[HL #4977](https://git.1814.love:8443/wx/HL/issues/4977)
>
> 发布范围：先合入 `dev`，再同步 `dev-v3` 并部署 TEST；当前不合入 `main`、不部署正式环境

## 1. 变更目的

草原指南编辑页原“操作记录”只有创建时间和最后编辑时间，无法说明谁修改了什么。本次新增独立分页接口，响应结构参考产品日志时间线，提供：

- 操作类型和中文摘要；
- 操作所属页面区域；
- 操作人 ID、名称快照和操作时间；
- 本次真实变化的字段；
- 字段中文名、旧值、新值和变更类型；
- 富文本、正文图片和生效封面等长值的摘要与哈希。

## 2. 接口

```http
GET /admin/grassland-guide/videos/{videoId}/operation-logs?page=1&pageSize=20
```

查询参数：

| 参数 | 必填 | 默认值 | 规则 |
|---|---:|---:|---|
| `videoId` | 是 | - | 草原指南视频 ID |
| `page` | 否 | `1` | 最小 `1` |
| `pageSize` | 否 | `20` | `1-100` |

分页顺序固定为 `createTime DESC, id DESC`，前端按 `records` 追加加载即可。只有 `SUPER_ADMIN`、`OPERATOR` 可以查询字段级历史值。

## 3. 响应示例

```json
{
  "code": 200,
  "message": "success",
  "data": {
    "records": [
      {
        "id": "2077195939797688322",
        "videoId": "2076195939797688322",
        "action": "UPDATE",
        "actionLabel": "编辑",
        "step": "BASIC",
        "stepLabel": "基础信息",
        "detail": "编辑基础信息",
        "changedFields": ["title", "summary"],
        "fromStatus": "PUBLISHED",
        "toStatus": "PUBLISHED",
        "operatorId": "10001",
        "operatorName": "yangchunsheng",
        "createTime": "2026-07-14 13:56:19",
        "changes": [
          {
            "field": "title",
            "fieldLabel": "视频标题",
            "oldValue": "草原指南验收",
            "newValue": "草原指南验收｜草原蜱虫怎么预防和处理",
            "changeType": "MODIFY",
            "oldHash": null,
            "newHash": null
          }
        ]
      }
    ],
    "total": 12,
    "page": 1,
    "pageSize": 20
  },
  "success": true
}
```

## 4. 字段枚举

`action`：

| 值 | `actionLabel` | 含义 |
|---|---|---|
| `CREATE` | 新建 | 创建草稿 |
| `UPDATE` | 编辑 | 更新内容或展示配置 |
| `PUBLISH` | 上线 | 首次发布或重新发布 |
| `OFFLINE` | 下线 | 已发布内容下线 |
| `DELETE` | 删除 | 删除草稿或已下架内容 |

`step`：

| 值 | 含义 |
|---|---|
| `BASIC` | 基础信息 |
| `CONTENT` | 图文正文 |
| `PUBLISH_SETTING` | 发布设置 |
| `DISPLAY_SETTING` | 展示设置 |
| `MULTIPLE` | 一次操作涉及多个区域，使用 `stepLabel` 展示具体区域 |

`changeType`：`ADD`、`MODIFY`、`DELETE`。

## 5. 前端接入规则

- 编辑页打开时请求第一页，滚动到底部后按 `page + 1` 加载；不要一次拉取全部日志。
- 时间线标题可使用 `actionLabel + stepLabel`，说明文本直接使用 `detail`。
- 字段差异直接渲染 `changes[].fieldLabel/oldValue/newValue`，不要自行把字段英文名转换为中文。
- 所有 `id`、`videoId`、`operatorId` 都按字符串处理。
- `fromStatus`、`toStatus` 可为空；状态没有变化的编辑操作也可能两者相同。
- 历史日志只有 `changedFields`，`changes` 会返回空数组；页面应展示动作、操作人和时间，不要报错。
- 富文本正文不返回整篇 HTML；`oldValue/newValue` 是去标签后的摘要，`oldHash/newHash` 用于判断完整内容是否不同。
- 正文图片返回“共 N 张”；生效封面返回脱敏摘要，例如 `封面#1a2b3c4d`，不会下发完整 OSS 地址。
- 后端只记录真实变化字段；无变化字段不会出现在 `changes` 中。

## 6. 与既有接口的关系

- 草原指南列表、详情、创建、编辑、发布、下架和删除接口路径均不变。
- 详情中的 `createdAt/updatedAt/createdBy/updatedBy` 保持兼容，但不再承担完整操作历史展示。
- 本接口不返回、也不接收 `version`；前端继续不维护版本号。
- 本文件只说明操作记录，不合并到素材上传、MP4 校验或删除功能的 changelog。

## 7. 联调清单

- [ ] 首次进入加载第一页，向下滚动可稳定分页且不重复。
- [ ] 编辑标题、简介、正文、展示设置后可显示对应旧值和新值。
- [ ] 发布、重新发布、下线和删除显示正确动作及状态变化。
- [ ] 历史日志 `changes=[]` 时页面正常降级。
- [ ] 非 `SUPER_ADMIN`、`OPERATOR` 角色不展示字段级操作历史入口。

## 8. 后端 TEST 验证（2026-07-14）

- 后端 PR：[HL #4980](https://git.1814.love:8443/wx/HL/pulls/4980) 已合入 `dev`；[HL #4981](https://git.1814.love:8443/wx/HL/pulls/4981) 已由 `dev` 同步至 `dev-v3`。
- TEST 部署任务 `5681477a` 成功，`hl-resource-service` 的 `8082/8182` 双实例均健康；部署内容与 `origin/dev-v3` 一致。
- Flyway `20260714.001` 执行成功，`changes JSON`、`operator_name VARCHAR(64)` 已落库。
- 真实 `EXPLAIN` 命中 `idx_ggol_video_time(video_id, operated_at, log_id)`，使用倒序索引扫描。
- 受控业务 API 验收已完成：临时草稿执行 `CREATE → UPDATE → DELETE`，操作日志总数和顺序正确；标题、简介、正文、精选、登录鉴权、排序权重均返回真实旧值和新值。
- `contentHtml` 只返回纯文本摘要和哈希，不返回原始 HTML；删除后详情返回 `371001`，该视频的三条历史日志仍可分页查询。
- 以 `pageSize=1/2` 跨页验证未出现重复 ID；`8082/8182` OpenAPI 均只包含 `videoId/page/pageSize`，没有 `version`。
- 以上是后端验收证据；第 7 节仍是前端接入自测清单，不以页面或按钮作为本后端工单关单条件。
