# 班期保存 - 最大参与人数 改为非必填（反转 2026-04-18 上一版 changelog）

**日期**: 2026-04-18
**PR**: #865 → 合并到 dev，已部署测试环境
**Issue**: #862
**影响端**: 管理后台 Web (hl-ui-admin)
**影响接口**:
- `POST /admin/product/item/{id}/schedule` (Step4 创建班期)
- `PUT /admin/product/item/{id}/schedule` (Step4 修改班期)
- `POST /admin/product/item/{id}/schedule/batch-create` (Step4 班期批量创建)

## ⚠️ 反转上一版
本 changelog 反转 `2026-04-18_product-v2_schedule-max-participants-required.md`（PR #861）。产品侧确认：**班期定价页的"最大人数"按用户交互本意就是非必填**（不填=不限）。上一版把 `@NotNull` 补强的方向是错的，本次撤回。

## 行为变化

| 字段 | 前端是否必填 | 不传时后端行为 | 说明 |
|---|---|---|---|
| `maxParticipants`（最大人数）| **否** | 兜底写 DB 为 `0`（0=不限） | 报名/库存校验对 `0=不限` 不再恒拒 |
| `maxRooms`（最大房间数）| **否，前端不传** | 后端自动取 `product_basic.default_room_count`（每天最少房间数，行程 Step2 自动算好）；无 default 则 0=不限 | 行为无变化，本次明确文档化 |
| `productStockLimit`（库存上限）| **否** | 写 DB `NULL`（不限） | 行为无变化，本次明确文档化 |

三者前端表单均**不要标红星**，不要做 required 校验。

## 请求体示例（最小体）

```json
POST /admin/product/item/{id}/schedule
{
  "departureDate": "2027-06-01",
  "adultPrice": 2999.00,
  "childPrice": 1999.00
}
```

上面请求合法返回 200，DB 存 `max_participants=0 / max_rooms=<default_room_count 或 0> / product_stock_limit=NULL`。

## 下游接口（/internal/batch-info）联动

`InternalProductService.getBatchInfo` 回传字段 `remainingSlots`：
- 当班期 `maxParticipants <= 0`（不限）：`remainingSlots = Integer.MAX_VALUE`（2147483647）
- 否则：`remainingSlots = maxParticipants - enrolledCount`

下游（订单服务）若展示"剩余名额"，建议判断 `>= Integer.MAX_VALUE` 时显示"不限"而非具体数字。

## DB DDL（已在测试环境应用）

```sql
ALTER TABLE group_tour_batch
  MODIFY COLUMN max_participants INT(11) NOT NULL DEFAULT 0
  COMMENT '最大参与人数(0=不限)';
```

## 不影响

- 字段名、字段类型不变
- `ScheduleRespVO` / `MpScheduleRespVO` 返回结构不变
- 其他字段校验规则不变
- 订单名额扣减逻辑：`maxParticipants > 0` 时仍按原逻辑控卡

🤖 Generated with [Claude Code](https://claude.com/claude-code)
