feat: 订单时间线 11 事件类型扩展 + 转单入参正式生效(管理后台 changelog)

覆盖 6 PR:#4422 #4426 #4434 #4449 #4454 #4464
关联 Issue:#4419 #4423 #4428 #4446 #4451 #4459
这个提交包含在:
yaosutu 2026-06-26 17:35:13 +08:00
父节点 98e35c6096
当前提交 c88cc66ffd

查看文件

@ -0,0 +1,405 @@
# 订单时间线 11 事件类型扩展 + 转单入参正式生效
- **变更类型**:修改接口
- **端类型**:管理后台
- **日期**2026-06-26
- **服务**hl-order-service-v3
- **关联 PR**#4422 #4426 #4434 #4449 #4454 #4464
- **关联 Issue**#4419 #4423 #4428 #4446 #4451 #4459
- **后端负责人**yst
---
## ① 接口背景
订单时间线 Epic6 PR 合并周期)带来两处接口变更:
1. **GET /v3/admin/order/{id}/status-log**:时间线出参 `eventType` 新增 11 个枚举值,覆盖增减项、合同、保险、退款、发票等业务动作,前端需按 eventType 渲染对应 label 与 content 文本。
2. **PUT /v3/admin/order/{id}**(修改订单字段):原先 `targetConsultantId` + `transferReason` 两个字段静默忽略(后端收到但不执行),现在**正式生效**——传这两个字段即触发真实转单逻辑。⚠️ 若前端已在传这两个字段,行为将从「无效」变为「真改归属」。
---
## ② 变更清单
| 接口 | 变更类型 | 变更描述 |
|---|---|---|
| GET /v3/admin/order/{id}/status-log | ✨ 出参枚举扩展 | eventType 新增 11 个取值(详见 §⑥) |
| GET /v3/admin/order/{id}/status-log | ✨ 出参新增触发场景 | INFO_ADJUST、REFUND_RECEIVED 新增触发场景(枚举值本身不变) |
| PUT /v3/admin/order/{id} | ⚠️ 入参行为变更 | targetConsultantId + transferReason 从「静默忽略」变为「真转单」 |
| PUT /v3/admin/order/{id} | ✨ 新增错误码 | 581042「目标定制师不存在或已停用」 |
---
## ③ 接口详情
### 接口 AGET /v3/admin/order/{id}/status-log
- **描述**:获取订单详情记录 Tab 的时间线列表
- **认证**:需要管理员 JWTBearer Token
- **幂等性**:只读,天然幂等
- **限流**:无特殊限流
### 接口 BPUT /v3/admin/order/{id}
- **描述**:修改订单字段(含转单字段)
- **认证**:需要管理员 JWTBearer Token
- **幂等性**:非幂等;同一 targetConsultantId 重复调用不报错但无实际变化(归属已是目标定制师则不重复写时间线)
- **限流**:无特殊限流
---
## ④ 接口入参
### 接口 AGET /v3/admin/order/{id}/status-log
#### 4.1 路径参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | Long | 是 | 订单 ID雪花 ID,字符串形式传入 |
无请求体。
### 接口 BPUT /v3/admin/order/{id}
#### 4.1 路径参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | Long | 是 | 订单 ID |
#### 4.2 请求体字段(仅列出本次变更相关字段,其余字段不变)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| targetConsultantId | Long | 否 | 转单目标定制师的 adminId。不传或与当前一致则不转单;传入且与当前不同则触发真实转单。 |
| transferReason | String | 否 | 转单原因备注,配合 targetConsultantId 使用;targetConsultantId 未传时忽略 |
---
## ⑤ 出参字段
### 接口 AGET /v3/admin/order/{id}/status-log
出参结构未变,records 数组每项字段如下:
| 字段 | 类型 | 说明 |
|---|---|---|
| records | Array | 时间线记录列表,按 changedAt 降序 |
| records[].id | String | 记录 ID |
| records[].eventType | String | 事件类型枚举(见 §⑥ 完整枚举表) |
| records[].content | String | 事件描述文本(见 §⑥ content 样例,后端生成,直接渲染) |
| records[].changedAt | String | 事件发生时间,ISO8601 格式 |
| records[].operatorName | String | 操作人名称(系统触发时为「系统」) |
| records[].fromStatus | String | 事件发生时订单粗状态快照 |
| records[].toStatus | String | 事件发生后订单粗状态快照 |
| records[].fromStatusName | String | fromStatus 中文名 |
| records[].toStatusName | String | toStatus 中文名 |
| records[].extra | Object | 附加结构化数据,按 eventType 不同而不同(可为 null |
### 接口 BPUT /v3/admin/order/{id}
出参结构不变,仍返回 `Result<Void>`(成功时 data 为 null,code=200
---
## ⑥ 枚举 / 数据字典
### eventType 完整枚举表(含本次新增)
| eventType 值 | label | content 文本样例 | 是否本次新增 |
|---|---|---|---|
| ORDER_CREATED | 创建订单 | 创建订单 | 否 |
| ORDER_CONFIRMED | 确认订单 | 确认订单 | 否 |
| ORDER_CANCELLED | 订单取消 | 订单取消 | 否 |
| ORDER_TRIP_STARTED | 出行开始 | 出行开始 | 否 |
| ORDER_TRIP_TERMINATED | 终止行程 | 终止行程 | 否 |
| ORDER_COMPLETED | 订单完成 | 订单完成 | 否 |
| PAYMENT_RECEIVED | 收款记录 | 收款 ¥6000微信支付 | 否 |
| PAYMENT_DEPOSIT | 定金收款 | 定金收款 ¥2000 | 否 |
| TRAVELER_CHANGED | 出行人变更 | 新增出行人:张三 / 移除出行人:李四 | 否 |
| INFO_ADJUST | 订单信息调整 | 修改客户信息 | 否(新增触发场景:改客户姓名/电话/紧急联系人/备注) |
| REFUND_RECEIVED | 退款到账 | ¥6000 已到账(手动完成) | 否(新增触发场景:退款手动完成) |
| ADJUSTMENT_ADD | 新增增减项 | 新增优惠 -¥500VIP优惠 / 新增附加费 +¥500船票升舱 | **是** |
| ADJUSTMENT_REVERSE | 撤销增减项 | 撤销优惠 ¥500录错 / 撤销附加费 ¥300录错 | **是** |
| CONSULTANT_TRANSFER | 转单 | 转单:张三→李四 | **是** |
| CONTRACT_CREATED | 创建合同 | 已创建合同HT202601001 / 已报备合同HT202601001 | **是** |
| CONTRACT_INVALIDATED | 作废合同 | 已作废合同HT202601001 | **是** |
| INSURANCE_PURCHASED | 投保 | 已投保 保游金标准方案3人 | **是** |
| INSURANCE_CANCELLED | 退保 | 已退保BY2026001234 | **是** |
| REFUND_REVIEWED | 退款审核 | 退款审核通过 ¥6000 / 退款审核驳回:金额超出实付 | **是** |
| REFUND_EXECUTING | 退款发起 | 退款发起 ¥6000 | **是** |
| INVOICE_APPLIED | 申请开票 | 申请开票:呼籁旅行科技有限公司 | **是** |
> **eventType 分类说明**
> - ADJUSTMENT_ADD / ADJUSTMENT_REVERSEDATA 类订单内数据变更,fromStatus/toStatus 为当时订单粗状态快照,不代表状态发生了迁移。
> - CONSULTANT_TRANSFERDATA 类,归属变更不触发订单状态迁移。
> - CONTRACT_CREATED / CONTRACT_INVALIDATED / INSURANCE_PURCHASED / INSURANCE_CANCELLED / REFUND_REVIEWED / REFUND_EXECUTING / INVOICE_APPLIEDDATA 类,均为业务动作记录。
---
## ⑦ 错误码
### 接口 BPUT /v3/admin/order/{id})新增错误码
| 错误码 | message | 触发场景 |
|---|---|---|
| 581042 | 目标定制师不存在或已停用 | targetConsultantId 对应的 admin 用户不存在,或该用户账号已被停用 |
### 已有错误码(保持不变,供参考)
| 错误码 | message | 说明 |
|---|---|---|
| 581001 | 订单不存在 | id 对应订单不存在 |
| 400 | 参数校验失败 | 请求体字段类型/格式错误 |
---
## ⑧ 示例
### 8.1 典型成功示例
#### 接口 A获取时间线含新枚举值
请求:
```
GET /v3/admin/order/1234567890123456789/status-log
Authorization: Bearer <admin-token>
```
响应:
```json
{
"code": 200,
"data": {
"records": [
{
"id": "9876543210",
"eventType": "ADJUSTMENT_ADD",
"content": "新增优惠 -¥500VIP优惠",
"changedAt": "2026-06-25T14:30:00+08:00",
"operatorName": "李定制",
"fromStatus": "CONFIRMED",
"toStatus": "CONFIRMED",
"fromStatusName": "已确认",
"toStatusName": "已确认",
"extra": null
},
{
"id": "9876543211",
"eventType": "CONSULTANT_TRANSFER",
"content": "转单:张三→李四",
"changedAt": "2026-06-25T10:00:00+08:00",
"operatorName": "系统",
"fromStatus": "CONFIRMED",
"toStatus": "CONFIRMED",
"fromStatusName": "已确认",
"toStatusName": "已确认",
"extra": null
},
{
"id": "9876543212",
"eventType": "INSURANCE_PURCHASED",
"content": "已投保 保游金标准方案3人",
"changedAt": "2026-06-24T16:20:00+08:00",
"operatorName": "系统",
"fromStatus": "CONFIRMED",
"toStatus": "CONFIRMED",
"fromStatusName": "已确认",
"toStatusName": "已确认",
"extra": null
}
]
}
}
```
#### 接口 B转单成功
请求:
```
PUT /v3/admin/order/1234567890123456789
Authorization: Bearer <admin-token>
Content-Type: application/json
{
"targetConsultantId": 987654321,
"transferReason": "原定制师休假,转交李四跟进"
}
```
响应:
```json
{
"code": 200,
"data": null
}
```
---
### 8.2 边界情况示例
#### 转单字段与当前归属相同(不触发转单,静默成功)
请求(当前归属已是 adminId=123456789
```json
{
"targetConsultantId": 123456789,
"transferReason": "测试"
}
```
响应:
```json
{
"code": 200,
"data": null
}
```
不会写入 CONSULTANT_TRANSFER 时间线记录。
#### 不传转单字段(其他字段正常修改,归属不变)
请求:
```json
{
"customerRemark": "客户备注更新"
}
```
响应:
```json
{
"code": 200,
"data": null
}
```
---
### 8.3 业务失败示例
#### targetConsultantId 目标定制师不存在或已停用
请求:
```json
{
"targetConsultantId": 999999999,
"transferReason": "转单测试"
}
```
响应:
```json
{
"code": 581042,
"msg": "目标定制师不存在或已停用",
"data": null
}
```
---
## ⑨ 业务边界
### 适用场景
- 接口 A任何状态的订单均可查询时间线只读
- 接口 B 转单:订单状态为非终态(未取消、未完成)时可转单;已取消或已完成订单会被业务守卫拦截。
### 不适用场景
- 不可通过时间线接口触发业务动作,时间线为只读查询。
- 转单不可将订单归属给已停用的管理员账号(报 581042
- transferReason 在 targetConsultantId 未传时无意义,后端忽略。
### 特殊边界
- ADJUSTMENT_ADD / ADJUSTMENT_REVERSE 的 fromStatus/toStatus 是当时订单粗状态的快照,这两个事件本身**不改变订单状态**,前端时间线渲染不需要显示状态迁移箭头。
- CONSULTANT_TRANSFER 同上,仅归属变更,不改变订单主状态。
- 时间线记录不可删除,历史订单在本次上线前发生的对应操作无时间线记录属正常现象(该类事件在此次上线前未记录)。
- targetConsultantId 传 null 或不传,后端视为「不转单」,与历史行为完全一致。
---
## ⑩ 修改前后对比
### 接口 AeventType 枚举值扩展
| 维度 | 修改前 | 修改后 |
|---|---|---|
| eventType 取值域 | 11 个基础值ORDER_CREATED 等) | 在原有基础上新增 11 个值ADJUSTMENT_ADD / ADJUSTMENT_REVERSE / CONSULTANT_TRANSFER / CONTRACT_CREATED / CONTRACT_INVALIDATED / INSURANCE_PURCHASED / INSURANCE_CANCELLED / REFUND_REVIEWED / REFUND_EXECUTING / INVOICE_APPLIED |
| INFO_ADJUST 触发场景 | 仅原有场景 | 新增:改客户姓名/电话/紧急联系人/备注时写入 |
| REFUND_RECEIVED 触发场景 | 仅原有场景 | 新增:退款手动标记完成时写入 |
| 出参字段结构 | 不变 | 不变 |
### 接口 B转单字段行为变更
| 维度 | 修改前 | 修改后 |
|---|---|---|
| targetConsultantId 传非空值行为 | **静默忽略**(后端接收但不执行任何操作) | **正式生效**:触发转单逻辑,改变订单归属定制师 |
| transferReason 传值行为 | **静默忽略** | 正式生效:记录转单备注,写入 CONSULTANT_TRANSFER 时间线 |
| 转单时间线记录 | 无 | 自动写入 CONSULTANT_TRANSFER 事件 |
| 错误码 581042 | 不存在 | **新增**,targetConsultantId 校验失败时返回 |
---
## ⑪ 影响评估 / 回滚
### ⚠️ 破坏兼容风险(高优先级确认)
**接口 B 转单字段行为变更是破坏性变更。**
请前端确认:
1. 现有「修改订单」表单是否已在传 `targetConsultantId` 字段?
- 若**已在传**:上线后该字段会真实改变订单归属,需评估是否符合预期,或在前端侧暂时移除该字段传入,等转单 UI 正式上线再接入。
- 若**未传**:无影响。
2. `transferReason` 同上评估逻辑。
### 前端同步上线要求
- **接口 A 时间线**:新枚举值前端若不处理,时间线条目的 label/icon 会命中 fallback。建议按 §⑥ 枚举表逐一补充渲染逻辑content 文本由后端返回,直接展示即可)。
- **接口 B 转单**:确认现有表单是否已传转单字段,按需调整后再上线。
### 回滚方案
- 后端可通过 Nacos 开关关闭时间线新事件写入(不影响已有记录)。
- 接口 B 转单生效逻辑如需紧急回滚,联系后端 yst 单独发布回滚版本。
---
## ⑫ 注意事项
1. **时间线 content 文本由后端生成**,前端直接渲染 records[].content 字符串,无需前端拼接或翻译枚举值。
2. **eventType 枚举将随业务持续扩展**,前端建议用 map/switch 处理已知值,对未知 eventType 做 fallback 渲染(展示 content 文本而不崩溃)。
3. **INFO_ADJUST 和 REFUND_RECEIVED 并非新枚举值**,只是新增了触发场景。历史订单在本次上线前对应操作无时间线记录,属预期行为。
4. **接口 B 转单字段传 null 或不传**等同于「不转单」,与历史行为一致。
5. **转单不改变订单主状态**,前端进度条/状态显示无需因转单刷新。
---
## ⑬ 关联 / 联系人
### Issue
- [#4419](https://git.1814.love:8443/wx/HL/issues/4419)
- [#4423](https://git.1814.love:8443/wx/HL/issues/4423)
- [#4428](https://git.1814.love:8443/wx/HL/issues/4428)
- [#4446](https://git.1814.love:8443/wx/HL/issues/4446)
- [#4451](https://git.1814.love:8443/wx/HL/issues/4451)
- [#4459](https://git.1814.love:8443/wx/HL/issues/4459)
### PR
- [#4422](https://git.1814.love:8443/wx/HL/pulls/4422)
- [#4426](https://git.1814.love:8443/wx/HL/pulls/4426)
- [#4434](https://git.1814.love:8443/wx/HL/pulls/4434)
- [#4449](https://git.1814.love:8443/wx/HL/pulls/4449)
- [#4454](https://git.1814.love:8443/wx/HL/pulls/4454)
- [#4464](https://git.1814.love:8443/wx/HL/pulls/4464)
### 后端负责人
yst腰苏图