# 接口变更记录 — 2026-03-20（定价字段精简 + 保险校验）

> **类型** refactor + feature
>
> 定价配置精简（移除6个冗余字段）+ 保险方案天数校验 + 保险费自动回填

---

## 一、定价配置字段精简

### 1. 移除 `maxGroupSize`（最多成团人数）

**原因**：业务上只需要"成团人数"一个概念，不需要区分最少/最多。

**前端需要调整**：
- 定价规则页面：移除"最多成团"输入框，只保留"成团人数"（字段 `minGroupSize`）
- `minGroupSize` 语义变为"成团人数"，不再是"最少成团"

| 字段 | 变更 | 说明 |
|------|------|------|
| ~~`maxGroupSize`~~ | **已移除** | 请求和响应都不再有此字段 |
| `minGroupSize` | **含义变更** | 现在代表"成团人数"（原为"最少成团人数"） |

### 2. 移除4个未使用的价格体系字段

**原因**：这4个字段从未参与任何价格计算逻辑，只是存储和展示，属于冗余数据。

| 移除的字段 | 原含义 | 说明 |
|-----------|--------|------|
| ~~`singleRoomDiff`~~ | 单房差 | **已移除** |
| ~~`adultExtraBed`~~ | 成人加床 | **已移除** |
| ~~`childNoBed`~~ | 儿童不占床 | **已移除** |
| ~~`companionPrice`~~ | 陪同价 | **已移除** |

**保留的价格字段**（实际参与计算）：

| 字段 | 含义 | 说明 |
|------|------|------|
| `childWithBed` | 儿童占床价 | 保留，参与儿童价计算 |
| `childDiscountPercent` | 儿童折扣百分比 | 保留，参与儿童价计算 |
| `babyPrice` | 婴儿价 | 保留，参与婴儿价计算 |
| `insuranceFee` | 保险费 | 保留，参与成本计算 |
| `mealBudget` | 餐费预算 | 保留 |
| `extraCostPerPerson` | 每人额外成本 | 保留 |

### 受影响的接口

#### `POST` /admin/product/item/{productId}/pricing — 保存定价规则

**请求参数变更**：

| 字段 | 变更 |
|------|------|
| ~~`maxGroupSize`~~ | **已移除** |
| ~~`singleRoomDiff`~~ | **已移除** |
| ~~`adultExtraBed`~~ | **已移除** |
| ~~`childNoBed`~~ | **已移除** |
| ~~`companionPrice`~~ | **已移除** |

#### `GET` /admin/product/item/{productId}/pricing — 获取定价规则

**响应变更**：同上5个字段从响应中移除。

#### 小程序端 — 定制产品详情

`MpCustomProductDetailVO.PricingItem` 同步移除以上5个字段。

---

## 二、保险方案天数校验

### 功能说明

产品选择保险方案时，系统会校验保险方案的**适用行程天数**是否与产品**行程天数**一致。不一致时拒绝保存。

### 保险方案列表新增字段

#### `GET` /admin/insurance/scheme — 保险方案列表

响应新增字段：

| 字段 | 类型 | 说明 |
|------|------|------|
| `totalDays` | Integer | 适用行程天数（根据保障段自动计算） |

### 产品保存时校验逻辑

- 创建/编辑产品时，如果设置了 `insuranceSchemeId`，系统自动调用保险服务校验
- 如果保险方案的 `totalDays` 与产品行程天数不匹配，返回错误提示：`保险方案「{方案名}」适用{N}天行程，但本产品行程为{M}天，请选择匹配的方案`

---

## 三、保险费自动回填

### 功能说明

产品选择保险方案后，系统自动计算每人保险费并回填到定价配置的 `insuranceFee` 字段。

### 新增接口：保险费预览

#### `GET` /admin/product/item/{productId}/pricing/insurance-fee-preview

**用途**：前端选择保险方案时实时预览保险费，不保存。

**请求参数**：

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `schemeId` | Long | 是 | 保险方案ID |

**响应**：`Result<Map>`

```json
{
  "code": 200,
  "data": {
    "schemeId": "1234567890",
    "schemeName": "测试3日方案",
    "totalDays": 3,
    "tripDays": 3,
    "perPersonPremium": 45.00
  }
}
```

| 字段 | 类型 | 说明 |
|------|------|------|
| `schemeId` | String | 保险方案ID |
| `schemeName` | String | 方案名称 |
| `totalDays` | Integer | 方案适用天数 |
| `tripDays` | Integer | 产品行程天数 |
| `perPersonPremium` | BigDecimal | 每人保险费（元） |

**错误场景**：
- 产品不存在 → 404
- 保险服务不可用 → 500（"保险服务暂不可用"）
- 天数不匹配 → 400（提示不匹配原因）

### 自动回填逻辑

产品保存（创建/编辑）时：
1. 如果设置了 `insuranceSchemeId`，自动调用保险服务获取每人保险费
2. 校验天数匹配（不匹配则报错）
3. 自动将 `perPersonPremium` 写入 `ProductPricing.insuranceFee`
4. 前端定价页面的"保险费"字段会自动更新为计算值（仍可手动修改）

---

## 数据库变更

```sql
-- 1. 移除 maxGroupSize
ALTER TABLE product_pricing DROP COLUMN max_group_size;

-- 2. 保险方案新增 totalDays
ALTER TABLE insurance_scheme ADD COLUMN total_days INT DEFAULT NULL COMMENT '适用行程天数';

-- 3. 移除4个未使用的定价字段
ALTER TABLE product_pricing DROP COLUMN single_room_diff;
ALTER TABLE product_pricing DROP COLUMN adult_extra_bed;
ALTER TABLE product_pricing DROP COLUMN child_no_bed;
ALTER TABLE product_pricing DROP COLUMN companion_price;
```

已在本地和测试环境执行完毕。
