# 产品上架放宽校验 + 已上架可独立管理团期/团队

**日期**: 2026-05-07
**类型**: 后端 API 增强 + 前端调整建议
**模块**: 产品（hl-product-service-v2）
**通知**: @mmg
**关联工单**: #1775
**关联 PR**: #1779 + #1781（hotfix）

---

## 业务变更

用户翻盘业务规则：**产品（尤其 GROUP/小蒙马）上架时不再硬校验团队/团期，可以「先上架后补」**。已上架（PUBLISHED）后通过现有/新增独立接口管理班期和团队成员。

---

## 后端改动

### 1. 上架校验放宽（`POST /admin/product/item/{id}/toggle-publish`）

GROUP 产品上架时**不再强校验**:
- ~~至少 1 个班期~~（已删除）
- ~~每个班期至少 1 个 LEADER 角色成员~~（已删除）
- ~~至少 1 个未来出发、成人价 > 0 的班期~~（已删除）

**保留校验**:
- 基础字段（名称/天数/封面/标签）
- 行程完整性（至少 1 天）
- 餐饮配置
- CORE/CUSTOM 价格日历未来有效价 ≥ 1（GROUP 不要求）

### 2. 已上架可独立管理班期

**`POST /admin/product/item/{id}/schedule`** — saveSchedule
- 新增/修改单个班期
- **PUBLISHED 状态可调用**（之前会被 checkEditable 拒）
- 调用成功后产品 `priceVersion++` 并触发 mp 缓存失效

**`POST /admin/product/item/{id}/schedule/batch-create`** — batchCreateSchedule
- 按重复模式批量生成班期（≤52个）
- **PUBLISHED 状态可调用**
- 整批调用 priceVersion 只 +1（不会膨胀）

**`DELETE /admin/product/item/{id}/schedule/{scheduleId}`** — deleteSchedule
- 删除班期
- **PUBLISHED 状态可调用**
- 已有报名订单的班期仍拒删（业务保护，返回剩余订单数）
- 删除后 `priceVersion++` 触发缓存失效

### 3. 已上架可独立管理团队（**新增独立接口**）

**`POST /admin/product/item/{id}/schedule/team`** — saveScheduleTeam ⭐ 本次新增
- request body 同既有 `ScheduleTeamSaveReqVO`：
  ```json
  {
    "productId": "<id>",
    "batchId": "<batchId>",
    "staffList": [
      {"staffId": "<staffId>", "staffRole": "LEADER", "staffName": "...", "staffPhone": "...", "sortOrder": 1}
    ]
  }
  ```
- 全删全插策略：传完整列表覆盖该 batchId 的全部成员
- **PUBLISHED 状态可直接调用**（绕过 supplement 接口的整体 checkEditable 拦截）
- staffId / staffRole / staffName / staffPhone 这些字段如果数据库 NOT NULL 必传

> 之前: 团队只能通过 `PUT /supplement` 嵌套保存，但 supplement 接口 PUBLISHED 整体被拒
> 现在: 独立 `POST /schedule/team` 直调 saveTeam，不受 supplement 状态拦截影响
> 与既有 `GET /schedule/team` 路径对称

### 4. 缓存一致性

修改班期/团队后通过 `registerAfterCommit('product' source)` 触发 D3 反向缓存失效，mp 端详情/列表/起步价自动同步（≤ 几秒）。

---

## 前端调整建议（@mmg）

### 1. 「上架向导第 4 步 → 补充信息 → 团队配置」

当前页面对每个班期显示「N 人已配」+ 必填校验「至少 1 个领队」。

**建议调整**:
- 去掉「至少 1 个领队」的必填星号 + 提交拦截
- 可保留业务建议文案（如「建议每期配置 1 个领队，确保订单详情显示完整」），但**不阻塞上架**
- 前端「上架」按钮在团队/团期为空时不再 disable 或弹错误提示

### 2. 「已上架后管理团期/团队」入口（**新交互**）

业务诉求：用户希望产品上架后能独立加新团期、补领队等。

**建议交互**（仅供参考，最终方案 mmg 决定）:
- 在产品列表「已上架」状态的产品行加「管理团期/团队」入口（侧边栏 / 浮层 / 跳转新页面均可）
- 已上架产品调用以下接口（参数 / response 与上架前一致）:
  - 加新团期: `POST /admin/product/item/{id}/schedule`
  - 删团期: `DELETE /admin/product/item/{id}/schedule/{scheduleId}`
  - 改团队: `POST /admin/product/item/{id}/schedule/team` ⭐ 新接口
- **不再需要先把产品下架再修改**

---

## round-trip 验收（已通过）

测试服 9443 网关 + admin / Admin@123456 token 实测:

| 验收项 | 接口 | 结果 |
|---|---|---|
| GROUP DRAFT toggle-publish message 不再含「班期/LEADER/领队」字样 | POST `/admin/product/item/{id}/toggle-publish` | ✅ message="行程未完整填写..." 不含班期相关字样 |
| PUBLISHED 加新班期 | POST `/admin/product/item/{id}/schedule` | ✅ code:200, batchId 落库 |
| PUBLISHED 删班期 | DELETE `/admin/product/item/{id}/schedule/{batchId}` | ✅ code:200 msg=班期删除成功 |
| PUBLISHED 调独立 saveTeam | POST `/admin/product/item/{id}/schedule/team` | ✅ code:200 msg=团队保存成功 |

---

## 风险与兼容性

- **订单价格 snapshot 模式不变**：已下单订单不受班期价格变化影响
- **既有 `PUT /admin/product/item/{id}/supplement` 接口不变**：仍可在草稿态批量保存团队（DRAFT/REJECTED/UNPUBLISHED 流程不受影响）
- **新接口与 GET 同路径不冲突**：`GET /schedule/team` (查询) + `POST /schedule/team` (保存) 共存
