docs(changelog): #7916 团期物资列表与候选补分类中文名 categoryName(修改接口)
changelog-filename-gate / validate (push) Failing after 2s
changelog-filename-gate / validate (push) Failing after 2s
这个提交包含在:
@@ -0,0 +1,370 @@
|
||||
---
|
||||
schema: "hl-changelog/v2"
|
||||
ticket: "7916"
|
||||
title: "团期物资列表与候选列表出参新增分类中文名 categoryName(字典外取值按原值显示)"
|
||||
consumer: "admin"
|
||||
author: "jw(GIT)"
|
||||
change_type: "修改接口"
|
||||
backend_status: "deployed"
|
||||
gateway_status: "verified"
|
||||
frontend_status: "pending"
|
||||
frontend_owner: "mmg"
|
||||
frontend_ref: ""
|
||||
target_release: ""
|
||||
verified_at: ""
|
||||
status_note: "团期物资列表 GET /v3/admin/order/group-batch/{groupBatchId}/supplies 与候选列表 .../supplies/candidates 出参各纯新增一个 categoryName;既有 category 原值一字不改,入参与错误码零变化。翻译三段回落:命中字典 supplies_category 的码译中文;值本身已是中文原样返回;字典外取值(TEST 存量的 EQUIPMENT / PROTECTION,共 140 行)按原值显示,不编造也不置空。字典 Feign 不可达时整批回落原值且接口仍 200(TEST 实测注入过)。后端已合并 dev-v3 并部署 TEST。"
|
||||
updated_at: "2026-09-18"
|
||||
base: "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 | 备注 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```http
|
||||
GET /v3/admin/order/group-batch/2100509904627191810/supplies
|
||||
Authorization: Bearer {admin-jwt}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": [
|
||||
{ "id": "2100509905000000001", "suppliesName": "团队识别手环1", "category": "个人装备", "categoryName": "个人装备", "quantity": 1 },
|
||||
{ "id": "2100509905000000002", "suppliesName": "户外急救箱", "category": "safety_protection", "categoryName": "安全防护", "quantity": 1 }
|
||||
],
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
```json
|
||||
{ "code": 200, "message": "成功", "data": [], "success": true }
|
||||
```
|
||||
|
||||
字典服务不可达时**不降级整个接口**,只是 `categoryName` 全批等于 `category`:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": [
|
||||
{ "id": "2100509905000000002", "suppliesName": "户外急救箱", "category": "safety_protection", "categoryName": "safety_protection" }
|
||||
],
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 589500,
|
||||
"message": "团期不存在",
|
||||
"data": null,
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 鉴权:管理后台 JWT + 团期查看权限(`GroupBatchPermissionGuard` VIEW),未登录 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 | 是否已加入本团清单 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```http
|
||||
GET /v3/admin/order/group-batch/2099919772194836482/supplies/candidates?categoryCode=camping_equipment
|
||||
Authorization: Bearer {admin-jwt}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": [
|
||||
{ "suppliesId": "2074063318837792770", "suppliesName": "折叠桌椅套装", "category": "camping_equipment", "categoryName": "露营设备" },
|
||||
{ "suppliesId": "2074063318837792771", "suppliesName": "对讲机", "category": "electronics", "categoryName": "电子设备" }
|
||||
],
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
资源域备品库不可达或无候选时返回空数组,不 500:
|
||||
|
||||
```json
|
||||
{ "code": 200, "message": "成功", "data": [], "success": true }
|
||||
```
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{
|
||||
"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](https://git.1814.love:8443/wx/HL/issues/7916)
|
||||
- 关联 PR: [wx/HL#7920](https://git.1814.love:8443/wx/HL/pulls/7920)
|
||||
- 同类先例(子订单 `roomTypeName`): 见 `changelogs-v2/2026-09/14_7536_*`
|
||||
|
||||
## 关联 / 联系人
|
||||
|
||||
### 链接
|
||||
|
||||
- **Issue**: [#7916](https://git.1814.love:8443/wx/HL/issues/7916)
|
||||
- **PR**: [#7920](https://git.1814.love:8443/wx/HL/pulls/7920)
|
||||
- **Merge commit**: [a18569162](https://git.1814.love:8443/wx/HL/commit/a18569162cb97e54b63f6b442e75292db4ad88d7)
|
||||
|
||||
### 联系人
|
||||
|
||||
- **后端负责人**: @jw
|
||||
在新工单中引用
屏蔽一个用户