docs(product-v2): 操作日志 P1 逐日聚合 diff + 跨产品检索 (PR #2423)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
这个提交包含在:
API Changelog Bot 2026-05-16 14:16:12 +08:00
父节点 d827a14dbe
当前提交 cf06dc6afc

查看文件

@ -0,0 +1,172 @@
# product-v2: 操作日志 P1 — 价格日历逐日聚合 diff + STEP2-5 全字段 + 跨产品检索
> **服务**: hl-product-service-v2 (端口 8083)
> **PR**: #2423(承接 P0 #2355
> **Issue**: #2409
> **日期**: 2026-05-16
> **影响范围**: 管理端「产品 → 操作日志」侧边栏 + 新增「跨产品操作日志检索」入口
---
## ⚠️ 关键变化
**P0 已让 `changes` 字段可用,P1 让 `changes` 真正"细到每天每档"+ 全字段覆盖**
- 旧逻辑P0 上线后PRICE_SET 只看到 1 行「成人售价 5800→9400」,不知道改了哪几天
- 新逻辑P1**按 (字段, 档位, 旧值, 新值) 智能聚合日期** → 8 天改同价 = **1 行带日期范围**「成人售价 2026-07-12~07-19 (8 天) 经典档: 5800→9400」
- **前端 0 改动**:复用 P0 的 `changes` 数组渲染表格,新 `fieldLabel` 自带聚合描述
**新接口**`GET /admin/product/item/operation-logs/search` 跨产品按字段名检索(运营查"今天谁改过价")。
---
## 一、背景
承接 P0 [#2355](https://git.1814.love:8443/wx/HL/pulls/2355) — 张老板查产品改价时,P0 只能看到「成人售价 5800→9400」一行取第一天作代表,看不出来"是哪几天改了"。如果运营改 8 天里 3 天,剩 5 天没改,P0 完全无法区分。
P1 解决:逐日 diff + 智能聚合 + STEP2-5 全字段全覆盖。
---
## 二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 查产品操作日志 | GET | `/admin/product/item/{id}/operation-logs` | **出参增强** | `changes` 数组含聚合 fieldLabel + STEP2-5 全字段 |
| 2 | 跨产品检索操作日志 | GET | `/admin/product/item/operation-logs/search` | **新接口** | 按字段名(如 adultSellPrice查谁改过价 |
---
## 三、接口详情
### 1. 查产品操作日志(出参增强)
`changes[].fieldLabel` 现在自带日期范围描述:
```json
{
"action": "PRICE_SET",
"actionLabel": "设置价格",
"step": "STEP4",
"stepLabel": "价格与班期",
"changes": [
{
"field": "adultSellPrice",
"fieldLabel": "成人售价 2026-07-12~07-19 (8 天) 经典档",
"oldValue": "5800",
"newValue": "9400",
"changeType": "MODIFY"
},
{
"field": "childSellPrice",
"fieldLabel": "儿童售价 2026-07-12~07-19 (8 天) 经典档",
"oldValue": "3000",
"newValue": "3980",
"changeType": "MODIFY"
}
]
}
```
#### 聚合描述格式
| 场景 | fieldLabel 示例 |
|------|----------------|
| 连续日期 | `成人售价 2026-07-12~07-19 (8 天) 经典档` |
| 离散日期 | `成人售价 2026-07-12, 07-15, 07-18 (3 天) 经典档` |
| 单天 | `成人售价 2026-07-12 经典档` |
| 跨月连续 | `成人售价 2026-07-30~08-01 (3 天) 经典档` |
| 不同新值(如周末加价) | 自动按 oldValue→newValue 分多组,多行 |
#### 长文本字段(>200 字)摘要
```json
{
"field": "introduction",
"fieldLabel": "产品介绍",
"oldValue": "已修改 (前80字…后80字)",
"newValue": "已修改 (前80字…后80字)",
"oldHash": "a3f4...",
"newHash": "b8e2...",
"changeType": "MODIFY"
}
```
- 字段白名单:`description / introduction / highlights / quickUnderstand / childExperience / growthGains / equipmentList / routeMapUrl / detailContent / coverContent`
- `oldHash/newHash`SHA-256 前 16 字节,**前端可选展示**(用于跨日志判断"内容是否真变了"
#### 集合字段聚合
```json
{
"field": "itineraryDays",
"fieldLabel": "行程列表",
"oldValue": "共 7 天",
"newValue": "共 8 天 (新增 1 / 删除 0)",
"changeType": "MODIFY"
}
```
- 集合白名单:`seasons / tags / tiers / itineraryDays / dayNodes / dayHotels / feeItems / carouselImages / excludedFees / includedFees / customFees`
- ⚠️ **注意**:集合字段不做深 diff避免日志 JSON 爆 50KB+),只聚合「新增 N / 删除 M」。具体哪一项的字段变了,目前需要查日志详情P2 后续可优化)
---
### 2. 跨产品检索操作日志(新接口)
`GET /admin/product/item/operation-logs/search`
#### 入参VO
| 字段 | 位置 | 类型 | 必填 | 默认 | 说明 |
|------|------|------|------|------|------|
| `field` | Query | String | ✅ | — | 字段英文名,如 `adultSellPrice` |
| `fromDate` | Query | LocalDate | ❌ | today-30d | 开始日期(双侧空时套 30 天兜底) |
| `toDate` | Query | LocalDate | ❌ | today | 结束日期 |
| `page` | Query | Integer | ❌ | 1 | 页码 |
| `size` | Query | Integer | ❌ | 20 (max 100) | 页大小 |
#### 权限
Service 入口校验 role ∈ {`SUPER_ADMIN`, `ADMIN`},普通销售员调用返 `PERMISSION_DENIED`403 业务码)。
#### 全词匹配
避免 `field=price` 误命中 `adultSellPrice` / `childSellPrice` / `infantPrice`
- 写入端:`changed_fields``,adultSellPrice,childSellPrice,`(两端逗号包裹)
- 查询端:`LIKE '%,adultSellPrice,%'` 全词匹配
- 兼容老日志P0 写入的没逗号包裹,OR 兜底 3 种边界exact / 头部 / 尾部)
#### 出参
复用 `ProductOperationLogRespVO`(带分页)。
---
## 四、前端改动建议mmg
**方案 A+ 聚合版****前端 0 改动**。
- P0 已实现的 `changes` 表格渲染逻辑自动适配(新 fieldLabel 自带"日期范围 (N 天) 档位名"
- 长文本字段oldValue/newValue 已是「已修改 (前80字…后80字)」文本,直接渲染
- 集合字段oldValue/newValue 已是「共 N 条 (新增 A / 删除 C)」文本,直接渲染
**新接口入口建议**(可选):管理端加个「操作日志检索」菜单,调 `/operation-logs/search?field=&fromDate=&toDate=`,用于审计场景。
---
## 五、向后兼容
- ✅ 老日志changes=null继续不渲染 diff 区块
- ✅ P0 写入的日志changed_fields 没两端逗号)依然能被新检索接口匹配
- ✅ 新接口 `/operation-logs/search` 不影响现有 `/operation-logs`
- ✅ Flyway V20260516_003 只加索引,无 DDL 风险
**部署顺序**Flyway 先行 → 后端发布。前端 0 改动可选发。
---
## 六、不在本期范围P2 后续)
- **集合字段深 diff**:当前只聚合「新增/删除数」,不展示哪一项的哪个字段变了
- 「还原到此版本」按钮
- 调价超阈值(>20%)钉钉/企微告警
- 跨产品聚合可视化页(直接读 `/operation-logs/search` 即可)