docs(order-v3): 团期人员与报账人变更写进团期时间线交接件(#8482)
changelog-filename-gate / validate (push) Failing after 2s
changelog-filename-gate / validate (push) Failing after 2s
五条人员写路径补留痕(新增 5 个事件码)+ GB-ADM-096 同秒按 logId 排序; PR #8490(e24be7af8)、#8492(75e182710),TEST 网关验收通过,前端零改动。 Refs wx/HL#8482 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
这个提交包含在:
@@ -0,0 +1,916 @@
|
||||
---
|
||||
schema: "hl-changelog/v2"
|
||||
ticket: "8482"
|
||||
title: "团期人员与报账人变更写进团期时间线:配置保存、设报账人、单人删除、单人更换、取消成团回收五条写路径补留痕(新增五个事件码),时间线同一秒内按 logId 排序"
|
||||
consumer: "admin"
|
||||
author: "jw(GIT)"
|
||||
change_type: "修改接口"
|
||||
backend_status: "deployed"
|
||||
gateway_status: "verified"
|
||||
frontend_status: "not_required"
|
||||
frontend_owner: ""
|
||||
frontend_ref: ""
|
||||
target_release: ""
|
||||
verified_at: ""
|
||||
status_note: "PR #8490 已合入 dev-v3(e24be7af8,五条写路径补留痕),PR #8492 已合入 dev-v3(75e182710,GB-ADM-096 同秒按 logId 排序);TEST 的 hl-order-service-v3 运行 dev-v3 75e182710。经网关 api.test.1814.love 用 admin token 实测:连设主报账人 A→B→C 三行可按时间还原更替、原样保存 / 只改排序 / 只改备注 / 设成已有等级零新增、单人删除与更换主(次)报账人各一行、保存移出主报账人一行、取消成团回收单独一行且排在取消成团之后、589508 / 589598 被拒零新增、CHECK 约束注入使留痕写失败时业务一起回滚、新增行无手机号,全部通过;排序修复部署后同一团期连读 5 次,同秒行全部按 logId 升序。frontend_status=not_required 的依据:#7987 时 mmg 已实证团期时间线组件 StatusLogsPanel 渲染 eventTypeName || eventType,中文名由后端直供,前端没有自建事件码映射表;2026-09-28 复核 hl-ui origin/v2.1@ce469f78 仍是这一写法,content 直接渲染,列表按接口返回顺序展示、不在前端重排,五个新事件码零改动即可正常显示。这一结论的前提是后端继续直供 eventTypeName:若后端对这些事件码返回 eventTypeName=null,页面会退化成显示原始事件码,那时本条须改回 pending。"
|
||||
updated_at: "2026-09-28"
|
||||
base: "dev-v3"
|
||||
---
|
||||
|
||||
# 团期人员与报账人变更写进团期时间线(管理后台)
|
||||
|
||||
> **服务**: hl-order-service-v3(端口 8086)
|
||||
> **PR**: #8490(合入 dev-v3 为 `e24be7af8`)、#8492(合入 dev-v3 为 `75e182710`)
|
||||
> **Issue**: #8482
|
||||
> **日期**: 2026-09-28
|
||||
> **影响范围**: 团期人员四个写接口与取消成团的副作用、团期状态流水(时间线 GB-ADM-096)
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 关键变化
|
||||
|
||||
1. **五条人员写路径成功后各写一行时间线**:配置人员保存、设报账人、单人删除、单人更换、取消成团回收人员。新增 5 个 `eventType`:`BATCH_STAFF_CONFIG_SAVE`「调整团期人员」、`BATCH_REPORTER_CHANGE`「报账人变更」、`BATCH_STAFF_REMOVE`「移除团期人员」、`BATCH_STAFF_REPLACE`「更换团期人员」、`BATCH_STAFF_RECYCLED`「取消成团·回收人员」,`changeType` 都是 `DATA`。
|
||||
2. **一次操作只写一行**:设新主报账人时原主报账人自动降级、换人时报账人等级转给新人、被移出的人带走报账人身份,这些报账人变化都并进同一行的 `content` 和 `extra`,不另起一行。
|
||||
3. **没有实际变化不写**:原样保存、只改排序或备注、只改服务日期或日薪、把人设成他已有的报账人等级,时间线都不新增。
|
||||
4. **被拒的请求不写;留痕写失败时业务一起回滚**:接口返回 500,名册与子订单副本都不变。
|
||||
5. **extra 里的 ID 一律是字符串**;主 / 次报账人前后字段(`primaryReporterBefore` / `primaryReporterAfter` / `secondaryReporterBefore` / `secondaryReporterAfter`)只在对应归属真的变了时出现。
|
||||
6. **GB-ADM-096 同一秒内的多行按 `logId` 升序返回**。改前同秒行的先后由数据库决定,实测建团和成团会排反;改后「取消成团」与随后的回收行稳定是「取消成团」在前。
|
||||
7. **六个接口的请求、响应结构一字未改**。前端无需改动,理由见第四节「前端交接清单」。
|
||||
|
||||
---
|
||||
|
||||
## 一、背景
|
||||
|
||||
团期缺口台账 g-062(2026-09-26 四方对账,P2,后端缺口):配置、删除、更换导游和摄影,改主 / 次报账人,以及取消成团时回收人员,这五条写路径都不写团期操作记录,运营在时间线上看不到「谁在什么时候把谁换成了谁」。
|
||||
|
||||
主报账人不只是一个标签:代收、垫付、报账的归属实时按当前主报账人计算,不存历史快照;团期确认逐户校验主报账人(581062),预支的领款人也限定为主报账人(589557)。主报账人一变,这些都跟着变,但改前时间线上找不到原因。
|
||||
|
||||
jw 2026-09-28 裁决:内容没变的操作不写;一次操作只写一行,报账人变化并入这一行;取消成团回收单独写一行。
|
||||
|
||||
| 问题 | 改前 | 改后 |
|
||||
|---|---|---|
|
||||
| 人员 / 报账人变更无留痕 | 五条写路径都不写时间线 | 各写一行,带前后差异 |
|
||||
| 取消成团回收了谁 | 时间线只有「取消成团」,回收人数只在服务端日志 | 单独一行,列出回收的人和报账人身份 |
|
||||
| 同秒行顺序 | 只按 `changedAt`(精确到秒)排,同秒先后不稳定 | 同秒按 `logId` 升序 |
|
||||
|
||||
---
|
||||
|
||||
## 二、变更接口清单
|
||||
|
||||
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||||
|------|------|------|------|----------|------|
|
||||
| 1 | 保存团期人员配置 | PUT | `/v3/admin/group-batch/{productBatchId}/staff` | 修改行为 | 名单或报账人归属有变化时写 `BATCH_STAFF_CONFIG_SAVE` |
|
||||
| 2 | 设置报账人等级 | PUT | `/v3/admin/group-batch/{productBatchId}/staff/{staffId}/reporter-rank` | 修改行为 | 主 / 次报账人归属有变化时写 `BATCH_REPORTER_CHANGE` |
|
||||
| 3 | 团期单人删除 | DELETE | `/v3/admin/group-batch/{productBatchId}/staff/{staffId}` | 修改行为 | 删除成功写 `BATCH_STAFF_REMOVE` |
|
||||
| 4 | 团期单人更换 | PUT | `/v3/admin/group-batch/{productBatchId}/staff/{staffId}/replace` | 修改行为 | 更换成功写 `BATCH_STAFF_REPLACE` |
|
||||
| 5 | 取消成团 | POST | `/v3/admin/order/group-batch/{groupBatchId}/cancel-group` | 修改行为 | 回收到人时,在「取消成团」那行之后再写一行 `BATCH_STAFF_RECYCLED` |
|
||||
| 6 | 团期状态流水(GB-ADM-096) | GET | `/v3/admin/order/group-batch/{groupBatchId}/status-logs` | 取值域扩展 + 排序 | `eventType` 新增五个值;同秒按 `logId` 升序 |
|
||||
|
||||
---
|
||||
|
||||
## 三、接口详情
|
||||
|
||||
### 1. 保存团期人员配置 `PUT /v3/admin/group-batch/{productBatchId}/staff`
|
||||
|
||||
**VO**: `BatchStaffConfigReqVO` → `Result<BatchStaffConfigRespVO>`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
「配置人员」弹窗保存(导游位、摄影位各一个弹窗)。请求与响应不变;保存成功后,名单或报账人归属有变化时,团期时间线多一行「调整团期人员」。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|------|------|------|------|------|------|
|
||||
| productBatchId | Path | Long | ✅ | 雪花 ID | 产品侧排期 ID,不是 groupBatchId |
|
||||
| scopeRoles | Body | String[] | 否 | 传了不能是空数组;导游位须同时传 GUIDE 与 LEADER | 本次覆盖的角色范围,不传 = 整期全量覆盖;也决定时间线里的位名 |
|
||||
| staffList | Body | Array | ✅ | 可以是 `[]`(清空该范围) | 覆盖范围内的最终名单 |
|
||||
| staffList[].staffId | Body | Long | ✅ | - | 员工 ID |
|
||||
| staffList[].staffRole | Body | String | ✅ | LEADER / GUIDE / PHOTOGRAPHER 等 | 落库角色 |
|
||||
| 其余字段 | Body | - | - | - | sortOrder / remark / serviceStartDate / serviceEndDate,与现有契约一致,本次不变;这些字段的变化不写时间线 |
|
||||
|
||||
#### 出参 `Result<BatchStaffConfigRespVO>`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| productBatchId | String | 回显,不变 |
|
||||
| groupBatchId | String | 团期主键,不变 |
|
||||
| staffList | Array | 保存后的名册,不变 |
|
||||
| affectedOrderCount | Integer | 扇出影响的子订单数,不变 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
TEST 实测「加一人减一人」(导游位原有李雪梅、白云飞、刘大山,本次移出李雪梅、加入萨仁高娃):
|
||||
|
||||
```json
|
||||
{
|
||||
"staffList": [
|
||||
{ "staffId": 1007, "staffRole": "LEADER", "sortOrder": 1 },
|
||||
{ "staffId": 1005, "staffRole": "LEADER", "sortOrder": 2 },
|
||||
{ "staffId": 1008, "staffRole": "LEADER", "sortOrder": 3 }
|
||||
],
|
||||
"scopeRoles": ["GUIDE", "LEADER"]
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
响应结构不变(下为 TEST 原文节选,名册每人只列部分字段,略去手机号):
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": {
|
||||
"productBatchId": "2104527134162853890",
|
||||
"groupBatchId": "2104527135173685249",
|
||||
"staffList": [
|
||||
{ "id": "2104527304799711233", "staffId": 1003, "staffRole": "PHOTOGRAPHER", "staffName": "王强", "sortOrder": 1, "reporterRank": "NONE", "reporterRankName": "非报账人" },
|
||||
{ "id": "2104527526883930114", "staffId": 1007, "staffRole": "LEADER", "staffName": "白云飞", "sortOrder": 1, "reporterRank": "PRIMARY", "reporterRankName": "主报账人" },
|
||||
{ "id": "2104527526888124417", "staffId": 1005, "staffRole": "LEADER", "staffName": "刘大山", "sortOrder": 2, "reporterRank": "SECONDARY", "reporterRankName": "次报账人" },
|
||||
{ "id": "2104527526892318722", "staffId": 1008, "staffRole": "LEADER", "staffName": "萨仁高娃", "sortOrder": 3, "reporterRank": "NONE", "reporterRankName": "非报账人" }
|
||||
],
|
||||
"affectedOrderCount": 1
|
||||
},
|
||||
"traceId": null,
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
同时 GB-ADM-096 新增的一行(原文):
|
||||
|
||||
```json
|
||||
{
|
||||
"logId": "2104527526900707330",
|
||||
"groupBatchId": "2104527135173685249",
|
||||
"changeType": "DATA",
|
||||
"eventType": "BATCH_STAFF_CONFIG_SAVE",
|
||||
"eventTypeName": "调整团期人员",
|
||||
"fromStatus": "RESOURCE_PREPARING",
|
||||
"toStatus": "RESOURCE_PREPARING",
|
||||
"content": "导游位:+萨仁高娃;−李雪梅",
|
||||
"operatorType": "ADMIN",
|
||||
"operatorId": "1001",
|
||||
"operatorName": "admin",
|
||||
"extra": {
|
||||
"scopeRoles": ["GUIDE", "LEADER"],
|
||||
"added": [{ "staffId": "1008", "staffName": "萨仁高娃", "staffRole": "LEADER" }],
|
||||
"removed": [{ "staffId": "1002", "staffName": "李雪梅", "staffRole": "GUIDE", "reporterRank": "NONE" }],
|
||||
"roleChanged": []
|
||||
},
|
||||
"changedAt": "2026-09-28 19:03:57"
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
无空数据形态。`staffList=[]` 表示清空该范围:有人被移出时同样写一行,位名后只有「−」一段。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{ "code": 589598, "message": "团期已确认,配置不可修改", "data": null, "traceId": null, "success": false }
|
||||
```
|
||||
|
||||
582115 / 582116 / 582119 / 589553 等其余错误码与改前相同。所有被拒请求零写入,也不写时间线。
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 写的条件:名单(staffId + 落库角色)有新增、移除或角色变化,或者主 / 次报账人归属变了。排序、备注、服务日期、日薪不参与比较。
|
||||
- 原样保存(前端形态:保留行只带 staffId / staffRole / sortOrder)、只改排序、只改备注:返回 200,时间线不新增(TEST 实测三次都是 8→8)。
|
||||
- content 格式:`{位名}:+新增的人;−移出的人;角色调整:某人(导游→领队)`,各段有内容才出现。位名:不传 `scopeRoles` 为「团期人员」,其余为「导游位」「摄影位」或「导游位、摄影位」。
|
||||
- 被移出的人带走报账人身份时,名字后写明去向:团期因此没有主报账人写「(原主报账人,团期现无主报账人)」,团期仍有别的主报账人写「(原主报账人,团期现主报账人为某某)」;次报账人同理。extra 同时带上报账人前后字段。
|
||||
- 报账人归属变了、却不是被移出的人带走的(少见,例如历史上同一人有重复行),content 末尾单列一段「主报账人:X → Y」。
|
||||
- content 超过 512 个字符时截断,末尾加「…」;完整名单以 extra 为准。
|
||||
|
||||
### 2. 设置报账人等级 `PUT /v3/admin/group-batch/{productBatchId}/staff/{staffId}/reporter-rank`
|
||||
|
||||
**VO**: `SetReporterRankReqVO` → `Result<Void>`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
名册里给某人设主报账人、次报账人,或取消报账人。团期内主、次报账人各唯一:设新的主(次)报账人时,原来那位自动降为非报账人。一次操作改动两个人,时间线只写一行。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|------|------|------|------|------|------|
|
||||
| productBatchId | Path | Long | ✅ | 雪花 ID | 产品侧排期 ID |
|
||||
| staffId | Path | Long | ✅ | 须是本团已配人员 | 员工 ID |
|
||||
| reporterRank | Body | String | ✅ | PRIMARY / SECONDARY / NONE | 目标等级 |
|
||||
|
||||
#### 出参 `Result<Void>`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| data | null | 不变 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
`PUT /v3/admin/group-batch/2104527134162853890/staff/1005/reporter-rank`(此前主报账人是李雪梅):
|
||||
|
||||
```json
|
||||
{ "reporterRank": "PRIMARY" }
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{ "code": 200, "message": "成功", "data": null, "traceId": null, "success": true }
|
||||
```
|
||||
|
||||
同时 GB-ADM-096 新增的一行(原文节选):
|
||||
|
||||
```json
|
||||
{
|
||||
"logId": "2104527347090894850",
|
||||
"eventType": "BATCH_REPORTER_CHANGE",
|
||||
"eventTypeName": "报账人变更",
|
||||
"changeType": "DATA",
|
||||
"content": "主报账人:李雪梅 → 刘大山",
|
||||
"operatorType": "ADMIN",
|
||||
"operatorId": "1001",
|
||||
"operatorName": "admin",
|
||||
"extra": {
|
||||
"staffId": "1005",
|
||||
"staffName": "刘大山",
|
||||
"staffRole": "LEADER",
|
||||
"reporterRankBefore": "NONE",
|
||||
"reporterRankAfter": "PRIMARY",
|
||||
"primaryReporterBefore": { "staffId": "1002", "staffName": "李雪梅" },
|
||||
"primaryReporterAfter": { "staffId": "1005", "staffName": "刘大山" }
|
||||
},
|
||||
"changedAt": "2026-09-28 19:03:14"
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
无空数据形态。把人设成他已有的等级:返回 200,时间线不新增(TEST 实测 7→7)。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{ "code": 589508, "message": "报账人不是该团期已派员工", "data": null, "traceId": null, "success": false }
|
||||
```
|
||||
|
||||
```json
|
||||
{ "code": 589598, "message": "团期已确认,配置不可修改", "data": null, "traceId": null, "success": false }
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 主 / 次报账人归属都没变就不写,业务写入照常执行。
|
||||
- content:「主报账人:张三 → 李四」「次报账人:无 → 王五」「取消主报账人:张三」。把次报账人升为主报账人时两段并在一行:「主报账人:无 → 乌日娜;次报账人:乌日娜 → 无」。
|
||||
- 前任在同一事务内加锁读取,记下的前任不会是过期值。
|
||||
- 历史数据里一团有两个主报账人时,重设其中一个会把另一个降级;归属因此变了,会写一行。
|
||||
- 留痕写失败时整笔回滚,接口返回 500「系统繁忙,请稍后重试或联系客服」,团级行与子订单副本的等级都不变(TEST 用 CHECK 约束注入实测)。
|
||||
|
||||
### 3. 团期单人删除 `DELETE /v3/admin/group-batch/{productBatchId}/staff/{staffId}`
|
||||
|
||||
**VO**: `Result<BatchStaffRemoveRespVO>`(无请求体)
|
||||
|
||||
#### 使用场景
|
||||
|
||||
名册里单独删掉一个人,其他人不动;同步删掉本团活跃子订单上此人的团期副本。本单在删除成功后写一行「移除团期人员」。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|------|------|------|------|------|------|
|
||||
| productBatchId | Path | Long | ✅ | 雪花 ID | 产品侧排期 ID |
|
||||
| staffId | Path | Long | ✅ | 须在本团 | 要删除的员工 ID |
|
||||
|
||||
#### 出参 `Result<BatchStaffRemoveRespVO>`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| productBatchId / groupBatchId | String | 回显,不变 |
|
||||
| removedStaffId / removedStaffRole | Long / String | 被删的人,不变 |
|
||||
| primaryReporterRemoved | Boolean | 删的是否主报账人,不变 |
|
||||
| affectedOrderCount | Integer | 同步删除副本的子订单数,不变 |
|
||||
| staffList | Array | 删除后的名册,不变 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```http
|
||||
DELETE /v3/admin/group-batch/2104527134162853890/staff/1007
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
响应结构不变(TEST 原文节选,略去名册):
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": {
|
||||
"productBatchId": "2104527134162853890",
|
||||
"groupBatchId": "2104527135173685249",
|
||||
"removedStaffId": 1007,
|
||||
"removedStaffRole": "LEADER",
|
||||
"primaryReporterRemoved": true,
|
||||
"affectedOrderCount": 1
|
||||
},
|
||||
"traceId": null,
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
同时 GB-ADM-096 新增的一行(原文节选):
|
||||
|
||||
```json
|
||||
{
|
||||
"logId": "2104527571683274754",
|
||||
"eventType": "BATCH_STAFF_REMOVE",
|
||||
"eventTypeName": "移除团期人员",
|
||||
"changeType": "DATA",
|
||||
"content": "移除领队 白云飞(原主报账人,团期现无主报账人)",
|
||||
"operatorType": "ADMIN",
|
||||
"operatorId": "1001",
|
||||
"extra": {
|
||||
"staffId": "1007",
|
||||
"staffName": "白云飞",
|
||||
"staffRole": "LEADER",
|
||||
"reporterRankBefore": "PRIMARY",
|
||||
"primaryReporterBefore": { "staffId": "1007", "staffName": "白云飞" },
|
||||
"primaryReporterAfter": null
|
||||
},
|
||||
"changedAt": "2026-09-28 19:04:08"
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
无空数据形态。删的不是报账人时 content 只有「移除导游 张三」,extra 不带报账人前后字段。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{ "code": 589508, "message": "报账人不是该团期已派员工", "data": null, "traceId": null, "success": false }
|
||||
```
|
||||
|
||||
```json
|
||||
{ "code": 589598, "message": "团期已确认,配置不可修改", "data": null, "traceId": null, "success": false }
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 每次删除成功写一行。加锁读到的名册里已经没有此人(并发下刚被别人删掉)时不写。
|
||||
- 删除不在本团的人返回 589508,message 是错误码共用的「报账人不是该团期已派员工」,与改前相同。
|
||||
- 响应里的 `primaryReporterRemoved` 与时间线 extra 的 `primaryReporterAfter: null` 是同一件事的两处体现。
|
||||
|
||||
### 4. 团期单人更换 `PUT /v3/admin/group-batch/{productBatchId}/staff/{staffId}/replace`
|
||||
|
||||
**VO**: `BatchStaffReplaceReqVO` → `Result<BatchStaffReplaceRespVO>`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
名册里把一个人换成另一个人;配置位、排序、备注、报账人等级、服务日期都转给新人。本单在更换成功后写一行「更换团期人员」。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|------|------|------|------|------|------|
|
||||
| productBatchId | Path | Long | ✅ | 雪花 ID | 产品侧排期 ID |
|
||||
| staffId | Path | Long | ✅ | 须在本团 | 被换下的员工 ID |
|
||||
| newStaffId | Body | Long | ✅ | 须上架、类型符合原配置位、不在本团 | 换上的员工 ID |
|
||||
|
||||
#### 出参 `Result<BatchStaffReplaceRespVO>`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| oldStaffId / newStaffId | Long | 换下 / 换上的人,不变 |
|
||||
| staffRole | String | 新人落库角色,不变 |
|
||||
| reporterRank | String | 新人继承的等级,不变 |
|
||||
| primaryReporterTransferred | Boolean | 主报账人是否随之转给新人,不变 |
|
||||
| affectedOrderCount / staffList | - | 不变 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
`PUT /v3/admin/group-batch/2104527134162853890/staff/1008/replace`(萨仁高娃是主报账人):
|
||||
|
||||
```json
|
||||
{ "newStaffId": 1009 }
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
响应结构不变(TEST 原文节选,略去名册):
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": {
|
||||
"productBatchId": "2104527134162853890",
|
||||
"groupBatchId": "2104527135173685249",
|
||||
"oldStaffId": 1008,
|
||||
"newStaffId": 1009,
|
||||
"staffRole": "LEADER",
|
||||
"reporterRank": "PRIMARY",
|
||||
"primaryReporterTransferred": true,
|
||||
"affectedOrderCount": 1
|
||||
},
|
||||
"traceId": null,
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
同时 GB-ADM-096 新增的一行(原文节选):
|
||||
|
||||
```json
|
||||
{
|
||||
"logId": "2104527581611192321",
|
||||
"eventType": "BATCH_STAFF_REPLACE",
|
||||
"eventTypeName": "更换团期人员",
|
||||
"changeType": "DATA",
|
||||
"content": "领队 萨仁高娃 → 陈志远(主报账人随之转给陈志远)",
|
||||
"operatorType": "ADMIN",
|
||||
"operatorId": "1001",
|
||||
"extra": {
|
||||
"oldStaff": { "staffId": "1008", "staffName": "萨仁高娃", "staffRole": "LEADER", "reporterRank": "PRIMARY" },
|
||||
"newStaff": { "staffId": "1009", "staffName": "陈志远", "staffRole": "LEADER", "reporterRank": "PRIMARY" },
|
||||
"primaryReporterBefore": { "staffId": "1008", "staffName": "萨仁高娃" },
|
||||
"primaryReporterAfter": { "staffId": "1009", "staffName": "陈志远" }
|
||||
},
|
||||
"changedAt": "2026-09-28 19:04:10"
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
无空数据形态。换下的不是报账人时 content 只有「导游 张三 → 李四」,extra 不带报账人前后字段。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{ "code": 589508, "message": "报账人不是该团期已派员工", "data": null, "traceId": null, "success": false }
|
||||
```
|
||||
|
||||
```json
|
||||
{ "code": 589598, "message": "团期已确认,配置不可修改", "data": null, "traceId": null, "success": false }
|
||||
```
|
||||
|
||||
100001 / 589582 / 582103 / 582118 / 582114 / 582119 / 589553 与改前相同。
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 更换一定改了名单,每次成功都写一行。
|
||||
- 次报账人同理:「领队 刘大山 → 乌日娜(次报账人随之转给乌日娜)」,extra 带 `secondaryReporterBefore` / `secondaryReporterAfter`。
|
||||
- 落库角色变了时两边都带角色,如「领队 李四 → 导游 巴特尔」。
|
||||
|
||||
### 5. 取消成团 `POST /v3/admin/order/group-batch/{groupBatchId}/cancel-group`
|
||||
|
||||
**VO**: `Result<Void>`(无请求体)
|
||||
|
||||
#### 使用场景
|
||||
|
||||
团期从「资源准备中」退回「招募中」,同时回收整团的导游 / 摄影配置。本单在回收之后单独写一行「取消成团·回收人员」,原来那行「取消成团」不动。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|------|------|------|------|------|------|
|
||||
| groupBatchId | Path | Long | ✅ | 雪花 ID | 团期主订单 ID(不是 productBatchId) |
|
||||
|
||||
#### 出参 `Result<Void>`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| data | null | 不变 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```http
|
||||
POST /v3/admin/order/group-batch/2104527135173685249/cancel-group
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{ "code": 200, "message": "成功", "data": null, "traceId": null, "success": true }
|
||||
```
|
||||
|
||||
同时 GB-ADM-096 新增的两行(原文节选,同一秒,按 logId 排序):
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"logId": "2104528117127360513",
|
||||
"changeType": "STATUS",
|
||||
"eventType": "BATCH_CANCEL_GROUP",
|
||||
"eventTypeName": "取消成团",
|
||||
"fromStatus": "RESOURCE_PREPARING",
|
||||
"toStatus": "RECRUITING",
|
||||
"content": "取消成团",
|
||||
"extra": null,
|
||||
"changedAt": "2026-09-28 19:06:18"
|
||||
},
|
||||
{
|
||||
"logId": "2104528117160914946",
|
||||
"changeType": "DATA",
|
||||
"eventType": "BATCH_STAFF_RECYCLED",
|
||||
"eventTypeName": "取消成团·回收人员",
|
||||
"fromStatus": "RECRUITING",
|
||||
"toStatus": "RECRUITING",
|
||||
"content": "取消成团,回收团期人员 2 人:王强、乌日娜(主报账人)",
|
||||
"operatorType": "ADMIN",
|
||||
"operatorId": "1001",
|
||||
"extra": {
|
||||
"recycledCount": 2,
|
||||
"staff": [
|
||||
{ "staffId": "1003", "staffName": "王强", "staffRole": "PHOTOGRAPHER", "reporterRank": "NONE" },
|
||||
{ "staffId": "1010", "staffName": "乌日娜", "staffRole": "LEADER", "reporterRank": "PRIMARY" }
|
||||
],
|
||||
"primaryReporterBefore": { "staffId": "1010", "staffName": "乌日娜" },
|
||||
"primaryReporterAfter": null
|
||||
},
|
||||
"changedAt": "2026-09-28 19:06:18"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
团期没配人员时只写「取消成团」一行,不写回收行(TEST 实测团期 Z:2→3,只多 `BATCH_CANCEL_GROUP`)。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
与改前相同(下为源码 `GroupBatchErrorCode` 定义的文案,本轮验收没有触发):
|
||||
|
||||
```json
|
||||
{ "code": 589502, "message": "取消成团被阻塞(有已确认子订单或已派单资源)", "data": null }
|
||||
```
|
||||
|
||||
```json
|
||||
{ "code": 589501, "message": "团期状态不允许当前操作", "data": null }
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 回收行的 `fromStatus` / `toStatus` 都是 `RECRUITING`(取消成团之后的状态)。它与「取消成团」通常在同一秒,靠 `logId` 稳定排在后面。
|
||||
- content:「取消成团,回收团期人员 N 人:张三(主报账人)、李四、王五(次报账人)」;回收的人里没有主报账人时末尾加「;其中无主报账人」。
|
||||
- 回收名单在同一事务内、软删之前加锁读取。回收或留痕任何一步失败,取消成团整体回滚。
|
||||
|
||||
### 6. 团期状态流水 `GET /v3/admin/order/group-batch/{groupBatchId}/status-logs`
|
||||
|
||||
**VO**: `GroupBatchStatusLogItemVO`(返回 `Result<List<GroupBatchStatusLogItemVO>>`,无请求体)
|
||||
|
||||
#### 使用场景
|
||||
|
||||
团期详情的时间线(GB-ADM-096)。结构不变;`eventType` 多了五个取值;同一秒内的行改为按 `logId` 升序。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|------|------|------|------|------|------|
|
||||
| groupBatchId | Path | Long | ✅ | 雪花 ID | 团期主订单 ID |
|
||||
|
||||
#### 出参 `Result<List<GroupBatchStatusLogItemVO>>`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| logId | String | 流水 ID;同秒排序的第二键 |
|
||||
| eventType | String | 新增五个值,见六.5 |
|
||||
| eventTypeName | String | 对应中文名,后端直供 |
|
||||
| changeType | String | 五个新事件都是 `DATA` |
|
||||
| fromStatus / toStatus | String | DATA 类两者相同,取写入时的团期状态 |
|
||||
| content | String | 展示文本,前端直接渲染 |
|
||||
| extra | Object | 结构化快照,按事件类型不同,见六.5 |
|
||||
| operatorType / operatorId / operatorName | String | 五个新事件都是 `ADMIN` + 管理员 ID(字符串)+ 管理员名字 |
|
||||
| 其余字段 | - | groupBatchId / fromStatusName / toStatusName / reason / changedAt 等,不变 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```http
|
||||
GET /v3/admin/order/group-batch/2104527135173685249/status-logs
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
TEST 原文节选(团期 X,排序修复后)。前两行同为 19:02:24,按 logId 升序:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": [
|
||||
{
|
||||
"logId": "2104527135194656770",
|
||||
"changeType": "STATUS",
|
||||
"eventType": "BATCH_CREATE",
|
||||
"eventTypeName": "建团",
|
||||
"content": "建团:2月18日海拉尔-呼伦湖2日团",
|
||||
"changedAt": "2026-09-28 19:02:24"
|
||||
},
|
||||
{
|
||||
"logId": "2104527136431976449",
|
||||
"changeType": "STATUS",
|
||||
"eventType": "BATCH_GROUP",
|
||||
"eventTypeName": "成团",
|
||||
"content": "手动成团 · 已售 1/15 户 · 理由:客户已全款,手动成团(#8482 验收造数)",
|
||||
"changedAt": "2026-09-28 19:02:24"
|
||||
},
|
||||
{
|
||||
"logId": "2104527342187737089",
|
||||
"groupBatchId": "2104527135173685249",
|
||||
"changeType": "DATA",
|
||||
"eventType": "BATCH_REPORTER_CHANGE",
|
||||
"eventTypeName": "报账人变更",
|
||||
"fromStatus": "RESOURCE_PREPARING",
|
||||
"fromStatusName": "资源准备中",
|
||||
"toStatus": "RESOURCE_PREPARING",
|
||||
"toStatusName": "资源准备中",
|
||||
"content": "主报账人:无 → 李雪梅",
|
||||
"reason": null,
|
||||
"operatorType": "ADMIN",
|
||||
"operatorId": "1001",
|
||||
"operatorName": "admin",
|
||||
"extra": {
|
||||
"staffId": "1002",
|
||||
"staffName": "李雪梅",
|
||||
"staffRole": "GUIDE",
|
||||
"reporterRankBefore": "NONE",
|
||||
"reporterRankAfter": "PRIMARY",
|
||||
"primaryReporterBefore": null,
|
||||
"primaryReporterAfter": { "staffId": "1002", "staffName": "李雪梅" }
|
||||
},
|
||||
"changedAt": "2026-09-28 19:03:13"
|
||||
}
|
||||
],
|
||||
"traceId": null,
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
无流水时 `data=[]`,与改前相同。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
与改前相同(源码 `GroupBatchErrorCode` 文案):
|
||||
|
||||
```json
|
||||
{ "code": 589507, "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)", "data": null }
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 排序:`changedAt` 升序,同一秒内 `logId` 升序(#8492)。TEST 同一团期修复前连读 5 次,都是「成团」排在「建团」之前;修复后连读 5 次,两组同秒行(建团 / 成团、取消成团 / 回收)全部按 logId 升序。
|
||||
- 历史不回补:本单合入之前的人员变更查不回来。
|
||||
- 库里认不出的事件码,`eventTypeName` 为 null,与改前相同。
|
||||
|
||||
---
|
||||
|
||||
## 四、契约约束与正确调用方式
|
||||
|
||||
> 本节只写**后端接受/拒绝的规则**和前端必须跟着做的事。
|
||||
|
||||
### ✅ 正确 / ❌ 错误用法对照
|
||||
|
||||
| 场景 | 做法 |
|
||||
|------|------|
|
||||
| ✅ 时间线展示新事件 | 渲染 `eventTypeName`,取不到回落 `eventType`;正文直接渲染 `content` |
|
||||
| ✅ 读 extra 里的报账人前后字段 | 缺键按 null 处理;要判断「这一行有没有改主报账人」,看 extra 里有没有 `primaryReporterAfter` 这个键 |
|
||||
| ❌ 把「缺键」当成「团期没有主报账人」 | 缺键只表示这一行没改该项归属;键在且值为 null 才表示那一端没有报账人 |
|
||||
| ❌ 把 extra 里的 staffId 转成数字 | extra 里的 ID 一律是字符串,按字符串比较 |
|
||||
| ❌ 用 productBatchId 调时间线或取消成团 | 人员四个接口的路径参数是 `productBatchId`,时间线与取消成团是 `groupBatchId`,两者不能混用 |
|
||||
| ❌ 前端按 changedAt 重排时间线 | changedAt 只到秒,重排会打乱同秒行的先后;按接口返回顺序展示 |
|
||||
|
||||
### 前端交接清单
|
||||
|
||||
**结论:无需改动。**
|
||||
|
||||
1. 团期时间线组件 `StatusLogsPanel` 渲染的是 `eventTypeName || eventType || '事件'`,中文名由后端直供,前端没有自建事件码映射表(#7987 时 mmg 实证;2026-09-28 复核 hl-ui `origin/v2.1@ce469f78` 未变)。五个新事件码不改代码就显示中文名。
|
||||
2. `content` 由后端拼好,面板直接渲染;新事件的说明文字都在 content 里。
|
||||
3. 面板对 extra 只挑 `orderNo` / `schemeName` / `kind` / `orderId` 几个键,缺键兜住。新事件的 extra 不含这些键,不会多渲染文字,也不会报错。
|
||||
4. 面板按接口返回顺序展示,没有在前端重排,同秒按 logId 排序的修复不用前端配合。
|
||||
5. 如果要在页面上用 extra(例如单独展示主报账人更替历史):报账人前后四个字段只在对应归属变了时出现,**缺键按 null 处理**;ID 都是字符串。
|
||||
6. 以上结论的前提是后端继续直供 `eventTypeName`。
|
||||
|
||||
---
|
||||
|
||||
## 五、数据库行为
|
||||
|
||||
| 情形 | order_batch_staff | group_batch_status_log |
|
||||
|------|-------------------|------------------------|
|
||||
| 保存配置:名单或报账人归属有变化 | 写入(与改前相同) | +1 `BATCH_STAFF_CONFIG_SAVE` |
|
||||
| 保存配置:原样、只改排序 / 备注 / 服务日期 / 日薪 | 写入(与改前相同) | 不写 |
|
||||
| 设报账人:归属变了 | 更新(与改前相同) | +1 `BATCH_REPORTER_CHANGE` |
|
||||
| 设报账人:设成已有等级 | 照常执行 | 不写 |
|
||||
| 单人删除 / 单人更换成功 | 写入(与改前相同) | +1 `BATCH_STAFF_REMOVE` / `BATCH_STAFF_REPLACE` |
|
||||
| 取消成团,团期配了人员 | 整团软删(与改前相同) | 「取消成团」之后 +1 `BATCH_STAFF_RECYCLED` |
|
||||
| 取消成团,团期没配人员 | 不动 | 只有「取消成团」一行 |
|
||||
| 被拒(589508 / 589598 / 582115 等) | 不动 | 不写 |
|
||||
| 留痕写失败 | 回滚 | 不写(接口 500) |
|
||||
|
||||
- **零 DDL**,不需要 Flyway:只往 `group_batch_status_log` 追加行,新事件码是 `event_type` 列的新取值。
|
||||
- 写之前先对 `order_batch_staff` 做锁定读(`SELECT ... FOR UPDATE`)取前态:保存配置锁本次覆盖范围内的行,设报账人 / 单人删除 / 单人更换 / 取消成团回收锁整团行。时间线记下的前任不会是过期值。
|
||||
- 留痕与业务写入在同一事务:业务回滚,留痕跟着回滚;留痕写失败,业务也回滚。
|
||||
- 子订单上的团期人员副本照旧扇出,副本的变化不进订单时间线。
|
||||
|
||||
---
|
||||
|
||||
## 六、边界行为
|
||||
|
||||
- 未登录 → 网关返回 `code=401`(HTTP 200)。
|
||||
- 无团期管理权限 → 589507,与改前相同。
|
||||
- 操作人:五种新事件都由后台请求触发,`operatorType=ADMIN`,`operatorId` 是管理员 ID(字符串),`operatorName` 是管理员名字。TEST 新增的 17 行全部是 `ADMIN` / `"1001"` / `admin`。
|
||||
- 手机号:content 和 extra 都不带手机号,明文、库列值都不带。
|
||||
- 团期当前状态是库里认不出的历史值时,这一行的 `fromStatus` / `toStatus` 为 null,业务照常写入。
|
||||
- 订单自派人员(`source=ORDER`)的变更不在本单范围。
|
||||
|
||||
---
|
||||
|
||||
## 六.5、枚举 / 数据字典
|
||||
|
||||
### eventType 新增取值(`GroupBatchLogEventType`)
|
||||
|
||||
| 值 | 中文名(eventTypeName) | changeType | 写入接口 | 典型 content(TEST 原文) |
|
||||
|---|---|---|---|---|
|
||||
| `BATCH_STAFF_CONFIG_SAVE` | 调整团期人员 | DATA | 保存团期人员配置 | 「导游位:+萨仁高娃;−李雪梅」「导游位:−陈志远(原主报账人,团期现无主报账人)」 |
|
||||
| `BATCH_REPORTER_CHANGE` | 报账人变更 | DATA | 设置报账人等级 | 「主报账人:李雪梅 → 刘大山」「次报账人:无 → 刘大山」「主报账人:无 → 乌日娜;次报账人:乌日娜 → 无」 |
|
||||
| `BATCH_STAFF_REMOVE` | 移除团期人员 | DATA | 团期单人删除 | 「移除领队 白云飞(原主报账人,团期现无主报账人)」 |
|
||||
| `BATCH_STAFF_REPLACE` | 更换团期人员 | DATA | 团期单人更换 | 「领队 萨仁高娃 → 陈志远(主报账人随之转给陈志远)」「领队 刘大山 → 乌日娜(次报账人随之转给乌日娜)」 |
|
||||
| `BATCH_STAFF_RECYCLED` | 取消成团·回收人员 | DATA | 取消成团 | 「取消成团,回收团期人员 2 人:王强、乌日娜(主报账人)」 |
|
||||
|
||||
content 里的角色中文名与名册 `staffRoleName` 同源(导游 / 领队 / 摄影等);报账人等级中文名为「主报账人」「次报账人」「非报账人」。
|
||||
|
||||
### 公共:报账人前后字段(五种事件都可能带)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| primaryReporterBefore | Object 或 null | 主报账人归属变了才有这个键;值为 `{staffId, staffName}`(staffId 为字符串),那一端没有主报账人时为 null |
|
||||
| primaryReporterAfter | Object 或 null | 同上,变更后 |
|
||||
| secondaryReporterBefore | Object 或 null | 次报账人归属变了才有这个键;形态同上 |
|
||||
| secondaryReporterAfter | Object 或 null | 同上,变更后 |
|
||||
|
||||
### BATCH_STAFF_CONFIG_SAVE 的 extra
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| scopeRoles | String[] 或 null | 本次覆盖范围;null 表示整期全量保存 |
|
||||
| added | Array(恒在,可为空) | 新增的人:staffId(String)/ staffName / staffRole |
|
||||
| removed | Array(恒在,可为空) | 移出的人:staffId(String)/ staffName / staffRole / reporterRank(移出前等级) |
|
||||
| roleChanged | Array(恒在,可为空) | 落库角色变了的人:staffId(String)/ staffName / staffRoleBefore / staffRoleAfter(一人多角色时用「/」连接) |
|
||||
|
||||
### BATCH_REPORTER_CHANGE 的 extra
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| staffId | String | 被设等级的人 |
|
||||
| staffName | String | 姓名快照 |
|
||||
| staffRole | String | 落库角色 |
|
||||
| reporterRankBefore | String | 此人原等级:PRIMARY / SECONDARY / NONE |
|
||||
| reporterRankAfter | String | 此人新等级 |
|
||||
|
||||
被自动降级的原主(次)报账人体现在报账人前后字段的 Before 里。
|
||||
|
||||
### BATCH_STAFF_REMOVE 的 extra
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| staffId | String | 被删的人 |
|
||||
| staffName | String | 姓名快照 |
|
||||
| staffRole | String | 落库角色 |
|
||||
| reporterRankBefore | String | 删除前等级 |
|
||||
|
||||
### BATCH_STAFF_REPLACE 的 extra
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| oldStaff | Object | 换下的人:staffId(String)/ staffName / staffRole / reporterRank(换下前的等级) |
|
||||
| newStaff | Object | 换上的人:staffId(String)/ staffName / staffRole / reporterRank(继承到的等级) |
|
||||
|
||||
### BATCH_STAFF_RECYCLED 的 extra
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| recycledCount | Integer | 回收人数(按人计) |
|
||||
| staff | Array | 每人一项:staffId(String)/ staffName / staffRole / reporterRank |
|
||||
|
||||
回收到主(次)报账人时带报账人前后字段,After 恒为 null。
|
||||
|
||||
---
|
||||
|
||||
## 六.6、修改前后对比
|
||||
|
||||
### 字段级对比
|
||||
|
||||
| 字段 | 改前 | 改后 |
|
||||
|------|------|------|
|
||||
| 六个接口的请求 / 响应字段 | - | 不变 |
|
||||
| GB-ADM-096 `eventType` 取值 | 没有人员类事件 | 新增五个 |
|
||||
| GB-ADM-096 同秒行顺序 | 不稳定 | `logId` 升序 |
|
||||
|
||||
### 行为级对比
|
||||
|
||||
| 行为 | 改前 | 改后 |
|
||||
|------|------|------|
|
||||
| 保存配置有增删、角色变化或报账人归属变化 | 时间线无记录 | +1 `BATCH_STAFF_CONFIG_SAVE` |
|
||||
| 保存配置原样、只改排序或备注 | 时间线无记录 | 仍无记录 |
|
||||
| 设报账人 | 时间线无记录 | +1 `BATCH_REPORTER_CHANGE`,被降级的原报账人写在同一行 |
|
||||
| 单人删除 / 单人更换 | 时间线无记录 | +1 `BATCH_STAFF_REMOVE` / `BATCH_STAFF_REPLACE` |
|
||||
| 取消成团回收人员 | 只有「取消成团」一行 | 「取消成团」之后 +1 回收行 |
|
||||
| 同秒行顺序 | TEST 连读 5 次都是「成团」排在「建团」前 | 连读 5 次都按 logId 升序 |
|
||||
|
||||
## 六.7、影响评估
|
||||
|
||||
- **是否破坏向后兼容**: 否(结构不变;新增的是 `eventType` 取值,前端按 `eventTypeName` 渲染)
|
||||
- **前端是否必须同步上线**: 否(前端零改动)
|
||||
- **前端 workaround 清理点**: 无
|
||||
|
||||
---
|
||||
|
||||
## 七、不影响范围
|
||||
|
||||
- **仅影响**: 五个写接口成功后的时间线副作用;GB-ADM-096 的取值域和同秒顺序
|
||||
- **零影响**:
|
||||
- 六个接口的请求 / 响应结构和错误码
|
||||
- 保存配置时保留人员沿用原报账人等级和备注:这一行为随 #8468 发布(见 `28_8468` 交接件),本篇不重复
|
||||
- 名册、候选列表、扇出到子订单的逻辑
|
||||
- 订单级时间线
|
||||
- 订单自派人员(`source=ORDER`)
|
||||
- 本单合入之前的历史变更(不回补)
|
||||
|
||||
---
|
||||
|
||||
## 八、测试环境已验证
|
||||
|
||||
部署:主轮(19:02–19:09)跑在 hl-order-service-v3 dev-v3 @ `e24be7af8`(#8490,18:53:31 部署),两实例经运行字节探针确认加载的是本次代码(`BATCH_STAFF_CONFIG_SAVE`、「取消成团·回收人员」命中,进程 jar 与磁盘 jar 同 inode)。排序复验(19:28)跑在 dev-v3 @ `75e182710`(#8492)。
|
||||
|
||||
经网关 `api.test.1814.love` 用 admin token(operatorId 1001)实测。团期 X:groupBatchId `2104527135173685249`(productBatchId `2104527134162853890`,一户全款、手动成团);团期 Z:groupBatchId `2104528158369951745`(productBatchId `2104528157774356482`)。每步前后各读一次 GB-ADM-096 整段原文比对行数。
|
||||
|
||||
```
|
||||
AC-B1 19:03:13~16 X 依次设主报账人 李雪梅 → 刘大山 → 白云飞
|
||||
→ GB-ADM-096 4→7,新增「主报账人:无 → 李雪梅」「主报账人:李雪梅 → 刘大山」「主报账人:刘大山 → 白云飞」,
|
||||
operatorType=ADMIN、operatorId=1001;同一次读取里 BATCH_CREATE / BATCH_GROUP 为阳性对照 ✓
|
||||
AC-B3 19:03:16 X 对白云飞再设 PRIMARY(已有等级) → 200,7→7 ✓
|
||||
AC-A2 19:03:31 X 设次报账人 刘大山 → 7→8「次报账人:无 → 刘大山」✓
|
||||
AC-A1 19:03:36 X 按前端形态原样保存导游位(只带 staffId/staffRole/sortOrder)
|
||||
AC-A2 → 200,8→8;团级行重新插入(白云飞 batch_staff_id 2104527299623956483 → 2104527440154095618)仍为 PRIMARY,
|
||||
AC-B3 刘大山仍为 SECONDARY;子订单 2104527134926221314 的 GROUP_BATCH 副本同为 PRIMARY / SECONDARY,update_time 19:03:37 ✓
|
||||
AC-B3 19:03:54 X 只改排序 → 8→8;19:03:56 只改备注 → 8→8 ✓
|
||||
AC-B3 19:03:57 X 导游位加萨仁高娃、移出李雪梅 → 8→9「导游位:+萨仁高娃;−李雪梅」✓
|
||||
AC-B2 19:04:07 X 单人删除主报账人白云飞 → 9→10「移除领队 白云飞(原主报账人,团期现无主报账人)」,
|
||||
响应 primaryReporterRemoved=true,extra.primaryReporterAfter=null ✓
|
||||
19:04:09 X 设主报账人 萨仁高娃 → 10→11「主报账人:无 → 萨仁高娃」
|
||||
AC-B2 19:04:10 X 单人更换主报账人 萨仁高娃 → 陈志远 → 11→12「领队 萨仁高娃 → 陈志远(主报账人随之转给陈志远)」✓
|
||||
AC-B2 19:04:11 X 单人更换次报账人 刘大山 → 乌日娜 → 12→13「领队 刘大山 → 乌日娜(次报账人随之转给乌日娜)」✓
|
||||
AC-A3 19:04:23 X 保存导游位时移出主报账人陈志远 → 13→14「导游位:−陈志远(原主报账人,团期现无主报账人)」,
|
||||
extra.primaryReporterAfter=null,导游位只剩乌日娜(SECONDARY)✓
|
||||
AC-B5 19:04:24~26 X 对已不在本团的人 设报账人 / 删除 / 更换 → 三个都是 589508「报账人不是该团期已派员工」,14→14,名册不变 ✓
|
||||
AC-B6 19:05:28 X 给 group_batch_status_log 临时加 CHECK 约束(只拦本团新的 BATCH_REPORTER_CHANGE,约 1.4 秒)后设主报账人乌日娜
|
||||
→ 500「系统繁忙,请稍后重试或联系客服」;服务端日志:order_batch_staff、order_staff_assignment 两条 UPDATE 已执行,
|
||||
随后 INSERT 时间线触发 3819;回滚后团级行与子订单副本的乌日娜仍为 SECONDARY,时间线 14→14;
|
||||
约束删除后 SHOW CREATE TABLE 与注入前逐字一致 ✓
|
||||
19:06:04 X 约束删除后再设一次 → 14→15「主报账人:无 → 乌日娜;次报账人:乌日娜 → 无」✓
|
||||
AC-B4 19:06:18 X 取消成团(已配人员) → 15→17,BATCH_CANCEL_GROUP「取消成团」之后
|
||||
BATCH_STAFF_RECYCLED「取消成团,回收团期人员 2 人:王强、乌日娜(主报账人)」✓
|
||||
AC-B4 19:06:28 Z 取消成团(未配人员) → 2→3,只多 BATCH_CANCEL_GROUP,无回收行 ✓
|
||||
AC-B5 19:07:23~27 Z 团期确认后(MATERIAL_PREPARING)保存 / 设报账人 / 删除 / 更换
|
||||
→ 四个都是 589598「团期已确认,配置不可修改」,14→14,名册不变 ✓
|
||||
AC-B7 19:08:21 X、Z 两团全部 31 行(新事件 17 行):11 个明文手机号逐个查、7 个库列值逐个查、掩码 **** 与 phone 键名,全部 0 命中;
|
||||
带数字边界的 11 位手机号正则 0 命中(19:44 复查);不带边界时命中的 3 行都是既有事件 extra 里雪花 ID 的片段,新事件 0 命中 ✓
|
||||
排序 19:21:19~23 排序修复部署前,X 连读 5 次:BATCH_GROUP 都排在 BATCH_CREATE 前(同为 19:02:24)
|
||||
19:28:36~40 dev-v3 75e182710,X 连读 5 次:两组同秒行(建团 / 成团、取消成团 / 回收)全部 logId 升序 ✓
|
||||
```
|
||||
|
||||
所有新增行 `operatorType=ADMIN`、`operatorId="1001"`、`operatorName=admin`、`changedAt` 有值,extra 里的 ID 全部是字符串。
|
||||
|
||||
单元层:五处留痕调用逐一去掉,对应用例各自转红(共 12 例);#8492 的排序键去掉后 `GroupBatchStatusLogMapperOrderTest` 转红。
|
||||
|
||||
---
|
||||
|
||||
## 九、相关历史 PR
|
||||
|
||||
- #3676:引入主 / 次报账人等级
|
||||
- #7304:GB-ADM-096 团期状态流水只读端点
|
||||
- #7987:时间线新事件由后端直供 `eventTypeName`,前端零改动的先例
|
||||
- #8231:取消成团回收导游 / 摄影配置
|
||||
- #8354:团期单人删除、单人更换
|
||||
- #8468:保存配置时保留人员沿用原报账人等级和备注(PR #8475)
|
||||
- #8481:团期物资留痕(同日,同一张时间线)
|
||||
|
||||
---
|
||||
|
||||
## 十、相关文档
|
||||
|
||||
- 关联 Issue: [wx/HL#8482](https://git.1814.love/wx/HL/issues/8482)
|
||||
- 关联 PR: [wx/HL#8490](https://git.1814.love/wx/HL/pulls/8490)、[wx/HL#8492](https://git.1814.love/wx/HL/pulls/8492)
|
||||
- 同日交接件:`changelogs-v2/2026-09/28_8468_团期导领摄配置加服务日期与基础日薪并在选人列表显示占用-修改接口-管理后台.md`、`changelogs-v2/2026-09/28_8481_团期物资确认后改清单自动失效并补全物资留痕-修改接口-管理后台.md`
|
||||
|
||||
## 关联 / 联系人
|
||||
|
||||
### 链接
|
||||
|
||||
- **Issue**: [#8482](https://git.1814.love/wx/HL/issues/8482)
|
||||
- **PR**: [#8490](https://git.1814.love/wx/HL/pulls/8490)、[#8492](https://git.1814.love/wx/HL/pulls/8492)
|
||||
- **Merge commit**: [e24be7af8](https://git.1814.love/wx/HL/commit/e24be7af8)、[75e182710](https://git.1814.love/wx/HL/commit/75e182710)
|
||||
|
||||
### 联系人
|
||||
|
||||
- **后端负责人**: @jw
|
||||
在新工单中引用
屏蔽一个用户