frontend_status pending→verified,frontend_ref=08d13de33b27948c31cb1e511ad59f342420e88c, verified_at=2026-09-18,status_note 追加实现摘要。
15 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 | 7916 | 团期物资列表与候选列表出参新增分类中文名 categoryName(字典外取值按原值显示) | admin | jw(GIT) | 修改接口 | deployed | verified | verified | mmg | 08d13de33b27948c31cb1e511ad59f342420e88c | 2026-09-18 | 团期物资列表 GET /v3/admin/order/group-batch/{groupBatchId}/supplies 与候选列表 .../supplies/candidates 出参各纯新增一个 categoryName;既有 category 原值一字不改,入参与错误码零变化。翻译三段回落:命中字典 supplies_category 的码译中文;值本身已是中文原样返回;字典外取值(TEST 存量的 EQUIPMENT / PROTECTION,共 140 行)按原值显示,不编造也不置空。字典 Feign 不可达时整批回落原值且接口仍 200(TEST 实测注入过)。后端已合并 dev-v3 并部署 TEST。[mmg 2026-09-18 已实现并验证] SuppliesPanel/SuppliesPickerModal 分类列由自查字典(getDictLabel||code)改显后端 categoryName(categoryName||category||'—'),SuppliesPanel 随删闲置 dictStore;筛选仍传 categoryCode 码、提交仍用 category 原值,categoryName 仅展示不分组不回传;SuppliesPanel.spec 加 categoryName 优先/回落断言,定向 7/7+checkpoint 全绿。 | 2026-09-18 | dev-v3 |
团期物资: 列表与候选列表出参新增分类中文名 categoryName
服务: hl-order-service-v3 (端口 8086) PR: #7920 Issue: #7916 日期: 2026-09-18 影响范围: 管理后台团期详情「物资清单」与「从备品库选择」候选弹窗的分类列
⚠️ 关键变化
- 本次两个接口的出参各纯新增一个
categoryName,既有category原值一字不改。 - 前端以前可能以为:拿到
category自己查字典supplies_category就能译出中文。这个做法译不出线上多数行——TEST 实测order_batch_supplies.category存量 442 行里有 140 行是字典里根本没有的EQUIPMENT/PROTECTION,另有 301 行存的本来就是中文。 - 实际现在是:后端按三段回落给出
categoryName,字典外的取值原样回传(显示出来仍是EQUIPMENT),不是后端漏译,是该列的存量脏值,归一另列工单。
一、背景
order_batch_supplies.category 是下单时固化的快照,写入来源有三个且口径各异(产品备品中文与大写码混杂、备品库基本是字典码、管理员手工新增无校验),因此同一列并存三套词表。
| 维度 | TEST 实测(2026-09-18,hl_order_service_v3) |
|---|---|
中文标签(如 个人装备) |
301 行 |
字典码(如 safety_protection) |
1 行 |
字典外大写码 EQUIPMENT |
70 行 |
字典外大写码 PROTECTION |
70 行 |
字典 supplies_category 取值 |
8 项,全是小写码,无 EQUIPMENT / PROTECTION |
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 查询团期备品列表 | GET | /v3/admin/order/group-batch/{groupBatchId}/supplies |
出参新增字段 | 每行新增 categoryName,category 不变 |
| 2 | 团期物资候选列表 | GET | /v3/admin/order/group-batch/{groupBatchId}/supplies/candidates |
出参新增字段 | 每项新增 categoryName,与列表同一套翻译规则 |
三、接口详情
1. 查询团期备品列表 GET /v3/admin/order/group-batch/{groupBatchId}/supplies
VO: GroupBatchSuppliesRespVO
使用场景
管理后台团期详情页「物资清单」区域加载已固化/已手工追加的备品行;分类列改为显示 categoryName,排序、筛选、提交仍用 category 原值。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | 雪花 ID | 团期主订单 ID |
出参 Result<List<GroupBatchSuppliesRespVO>>
| 字段 | 类型 | 说明 |
|---|---|---|
| id | String | 备品行 ID(19 位雪花,字符串输出) |
| groupBatchId | String | 团期 ID |
| suppliesName | String | 备品名称 |
| category | String | 分类原值(本次不变):可能是字典码、中文标签或字典外取值,可为 null |
| categoryName | String | 本次新增:分类展示名;category 为 null/空白时为 null |
| hasCost | Boolean | 是否计费 |
| billingType | String | 计费方式 PER_PERSON / PER_QUANTITY |
| unitPrice | String | 单价 |
| quantity | Integer | 数量 |
| sortOrder | Integer | 排序号 |
| remark | String | 备注 |
请求示例
GET /v3/admin/order/group-batch/2100509904627191810/supplies
Authorization: Bearer {admin-jwt}
响应示例
{
"code": 200,
"message": "成功",
"data": [
{ "id": "2100509905000000001", "suppliesName": "团队识别手环1", "category": "个人装备", "categoryName": "个人装备", "quantity": 1 },
{ "id": "2100509905000000002", "suppliesName": "户外急救箱", "category": "safety_protection", "categoryName": "安全防护", "quantity": 1 }
],
"success": true
}
空数据 / 降级响应
{ "code": 200, "message": "成功", "data": [], "success": true }
字典服务不可达时不降级整个接口,只是 categoryName 全批等于 category:
{
"code": 200,
"message": "成功",
"data": [
{ "id": "2100509905000000002", "suppliesName": "户外急救箱", "category": "safety_protection", "categoryName": "safety_protection" }
],
"success": true
}
错误响应
{
"code": 589500,
"message": "团期不存在",
"data": null,
"success": false
}
业务边界
- 鉴权:管理后台 JWT + 团期查看权限(
GroupBatchPermissionGuardVIEW),未登录 401。 category为 null 或纯空白 →categoryName为 null,不是空串、不是字符串 "null"。category命中字典 → 中文标签;已是中文标签 → 原样返回;字典外取值 → 原样返回,后端不编造分类。- 只读接口,天然幂等;整页只加载一次字典,不按行调用。
2. 团期物资候选列表 GET /v3/admin/order/group-batch/{groupBatchId}/supplies/candidates
VO: SuppliesCandidateRespVO
使用场景
管理后台团期物资「从备品库选择」弹窗,列出资源域备品库中上架未软删的备品,并标出哪些已加入本团清单;分类列同样改用 categoryName。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | 雪花 ID | 团期主订单 ID |
| categoryCode | Query | String | ❌ | 字典 supplies_category 的值 |
按分类筛选,筛选仍用码,不用中文名 |
| keyword | Query | String | ❌ | - | 匹配名称或副标题 |
出参 Result<List<SuppliesCandidateRespVO>>
| 字段 | 类型 | 说明 |
|---|---|---|
| suppliesId | String | 备品库 ID |
| suppliesName | String | 备品名称 |
| subtitle | String | 副标题 |
| category | String | 分类码原值(本次不变),来自备品库 category_code |
| categoryName | String | 本次新增:分类展示名,规则与列表接口完全一致 |
| billingType | String | 计费方式(已归一为 PER_PERSON / PER_QUANTITY) |
| hasCost | Boolean | 是否计费 |
| unitPrice | String | 单价 |
| selected | Boolean | 是否已加入本团清单 |
请求示例
GET /v3/admin/order/group-batch/2099919772194836482/supplies/candidates?categoryCode=camping_equipment
Authorization: Bearer {admin-jwt}
响应示例
{
"code": 200,
"message": "成功",
"data": [
{ "suppliesId": "2074063318837792770", "suppliesName": "折叠桌椅套装", "category": "camping_equipment", "categoryName": "露营设备" },
{ "suppliesId": "2074063318837792771", "suppliesName": "对讲机", "category": "electronics", "categoryName": "电子设备" }
],
"success": true
}
空数据 / 降级响应
资源域备品库不可达或无候选时返回空数组,不 500:
{ "code": 200, "message": "成功", "data": [], "success": true }
错误响应
{
"code": 589500,
"message": "团期不存在",
"data": null,
"success": false
}
业务边界
- 鉴权同列表接口(VIEW 权限)。
categoryCode筛选只认字典码,传中文名筛不出结果。- 备品库里存在字典外的
category_code(TEST 现存 1 条TENT,已下架)→categoryName回传TENT。 - 只读接口,整页只加载一次字典。
四、契约约束与正确调用方式(接口类必写)
本节只写后端返回值的契约,不写 UI 渲染建议。
| 场景 | category |
categoryName |
|---|---|---|
| ✅ 字典码 | safety_protection |
安全防护 |
| ✅ 存量中文 | 个人装备 |
个人装备 |
| ✅ 字典外取值 | EQUIPMENT |
EQUIPMENT(原值,非空、非 null) |
| ✅ 空分类 | null |
null |
| ✅ 字典不可达 | safety_protection |
safety_protection(整批回落) |
调用方必须注意
- 写入与筛选一律用
category/categoryCode原值,categoryName只用于展示,不要拿它回传给任何写接口。 - 不要假设
categoryName一定是中文:字典外取值原样回传,这是刻意的(编造分类比显示英文码更有害)。 - 不要用
categoryName做分组键:同一分类可能因存量三套词表而出现个人装备与personal_gear两个不同的category,却都展示成「个人装备」。分组仍应按category。
五、数据库行为
零变更:本次无 Flyway 迁移,不新增/修改任何表与列。categoryName 是读取时按数据字典翻译出来的派生展示字段,不落库;order_batch_supplies.category 只读不写,存量脏值不回填。
六、边界行为
- 未登录 → 401(网关拦截)
- 无团期查看权限 → 权限守卫拒绝
- 团期不存在 → 589500
- 字典服务降级 →
categoryName全批等于category,接口仍 200,不阻断页面 - 老数据兼容 →
category为 null 的历史行 →categoryName为 null,不异常
六.5、枚举 / 数据字典
categoryName 的取值来源(数据字典 supplies_category)
所属字段: GroupBatchSuppliesRespVO.categoryName / SuppliesCandidateRespVO.categoryName | 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
personal_gear |
个人装备 | 字典项 |
camping_equipment |
露营设备 | 字典项 |
riding_gear |
骑行装备 | 字典项 |
electronics |
电子设备 | 字典项 |
safety_protection |
安全防护 | 字典项 |
entertainment |
娱乐器材 | 字典项 |
warmth_gear |
保暖装备 | 字典项 |
vehicle_accessories |
车载装备 | 字典项 |
EQUIPMENT / PROTECTION / TENT |
(无) | 不在字典内的存量取值,原样回传 |
六.6、修改前后对比
字段级对比
| 字段 | 改前 | 改后 |
|---|---|---|
GroupBatchSuppliesRespVO.category |
分类原值 | 不变 |
GroupBatchSuppliesRespVO.categoryName |
不存在 | 新增,三段回落的展示名,可为 null |
SuppliesCandidateRespVO.category |
分类码原值 | 不变 |
SuppliesCandidateRespVO.categoryName |
不存在 | 新增,同一套规则 |
行为级对比
| 行为 | 改前 | 改后 |
|---|---|---|
| 前端显示分类中文 | 需自查字典,且线上多数行查不到 | 直接用 categoryName |
| 字典服务不可达 | 与本字段无关 | 接口仍 200,categoryName 整批等于 category |
| 字典查询次数 | — | 每次请求整页一次,不按行调用 |
| 入参 / 错误码 | — | 零变化 |
六.7、影响评估
- 是否破坏向后兼容: 否(纯新增出参字段,既有字段与错误码零变化)
- 前端是否必须同步上线: 否(不接入则与现状一致)
- 前端 workaround 清理点: 前端若已有「按
category自查字典译中文」的逻辑,可改用categoryName;但不要顺手把字典外取值改成显示空白,那是存量脏值,另有工单归一。
七、不影响范围
- 仅影响: 管理后台团期物资清单、团期物资候选弹窗两个只读接口的出参
- 零影响:
- 小程序端备品清单与其分组接口(本次未改)
- 物资新增 / 改数量 / 软删 / 确认物资等写接口(取值域未收紧,手工新增仍可自由填)
- 终止退款链路取备品行的内部调用(刻意不走翻译,避免在写事务内发跨服务字典调用)
- 数据库(零 Flyway、存量不回填)
八、测试环境已验证
部署:dev-v3@a18569162(合并 PR #7920 后)部署至 TEST,hl-order-service-v3 双实例滚动完成。
GET /v3/admin/order/group-batch/2100509904627191810/supplies
→ 200;category=个人装备 → categoryName=个人装备 ✓(存量中文原样)
→ 200;category=safety_protection → categoryName=安全防护 ✓(字典码译中文)
GET /v3/admin/order/group-batch/2099463556951941122/supplies
→ 200;category=EQUIPMENT → categoryName=EQUIPMENT ✓(字典外原值)
→ 200;category=PROTECTION → categoryName=PROTECTION ✓
GET /v3/admin/order/group-batch/2099919772194836482/supplies/candidates
→ 200;15 项全部带 categoryName,personal_gear→个人装备、camping_equipment→露营设备 ✓
category 为空的行(临时夹具,取证后已删)
→ 200;category=null → categoryName=null ✓(非空串、非 "null")
字典不可达注入(临时改 sys_dict_type.dict_type 使 supplies_category 查不到,重启后冷缓存)
→ 列表 200;safety_protection → safety_protection ✓(整批回落原值)
→ 候选 200;personal_gear → personal_gear、camping_equipment → camping_equipment ✓
→ 还原字典后翻译恢复 ✓
验证团期: 2100509904627191810(三段全覆盖)、2099463556951941122(字典外取值)、2099919772194836482(候选列表)
十、相关文档
- 关联 Issue: wx/HL#7916
- 关联 PR: wx/HL#7920
- 同类先例(子订单
roomTypeName): 见changelogs-v2/2026-09/14_7536_*
关联 / 联系人
链接
联系人
- 后端负责人: @jw