changelog-filename-gate / validate (push) Failing after 2s
保存人员配置 staffList 必填、备品候选 keyword 转义、加备品行定点查三端点 行为变更,前端实查零改动:saveGroupBatchStaff 请求体恒带 staffList,备品 keyword 原样透传,加行 500 上限解除对调用方透明。
13 KiB
13 KiB
schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
| schema | ticket | title | consumer | author | change_type | backend_status | gateway_status | frontend_status | frontend_owner | frontend_ref | target_release | verified_at | status_note | updated_at | base |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hl-changelog/v2 | 7377 | 团期人员配置 staffList 改必填 + 备品候选关键字转义 + 加备品行改定点查 | admin | jw(GIT) | 修改接口 | deployed | verified | not_required | mmg | 2026-09-09 | not_required 2026-09-09 mmg:三端点行为变更,前端零改动。①保存人员 saveGroupBatchStaff(orderV2GroupBatch.js:186) 请求体恒为 {staffList},省略字段路径不存在,清空即传 [](GroupBatchStaffConfigModal handleSave 过滤后数组恒在)。②备品候选 keyword 由 SuppliesPickerModal 原样透传(仅 trim),无前端通配依赖。③加备品行 addGroupBatchSupplies 只传 {suppliesResourceId,quantity},500 上限解除对调用方透明,589518 已正确区分库挂/无备品。 | 2026-09-09 | dev-v3 |
团期人员配置必填与备品库口径收口
一、给前端的一句话
两处行为变更要注意:保存团期人员配置必须带 staffList 字段(要清空就传 [],别省略);备品候选列表搜 % / _ 不再返回全库。另有一处纯修复不影响调用方——加备品行不再受「备品库超 500 条」的隐性上限。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 保存团期人员配置 | PUT | /v3/admin/group-batch/:productBatchId/staff |
修改接口 | staffList 由可省略改为必填,缺失返 400;显式传 [] 仍是清空 |
| 2 | 团期物资候选列表 | GET | /v3/admin/order/group-batch/:groupBatchId/supplies/candidates |
修改接口 | keyword 转义 LIKE 通配符,% / _ 不再当通配符 |
| 3 | 团期物资新增行 | POST | /v3/admin/order/group-batch/:groupBatchId/supplies |
修改接口 | 取备品库快照改走定点查,解除「备品库超 500 条后加不进」的隐性上限 |
三、接口详情
1. 保存团期人员配置 PUT /v3/admin/group-batch/:productBatchId/staff
VO: BatchStaffConfigReqVO / BatchStaffConfigRespVO
使用场景
团期详情的「导游 / 摄影」配置,全量覆盖式保存。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
productBatchId |
Path | String | 是 | 正整数 | 产品侧班期 ID |
staffList |
Body | Array | 是(本次变更) | 可为空数组 | 全量覆盖列表;显式传 [] 即清空,字段缺失一律 400 |
staffList[].staffId |
Body | String | 是 | 正整数 | 资源域人员 ID |
staffList[].staffRole |
Body | String | 是 | LEADER / GUIDE / DRIVER / PHOTOGRAPHER / OTHER,区分大小写 |
越界值返 400;与该人在资源域的实际类型不符返 582114 |
staffList[].sortOrder |
Body | Integer | 否 | 默认 0 | 展示排序 |
staffList[].remark |
Body | String | 否 | 最长 500 | 备注 |
出参
| 字段 | 类型 | 说明 |
|---|---|---|
code / message / success |
Integer / String / Boolean | 业务结果 |
data.staffList |
Array | 保存后的配置快照,含 staffId / staffName / staffPhone / staffRole 等 |
data.affectedOrderCount |
Integer | 已触发异步扇出的活跃订单数,仅作提示 |
请求示例
{
"staffList": [
{
"staffId": "1002",
"staffRole": "GUIDE",
"sortOrder": 0
}
]
}
响应示例
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"staffList": [
{
"staffId": "1002",
"staffName": "李雪梅",
"staffPhone": "138****1002",
"staffRole": "GUIDE",
"sortOrder": 0
}
],
"affectedOrderCount": 2
}
}
空数据 / 降级响应
显式传 [] 是合法请求:清空该团期全部人员配置并返回空 staffList,code 仍为 200。
错误响应
{
"code": 400,
"message": "staff 配置列表不能缺失;确要清空请显式传空数组 []",
"data": null,
"success": false
}
业务边界
- 字段缺失或字段名写错一律 400,且现有配置零变动、不触发扇出——这正是本次要堵的洞。
- 团期未创建返 589553、未成团返 589552;人员角色与资源域类型不符返 582114,整批拒绝不落库。
- 「显式传
[]即清空」这条既有语义没有改变。
2. 团期物资候选列表 GET /v3/admin/order/group-batch/:groupBatchId/supplies/candidates
VO: SuppliesCandidateRespVO
使用场景
团期物资清单的「从备品库选择」弹窗,支持按分类与关键字筛选。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
groupBatchId |
Path | String | 是 | 正整数 | 团期主订单 ID |
categoryCode |
Query | String | 否 | 字典 supplies_category |
分类筛选 |
keyword |
Query | String | 否 | 无长度限制 | 匹配名称或副标题;本次起 LIKE 通配符被转义 |
出参
| 字段 | 类型 | 说明 |
|---|---|---|
code / message / success |
Integer / String / Boolean | 业务结果 |
data[].suppliesResourceId |
String | 备品资源 ID |
data[].suppliesName / subtitle / category |
String | 备品名称、副标题、分类 |
data[].billingType / hasCost / basePrice |
String / Boolean / String | 计费方式、是否收费、库价 |
data[].added / batchSuppliesId |
Boolean / String | 是否已加入本团期清单及对应行 ID |
请求示例
GET /v3/admin/order/group-batch/2097500233511362561/supplies/candidates?keyword=%E5%B8%BD
响应示例
{
"code": 200,
"message": "成功",
"success": true,
"data": [
{
"suppliesResourceId": "2023438566624866305",
"suppliesName": "定制遮阳帽",
"subtitle": "呼籁旅行专属防晒鸭舌帽",
"category": "personal_gear",
"billingType": "PER_PERSON",
"hasCost": true,
"basePrice": "15.00",
"added": false,
"batchSuppliesId": null
}
]
}
空数据 / 降级响应
无命中返回 data: [],code 仍为 200。
错误响应
{
"code": 589500,
"message": "团期不存在",
"data": null,
"success": false
}
业务边界
keyword里的%/_/\/!一律按字面字符匹配,不再当通配符。- 普通关键字的搜索结果不受影响(实测「帽」仍命中「定制遮阳帽」)。
- 只返上架备品,排序与分页口径未变。
3. 团期物资新增行 POST /v3/admin/order/group-batch/:groupBatchId/supplies
VO: AddSuppliesReqVO
使用场景
团期物资清单新增一行,可从备品库选择(传 suppliesResourceId)或纯手填(传 suppliesName)。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
groupBatchId |
Path | String | 是 | 正整数 | 团期主订单 ID |
suppliesResourceId |
Body | String | 与 suppliesName 二选一 |
正整数 | 备品库资源 ID;传了则名称、分类、计费方式以库为准覆盖入参 |
suppliesName |
Body | String | 与 suppliesResourceId 二选一 |
最长 100 | 纯手填备品名 |
quantity |
Body | Integer | 是 | 大于 0 | 数量 |
unitPrice |
Body | String | 否 | 金额字符串 | 单价,入参优先;不传取库价 |
出参
| 字段 | 类型 | 说明 |
|---|---|---|
code / message / success |
Integer / String / Boolean | 业务结果 |
data |
String | 新建行主键 batchSuppliesId |
请求示例
{
"suppliesResourceId": "2023438566624866305",
"quantity": 1
}
响应示例
{
"code": 200,
"message": "成功",
"success": true,
"data": "2097600714757783553"
}
空数据 / 降级响应
无空成功结果;任一校验失败返回 data: null、success: false。
错误响应
{
"code": 589523,
"message": "该备品已在本团期物资清单中,请直接调整数量",
"data": null,
"success": false
}
业务边界
- 备品库不可用(资源域故障)与备品本身不可用(不存在 / 已下架)分开报:前者 589522,后者 589519。
- 同一
suppliesResourceId重复加入返 589523;纯手填行不参与判重。 - 团期不在「物料准备中」返 589520,团期不存在返 589500。
四、契约约束与正确调用方式
- 保存人员配置永远显式带上
staffList:要清空传[],不要省略字段。省略在改前会静音清空整团配置,现在会 400。 - 备品搜索框不需要前端做任何转义,直接把用户输入原样传
keyword即可。 - 加备品行时
unitPrice不传即取库价;传了以入参为准(同团期可议价不同)。
五、数据库行为
- 人员配置:全量覆盖式保存——软删旧行 + 插入新行,随后异步扇出到该班期全部活跃订单的
order_staff_assignment。校验失败时一行都不写。 - 物资新增:向
order_batch_supplies插一行;重复supplies_resource_id在插入前被拒。 - 本次无表结构变更、无 Flyway 脚本。
六、边界行为
- 人员配置越界角色值区分大小写,
guide不等于GUIDE。 - 备品候选列表只返上架备品;已下架的既有行不受影响,仍留在清单里。
- 加备品行的库快照覆盖入参的字段是名称、分类、计费方式;单价例外,入参优先。
六.6、修改前后对比
| 场景 | 改前 | 改后 |
|---|---|---|
保存人员配置时不带 staffList(或字段名写错) |
静音软删整团人员配置 + 触发全团扇出,返 200 | 返 400,现有配置零变动 |
保存人员配置时显式传 [] |
清空 | 清空(不变) |
备品候选搜 % 或 _ |
返回全库 | 返回零结果 |
| 备品候选搜普通关键字 | 正常命中 | 正常命中(不变) |
| 备品库超过 500 条时加第 501 条之后的备品 | 一律报「所选备品不存在或已下架」,实际是被 500 条上限截断 | 正常加入 |
| 资源域故障时加备品行 | 报「不存在或已下架」,与备品真下架无法区分 | 报 589522「备品库查询失败」,与 589519 分开 |
六.7、影响评估
- 需要前端配合的只有一条:保存人员配置必须带
staffList。经排查管理后台现有调用是带该字段的,理论上不受影响;但字段名一旦写错,改前是静默清空、改后是 400,属"报错优于静默毁数据"。 - 备品搜索语义变化只影响把
%/_当通配符用的用法,业务上没有这种用法。 - 加备品行的改动对调用方完全透明,契约与错误码不变,只是不再有隐性上限。
七、不影响范围
- 团期看板、详情、子订单、合同保险、财务、流团与退单等其余端点未改动。
- 备品清单的查询、改数量、删除、确认物资四个端点契约不变。
- 无表结构变更、无网关路由变更、无新增错误码(589519 / 589522 / 589523 / 582114 均为既有)。
八、测试环境已验证
真实网关(api.test.1814.love)逐条实测,dev-v3 分支已部署 hl-resource-service 与 hl-order-service-v3:
| 用例 | 结果 |
|---|---|
保存人员配置缺 staffList(模拟字段名写成 items) |
400「staff 配置列表不能缺失;确要清空请显式传空数组 []」 |
保存人员配置显式传 [] |
200,配置清空为 0 条 |
| GUIDE 类型的人配成 PHOTOGRAPHER | 582114,配置数仍为 0(零写入) |
| GUIDE 类型的人配成 GUIDE | 200,回显 staffId / staffName / staffPhone / staffRole 全字段 |
| 配完后看导游位候选 | assigned=true、assignedRole=GUIDE |
| 配完后看摄影位候选 | 该人不在候选内(勾选态按配置位收敛) |
备品候选 keyword=% / keyword=_ |
均返 0 条(改前返回全库 15 条) |
备品候选 keyword=帽 |
返 1 条「定制遮阳帽」 |
| 从备品库加行 | 200,库快照生效(billingType=PER_PERSON、hasCost=true、unitPrice=15.00) |
| 同一备品再加一次 | 589523,清单无重复行 |
| 三个写端点传不存在的 ID | 589500 / 589521 / 589553,一律零写入 |
单元测试:hl-order-service-v3 全量 9303 例、hl-resource-service 全量 2707 例,均 0 失败 0 错误。
九、相关历史 PR
- PR #7028(本次合入,含 2026-09-03 审计的 F-01 / F-02 / F-04 三项中危修复)
- 前序 #6950(团期人员配置候选列表)、#6986(团期物资备品库选择)
十、相关文档
- 审计记录:
dev-records/records/2026-09-03-local-group-tour-6950-6986-post-merge-audit.md - 实施单:
docs/group/实施单/07-人员-导游摄影司机.html、docs/group/实施单/10-物资清单.html
关联 / 联系人
- 工单:#7377(收口审计余项)、#7028(PR)
- 后端:jw
- 前端:mmg —— 只需确认保存人员配置时始终带
staffList字段