diff --git a/changelogs/2026-04/2026-04-17_fix_product-simple-list-500.md b/changelogs/2026-04/2026-04-17_fix_product-simple-list-500.md new file mode 100644 index 0000000..96b97e4 --- /dev/null +++ b/changelogs/2026-04/2026-04-17_fix_product-simple-list-500.md @@ -0,0 +1,161 @@ +# 修复 商品选择列表接口 500 错误 + +- **日期**: 2026-04-17 +- **服务**: hl-product-service-v2(端口 8083) +- **类型**: BUG 修复(非破坏性) +- **前端影响**: **无需改动** + +--- + +## 修复说明 + +### 现象 + +调用订单创建「选择商品」弹窗的商品列表接口时,**100% 返回 500**: + +```json +{ + "code": 500, + "message": "服务器内部错误", + "data": null, + "success": false +} +``` + +该接口一上线就无法使用,前端弹窗里产品列表始终为空。 + +### 根因 + +Mapper 使用 `selectAll(ProductDO.class)` 把 `ProductDO` 所有字段映射到 VO。其中: + +- 实体 `ProductDO.tiers` 是 **String 类型(存 JSON 字符串)** +- VO `ProductSimpleItemRespVO.tiers` 是 **`List`(结构化列表)** + +MyBatis-Plus Join 在构造 ResultMap 阶段发现同名字段类型不一致,抛 `IllegalStateException`,整个请求返回 500。 + +### 修复方式 + +Mapper 改为**显式 selectFields**,只映射基础字段;`tiers` 字段由 Service 层单独查 `ProductTierDO` 表并解析为结构化列表再塞回 VO。 + +对前端而言:**接口路径、请求参数、响应结构完全不变**,原来调不通的接口现在正常返回数据。 + +--- + +## 接口信息 + +### 请求 + +``` +GET /admin/product/item/simple-list +``` + +**Header**: + +``` +Authorization: Bearer {token} +tenant-id: {租户ID} +``` + +### 查询参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| productType | String | 否 | 产品类型(`CORE`=核心产品,`GROUP`=小蒙马),不传=全部 | +| keyword | String | 否 | 搜索关键词(匹配产品名称) | +| pageNo | Integer | 否 | 页码,默认 1 | +| pageSize | Integer | 否 | 每页条数,默认 50 | + +> 后端固定只返回**已上架**(status=PUBLISHED)的产品,前端不需要传 status。 + +### 响应字段 + +外层(`data`): + +| 字段 | 类型 | 说明 | +|------|------|------| +| records | Array | 产品列表 | +| total | Long | 总数 | + +`records` 数组中每一项: + +| 字段 | 类型 | 说明 | +|------|------|------| +| productId | Long | 产品ID(JSON 序列化为字符串防精度丢失) | +| productNo | String | 产品编号(如 `C260416002`) | +| name | String | 产品名称 | +| tripDays | Integer | 行程天数 | +| lineName | String | 所属产品线名称(LEFT JOIN 查出) | +| tiers | Array | 该产品的档位列表(可能为空数组) | + +`tiers` 数组中每一项(档位): + +| 字段 | 类型 | 说明 | +|------|------|------| +| tierSeq | Integer | 档位序号(1 开始) | +| tierName | String | 档位名称(如 `舒适`、`豪华`) | +| tierDescription | String | 档位描述,可能为空字符串 | + +--- + +## 完整请求示例 + +``` +GET /admin/product/item/simple-list?productType=CORE&pageNo=1&pageSize=20 +Authorization: Bearer eyJxxx... +tenant-id: 1 +``` + +## 完整响应示例 + +```json +{ + "code": 200, + "message": "成功", + "data": { + "records": [ + { + "productId": "2044704111294672897", + "productNo": "C260416002", + "name": "嗨冰雪3.0南线(6天5晚)", + "tripDays": 6, + "lineName": "嗨冰雪", + "tiers": [ + { "tierSeq": 1, "tierName": "舒适", "tierDescription": "" }, + { "tierSeq": 2, "tierName": "豪华", "tierDescription": "" } + ] + } + ], + "total": 5 + }, + "success": true +} +``` + +--- + +## 前端无需改动 + +> 🟢 **该修复纯属后端 Bug 修复,前端不需要任何调整。** +> +> - 接口路径:**不变** +> - 请求参数:**不变** +> - 响应字段结构:**不变** +> - 错误码/成功码:**不变** +> +> 此前调用此接口拿到 500 的地方,现在可以正常拿到数据;已经写好的调用代码无需修改。 + +如果之前前端为了"兼容 500"加过 try/catch 降级逻辑,可以保留,不会有副作用。 + +--- + +## 重启服务 + +- `hl-product-service-v2`(端口 8083) + +--- + +## 关联信息 + +- **Issue**: #745 +- **PR**: #746(已合并到 dev) +- **Commit**: `cfd901e5`