# 修复 商品选择列表接口 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<TierItem>`（结构化列表）**

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`
