docs(product-v2): 产品全量快照按需保存+一键还原 (PR #2431)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
这个提交包含在:
父节点
d84973ed4a
当前提交
e0250564b1
@ -0,0 +1,194 @@
|
|||||||
|
# product-v2: 产品全量快照 — 按需保存 + 一键还原(新功能)
|
||||||
|
|
||||||
|
> **服务**: hl-product-service-v2 (端口 8083)
|
||||||
|
> **PR**: #2431
|
||||||
|
> **Issue**: #2425
|
||||||
|
> **日期**: 2026-05-16
|
||||||
|
> **影响范围**: 产品编辑页右侧新增「版本管理」入口(保存/列表/还原/删除/标记永久)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ 关键新功能(mmg 前端需新增 UI)
|
||||||
|
|
||||||
|
产品支持「按需手动保存版本」+「一键还原到任意历史版本」。**这是个全新模块,前端需要新增 3 个组件**:
|
||||||
|
|
||||||
|
1. **保存版本按钮**(产品编辑页右上角)
|
||||||
|
2. **版本列表页/抽屉**(点按钮看历史版本)
|
||||||
|
3. **还原对话框**(必填还原原因 ≥10 字符)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、设计要点
|
||||||
|
|
||||||
|
| 项 | 设计 |
|
||||||
|
|---|---|
|
||||||
|
| 触发方式 | **按需手动**(不是每次 EDIT 自动) |
|
||||||
|
| 存储位置 | 阿里云 OSS(`hlgl-test` bucket,prefix `hl-product-snapshots/`) |
|
||||||
|
| 压缩 | gzip(典型 40KB JSON 压到 8-10KB) |
|
||||||
|
| 版本上限 | 每产品最多 10 个;keep_forever 标记每产品最多 3 个 |
|
||||||
|
| 超阈值 | 自动删最老的非 keep_forever 快照 |
|
||||||
|
| 还原后 | 状态强制 DRAFT(避免与审批/上架冲突),保留 id/created_by/createdAt |
|
||||||
|
| 权限 | SUPER_ADMIN 或 CUSTOMIZER+owner(复用 P2 改价权限校验) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、5 个新接口
|
||||||
|
|
||||||
|
### 1. 保存快照
|
||||||
|
`POST /admin/product/item/{productId}/snapshots`
|
||||||
|
|
||||||
|
入参 VO `ProductSnapshotSaveReqVO`:
|
||||||
|
| 字段 | 类型 | 必填 | 校验 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| name | String | ✅ | ≤64 字符,同产品下唯一 |
|
||||||
|
| description | String | ❌ | ≤255 字符 |
|
||||||
|
| keepForever | Boolean | ❌ | 默认 false |
|
||||||
|
|
||||||
|
出参:`Result<Long>` (snapshotId)
|
||||||
|
|
||||||
|
**错误码**:
|
||||||
|
- `410120` SNAPSHOT_NOT_FOUND
|
||||||
|
- `410121` SNAPSHOT_INVALID_STATE(仅 DRAFT/COMPLETED 可保存)
|
||||||
|
- `410122` SNAPSHOT_NAME_DUPLICATE
|
||||||
|
- `410123` SNAPSHOT_SIZE_EXCEED(序列化 >1MB 拒绝)
|
||||||
|
- `410124` SNAPSHOT_KEEP_FOREVER_LIMIT(>3 个 keep_forever 拒绝)
|
||||||
|
- `410115` PRICE_EDIT_PERMISSION_DENIED(复用,非 SUPER_ADMIN/CUSTOMIZER+owner)
|
||||||
|
- `510100` SNAPSHOT_OSS_FAIL(OSS 服务端错误)
|
||||||
|
|
||||||
|
### 2. 列表
|
||||||
|
`GET /admin/product/item/{productId}/snapshots?page=1&size=20`
|
||||||
|
|
||||||
|
出参(分页):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"data": {
|
||||||
|
"list": [{
|
||||||
|
"id": "...",
|
||||||
|
"productId": "...",
|
||||||
|
"name": "上架前最终版",
|
||||||
|
"description": "改价前备份",
|
||||||
|
"fileSize": 9876,
|
||||||
|
"keepForever": true,
|
||||||
|
"createdBy": "...",
|
||||||
|
"createdByName": "wangyu",
|
||||||
|
"createdAt": "2026-05-16 17:23:11"
|
||||||
|
}],
|
||||||
|
"total": 5,
|
||||||
|
"pageNum": 1,
|
||||||
|
"pageSize": 20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 还原
|
||||||
|
`POST /admin/product/item/{productId}/snapshots/{snapshotId}/restore`
|
||||||
|
|
||||||
|
入参 VO `ProductSnapshotRestoreReqVO`:
|
||||||
|
| 字段 | 必填 | 校验 |
|
||||||
|
|---|---|---|
|
||||||
|
| reason | ✅ | ≥10 字符 |
|
||||||
|
|
||||||
|
**还原后效果**:
|
||||||
|
- 产品全字段 + 所有子表(priceCalendars/days/dayNodes/dayHotels/feeItems/supplies/tiers/...)恢复到快照时点
|
||||||
|
- 产品状态强制设回 `DRAFT`
|
||||||
|
- 产品 id / created_by / createdAt 保持不变
|
||||||
|
- 自动写一条 `RESTORE` 操作日志,detail = `"还原至 {name} ({createdAt}), 原因: {reason}"`
|
||||||
|
|
||||||
|
**错误码**:
|
||||||
|
- `410125` SNAPSHOT_RESTORE_PUBLISHED(已上架不能还原,必须先 UNPUBLISH)
|
||||||
|
- `410126` SNAPSHOT_RESTORE_HAS_ORDER(有报名班期不能还原)
|
||||||
|
|
||||||
|
### 4. 删除
|
||||||
|
`DELETE /admin/product/item/{productId}/snapshots/{snapshotId}`
|
||||||
|
|
||||||
|
软删 MySQL + 异步删 OSS 对象(OSS 删失败 log.warn 不阻塞)。
|
||||||
|
|
||||||
|
### 5. 标记/取消永久保留
|
||||||
|
`PUT /admin/product/item/{productId}/snapshots/{snapshotId}/keep-forever?keepForever=true`
|
||||||
|
|
||||||
|
切换 keep_forever 标记。设 true 时校验 keep_forever 总数 < 3。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、前端 UI 建议(mmg)
|
||||||
|
|
||||||
|
### 保存按钮(编辑页右上角)
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
icon={<SaveOutlined />}
|
||||||
|
disabled={!isDraft && !isCompleted} // PUBLISHED/审批中禁用
|
||||||
|
onClick={openSaveDialog}
|
||||||
|
>
|
||||||
|
保存版本
|
||||||
|
</Button>
|
||||||
|
```
|
||||||
|
|
||||||
|
保存对话框:
|
||||||
|
- 输入版本名(如"上架前最终版" / "调价前备份")
|
||||||
|
- 选填描述
|
||||||
|
- 复选框「永久保留(不被阈值清理)」
|
||||||
|
|
||||||
|
### 版本列表(侧边抽屉)
|
||||||
|
|
||||||
|
| 版本名 | 描述 | 大小 | 创建人 | 时间 | 操作 |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| 上架前最终版 📌 | 改价前备份 | 9.6 KB | 王宇 | 17:23 | 还原 / 删除 / 取消📌 |
|
||||||
|
| 改 6 月价之前 | — | 8.2 KB | 王宇 | 16:01 | 还原 / 删除 / 📌 |
|
||||||
|
|
||||||
|
📌 = keep_forever 标记,不会被阈值清理删除。
|
||||||
|
|
||||||
|
### 还原对话框
|
||||||
|
|
||||||
|
```
|
||||||
|
⚠️ 还原到「上架前最终版」(2026-05-16 17:23)
|
||||||
|
|
||||||
|
还原后:
|
||||||
|
- 产品所有字段会回到该版本(包括价格、行程、备品等)
|
||||||
|
- 产品状态会强制设回"草稿"
|
||||||
|
- 操作日志会记录一条 RESTORE
|
||||||
|
|
||||||
|
还原原因(必填,≥10 字):
|
||||||
|
[ ]
|
||||||
|
|
||||||
|
[ 确认还原 ] [ 取消 ]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、部署前置(运维必做)
|
||||||
|
|
||||||
|
合并部署前 **nacos 必须配 OSS 凭据**,否则保存/还原接口返 `SNAPSHOT_OSS_FAIL`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# hl-common-{dev,test,prod}.yml
|
||||||
|
product:
|
||||||
|
snapshot:
|
||||||
|
oss:
|
||||||
|
access-key-id: <AK>
|
||||||
|
access-key-secret: <SK>
|
||||||
|
bucket: hlgl-test # 或新建专用 bucket
|
||||||
|
endpoint: oss-cn-beijing.aliyuncs.com # 已有默认值
|
||||||
|
key-prefix: hl-product-snapshots # 已有默认值
|
||||||
|
max-per-product: 10 # 已有默认值
|
||||||
|
max-keep-forever-per-product: 3 # 已有默认值
|
||||||
|
max-size-bytes: 1048576 # 已有默认值
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、向后兼容
|
||||||
|
|
||||||
|
- ✅ 新增功能,不影响任何现有接口
|
||||||
|
- ✅ Flyway V20260516_004 只建新表 product_snapshot
|
||||||
|
- ✅ 老日志/老产品完全不受影响
|
||||||
|
- ✅ 前端不实施新 UI 也不会出错(只是不显示新功能)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、不在本期范围(P2.1 #2428 + P2-4 #2426)
|
||||||
|
|
||||||
|
- 集合深 diff(dayHotels 子项变化)— P2.1 #2428
|
||||||
|
- 跨产品聚合可视化页 — P2-4 #2426
|
||||||
正在加载...
x
在新工单中引用
屏蔽一个用户