# fix(product-v2): 产品列表状态中文化 + 上下架理由必填

> **服务**: hl-product-service-v2 (端口 8083)
> **PR**: #821
> **Issue**: #820
> **Merge commit**: `adc86652`
> **日期**: 2026-04-18
> **影响范围**: 管理端产品列表/详情状态展示 + 产品上架/下架接口

---

## 一、背景

本次修复两个 BUG：

### BUG-1：产品列表状态徽标出现英文 `PENDING_REVIEW`
- 产品版本卡片上，仅 `PENDING_REVIEW` 状态显示英文，其它状态（`PUBLISHED→已上架`、`DRAFT→草稿` 等）显示正常
- 根因：后端 `ProductListRespVO` / `ProductDetailRespVO` 只返状态 code（例：`PENDING_REVIEW`），前端本地字典遗漏该条目 → 降级显示裸英文
- 违反项目硬规则「所有展示数据用中文」

### BUG-2：产品上架/下架接口缺少"理由"必填校验
- 旧行为：`POST /admin/product/item/{id}/toggle-publish` 的 `remark` 字段可选，前端不传也能通过
- 风险：上下架是关键业务操作，没有理由 → 无法追溯审计，`product_operation_log` 里 `detail` 为空
- 现改为 **必填**，并在后端强制非空校验

---

## 二、变更接口清单

| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|---------|------|
| 1 | 产品列表 | GET | `/admin/product/item/list` | 响应新增字段 | 新增 `statusName: string`（中文名） |
| 2 | 产品详情 | GET | `/admin/product/item/{id}` | 响应新增字段 | 新增 `statusName: string`（中文名） |
| 3 | 产品上架/下架 | POST | `/admin/product/item/{id}/toggle-publish` | **破坏性变更** | Request body `remark` 由可选改为**必填** |

> ⚠️ `POST /admin/product/item/{id}/complete`（完成设计）接口**不在本次变更范围**，其 `remark` 字段**仍为可选**，前端无需改动。

---

## 三、接口详情

### 1. 产品列表 `GET /admin/product/item/list`

响应结构新增 `statusName` 字段：

```json
{
  "code": 0,
  "data": {
    "list": [
      {
        "id": 1001,
        "name": "xxx 亲子游",
        "status": "PENDING_REVIEW",
        "statusName": "待审核",
        "...": "其他字段不变"
      }
    ],
    "total": 10
  }
}
```

### 2. 产品详情 `GET /admin/product/item/{id}`

响应结构新增 `statusName` 字段（用法同上）：

```json
{
  "code": 0,
  "data": {
    "id": 1001,
    "status": "PUBLISHED",
    "statusName": "已上架",
    "...": "其他字段不变"
  }
}
```

### 3. 产品上架/下架 `POST /admin/product/item/{id}/toggle-publish`

**Request body**：

```json
{
  "remark": "根据市场部决议下架调整"
}
```

| 字段 | 类型 | 必填 | 说明 | 变化 |
|------|------|------|------|------|
| `remark` | String | **是** | 上架/下架理由（非空、非纯空白） | **由可选改为必填** |

**违反必填的错误响应**：

- 场景 A：body 完全为空 / 不传 body

```json
{
  "code": 400,
  "message": "请求数据格式错误，请检查参数是否正确"
}
```

- 场景 B：`remark` 为空字符串或纯空白

```json
{
  "code": 400,
  "message": "remark: 上架/下架操作必须填写理由"
}
```

---

## 四、状态枚举字典对照

`status` code 字段**保持不变**，前端仍可用其做逻辑判断。如需展示中文，**推荐直接读 `statusName`**；若坚持本地字典，请确保以下条目齐全：

| status (code) | statusName (中文) |
|---------------|------------------|
| `DRAFT` | 草稿 |
| `PENDING_REVIEW` | 待审核 |
| `PUBLISHED` | 已上架 |
| `UNPUBLISHED` | 已下架 |
| `REJECTED` | 已驳回 |
| `COMPLETED` | 已完成 |
| `ORDERED` | 已下单 |

---

## 五、前端必须配合

### 改动 1：列表/详情展示

- **推荐**：展示位直接读 `statusName`
- **或者**：保留本地字典，但必须补齐上表所有 7 个条目（特别是之前漏的 `PENDING_REVIEW`、`UNPUBLISHED`、`REJECTED`、`COMPLETED`、`ORDERED`）
- `status` 字段继续用于前端逻辑判断（按钮 disabled、tab 过滤等），**不要**用 `statusName` 做逻辑

### 改动 2：上架/下架弹框

- 点击「上架」/「下架」按钮时弹出对话框，包含**必填**的理由输入框（如 `<textarea>`）
- 前端本地校验：空字符串/纯空白禁止提交，给出友好提示
- 请求 body 结构：

```json
{ "remark": "用户输入的理由文本" }
```

### 兼容性警告

- 旧代码如直接调用 `toggle-publish` 不带 body / remark 为空 → 现在会被后端 400 拒绝
- 请同步检查所有调用 `toggle-publish` 的地方，确保都已加上理由输入 UI

---

## 六、未受影响接口（明确说明）

- `POST /admin/product/item/{id}/complete`（完成设计）：`remark` **仍可选**，与本次变更无关，**前端无需改动**
- 其他产品管理接口（创建、编辑、删除、审核等）零影响
- 小程序端接口零影响

---

## 七、重启提示

- **仅需重启** `hl-product-service-v2`（端口 8083）
- 测试环境由服务器管理员通过 Deploy Panel 部署最新 jar
- 本地由 Claude 手动重启

---

## 八、相关链接

- Issue: https://git.1814.love:8443/wx/HL/issues/820
- PR: https://git.1814.love:8443/wx/HL/pulls/821
- Merge commit: `adc86652`
