docs(product-v2): 操作日志中文化 + 字段级 diff (PR #2355)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
这个提交包含在:
父节点
330fc6e1a2
当前提交
d7be5c267e
@ -0,0 +1,210 @@
|
||||
# product-v2: 产品操作日志全中文化 + 字段级 diff(旧值→新值)
|
||||
|
||||
> **服务**: hl-product-service-v2 (端口 8083)
|
||||
> **PR**: #2355
|
||||
> **Issue**: #2354
|
||||
> **日期**: 2026-05-15
|
||||
> **影响范围**: 管理端「产品 → 操作日志」侧边栏(admin.1814.love `/product/edit?id=X` 右侧抽屉)
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 关键变化
|
||||
|
||||
`GET /admin/product/item/{id}/operation-logs` **出参新增 3 字段**(`actionLabel` / `stepLabel` / `changes`),接口路径、入参、HTTP 方法**完全没变**。
|
||||
|
||||
- 旧逻辑(mmg 现在):把 `action="EDIT"` / `step="STEP1"` 当字符串裸渲染,用户看不懂
|
||||
- 新逻辑:直接读 `actionLabel="编辑"` / `stepLabel="基础信息"` 即可;新增 `changes` 数组渲染字段差异表格
|
||||
- **老日志兼容**:2026-05-15 之前的历史日志 `changes` 字段为 `null`,前端**不渲染 diff 区块**,只显示 `actionLabel + detail`(向后兼容)
|
||||
|
||||
---
|
||||
|
||||
## 一、背景
|
||||
|
||||
张老板 2026-05-15 反馈:产品 `2055138817265897473` 改价后无法追溯具体金额变化。
|
||||
- 旧版日志只记 `detail="价格区间设置 2026-07-12~2026-07-19"`,金额变化要靠 RDS binlog 还原(1 小时排查)
|
||||
- 20 种 action 落库为英文 `EDIT/PRICE_SET/COMPLETE`,前端裸出导致每次都要询问含义
|
||||
- `operatorName` 列存在但 Service 没赋值,所有日志显示 null
|
||||
|
||||
P0 解决:action 中文化 + 字段级 diff(前端表格可直接展示「成人售价 5800 → 9400」)。
|
||||
|
||||
---
|
||||
|
||||
## 二、变更接口清单
|
||||
|
||||
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||||
|---|------|------|------|----------|------|
|
||||
| 1 | 查产品操作日志 | GET | `/admin/product/item/{id}/operation-logs` | **出参 EXTEND** | 新增 actionLabel / stepLabel / changes 三字段 |
|
||||
|
||||
---
|
||||
|
||||
## 三、接口详情
|
||||
|
||||
### 1. 查产品操作日志 `GET /admin/product/item/{id}/operation-logs`
|
||||
|
||||
**VO**: `ProductOperationLogRespVO`
|
||||
|
||||
#### 入参(无变化)
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|------|
|
||||
| id | Path | Long | ✅ | productId |
|
||||
|
||||
#### 出参(新增 3 字段,加粗为新)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": [
|
||||
{
|
||||
"id": "2055231522046218242",
|
||||
"action": "EDIT",
|
||||
"actionLabel": "编辑",
|
||||
"step": "STEP1",
|
||||
"stepLabel": "基础信息",
|
||||
"detail": "基础信息",
|
||||
"operatorId": "2033350100000000006",
|
||||
"operatorName": "wangyu",
|
||||
"createTime": "2026-05-15 18:19:14",
|
||||
"changes": [
|
||||
{
|
||||
"field": "name",
|
||||
"fieldLabel": "产品名称",
|
||||
"oldValue": "Tina空想2大1小 私人定制线路",
|
||||
"newValue": "Tina空想2大1小 私人定制线路 8天7晚",
|
||||
"changeType": "MODIFY"
|
||||
},
|
||||
{
|
||||
"field": "depositAmount",
|
||||
"fieldLabel": "订金金额",
|
||||
"oldValue": "1000.00",
|
||||
"newValue": "1500.00",
|
||||
"changeType": "MODIFY"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2055222984284573697",
|
||||
"action": "PRICE_SET",
|
||||
"actionLabel": "设置价格",
|
||||
"step": "STEP4",
|
||||
"stepLabel": "价格与班期",
|
||||
"detail": "价格区间设置 2026-07-12~2026-07-19",
|
||||
"operatorId": "2033350100000000006",
|
||||
"operatorName": "wangyu",
|
||||
"createTime": "2026-05-15 12:01:59",
|
||||
"changes": [
|
||||
{
|
||||
"field": "adultSellPrice",
|
||||
"fieldLabel": "成人售价",
|
||||
"oldValue": "5800.00",
|
||||
"newValue": "9400.00",
|
||||
"changeType": "MODIFY"
|
||||
},
|
||||
{
|
||||
"field": "childSellPrice",
|
||||
"fieldLabel": "儿童售价",
|
||||
"oldValue": "3000.00",
|
||||
"newValue": "3980.00",
|
||||
"changeType": "MODIFY"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2055216483381071873",
|
||||
"action": "COMPLETE",
|
||||
"actionLabel": "完成设计",
|
||||
"step": null,
|
||||
"stepLabel": null,
|
||||
"detail": "",
|
||||
"operatorId": "2033350100000000006",
|
||||
"operatorName": "wangyu",
|
||||
"createTime": "2026-05-15 17:43:16",
|
||||
"changes": null
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### `changes` 字段定义
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `changes` | `Array<FieldChange> \| null` | 字段差异列表;老日志为 `null` 时不渲染 |
|
||||
| `changes[].field` | `string` | 字段英文名(用于排序/筛选/调试) |
|
||||
| `changes[].fieldLabel` | `string` | **字段中文名(前端直接展示这个)** |
|
||||
| `changes[].oldValue` | `string \| number \| null` | 旧值(已转中文:枚举值如 `FULL` 已翻译为 `"全款"`) |
|
||||
| `changes[].newValue` | `string \| number \| null` | 新值 |
|
||||
| `changes[].changeType` | `"ADD" \| "MODIFY" \| "DELETE"` | ADD=新增(oldValue=null)/MODIFY=修改/DELETE=删除(newValue=null) |
|
||||
|
||||
#### 本期接入字段级 diff 的 3 类操作
|
||||
|
||||
| action / step | 接入字段(5 个/类) |
|
||||
|--------------|------|
|
||||
| `PRICE_SET` / `BATCH_SAVE`(STEP4) | `adultSellPrice` / `childSellPrice` / `toddlerDiscount` / `dailyStock` / `priceType` |
|
||||
| `EDIT` STEP1 | `name` / `subtitle` / `paymentType` / `depositAmount` / `defaultDailyStock` |
|
||||
| 状态变更(`SUBMIT_PUBLISH`/`APPROVE`/`REJECT` 等) | `status`(旧→新状态值已翻译为中文) |
|
||||
|
||||
**未接入的 action(changes=null,按老日志渲染)**:CREATE / EDIT STEP2-5 / COPY / DELETE / EDIT_MAP_AUTO / EDIT_MAP_MODE / SAVE_DETAIL_BLOCKS / TEAM_SAVE 等。
|
||||
**P1 后续**会全字段 diff 覆盖 STEP2-5 + 长文本摘要 + 集合 diff,单独发 changelog 通知。
|
||||
|
||||
---
|
||||
|
||||
## 四、前端改动建议(mmg)
|
||||
|
||||
### 1. 日志侧边栏渲染逻辑(伪代码)
|
||||
|
||||
```jsx
|
||||
{logs.map(log => (
|
||||
<Timeline.Item>
|
||||
<div className="log-header">
|
||||
<span className="action-tag">{log.actionLabel}</span>
|
||||
{log.stepLabel && <span className="step-tag">{log.stepLabel}</span>}
|
||||
<span className="time">{log.createTime}</span>
|
||||
<span className="operator">{log.operatorName ?? '系统'}</span>
|
||||
</div>
|
||||
{log.detail && <div className="detail">{log.detail}</div>}
|
||||
{log.changes && log.changes.length > 0 && (
|
||||
<table className="diff-table">
|
||||
<thead><tr><th>字段</th><th>旧值</th><th>新值</th></tr></thead>
|
||||
<tbody>
|
||||
{log.changes.map(c => (
|
||||
<tr key={c.field}>
|
||||
<td>{c.fieldLabel}</td>
|
||||
<td className="old">{c.oldValue ?? '—'}</td>
|
||||
<td className="new">{c.newValue ?? '—'}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
)}
|
||||
</Timeline.Item>
|
||||
))}
|
||||
```
|
||||
|
||||
### 2. action 颜色建议(前端可自行决定)
|
||||
|
||||
| 类别 | 取值 | 建议色 |
|
||||
|------|------|--------|
|
||||
| 价格类 | PRICE_SET / PRICE_DELETE / BATCH_SAVE / ADJUST_PRICE | 橙 |
|
||||
| 状态类 | PUBLISH / SUBMIT_PUBLISH / APPROVE / DIRECT_PUBLISH | 绿 |
|
||||
| 状态类(负向) | REJECT / WITHDRAW / UNPUBLISH / FORCE_UNPUBLISH / DELETE | 红 |
|
||||
| 编辑类 | EDIT / EDIT_MAP_AUTO / EDIT_MAP_MODE | 蓝 |
|
||||
| 其它 | CREATE / COPY / COMPLETE / TRANSFER / TEAM_SAVE | 灰 |
|
||||
|
||||
---
|
||||
|
||||
## 五、向后兼容性
|
||||
|
||||
- ✅ 接口路径、入参、HTTP 方法、原有出参字段全部不变
|
||||
- ✅ 老日志 `changes=null`,前端 `if(changes)` 守卫即可
|
||||
- ✅ 后端可独立先行发布(前端不改也不会出错,只是不显示新功能)
|
||||
- ✅ 新日志的 actionLabel/stepLabel 即使前端不读也不影响
|
||||
|
||||
**部署顺序**:Flyway 先行 → 后端 → 前端(任意顺序都安全)。
|
||||
|
||||
---
|
||||
|
||||
## 六、不在本期范围(P1/P2 后续单独工单)
|
||||
|
||||
- **P1**:全字段 diff(>100 字段全覆盖)、长文本摘要策略、集合字段 diff(seasons/tags/tiers/days/feeItems)
|
||||
- **P2**:「还原到此版本」按钮、跨产品聚合查询页、调价超阈值钉钉/企微告警
|
||||
正在加载...
x
在新工单中引用
屏蔽一个用户