hl-api-changelog/changelogs/2026-04/2026-04-13_product-v2_create-merge-and-pricing-guide.md
API Changelog Bot c61ba75a47 docs: 补充后端与前端名词对照(产品线=主题,产品=版本,档位=规格)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 09:54:51 +08:00

258 行
7.2 KiB
Markdown

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

# 接口变更记录 — 2026-04-13
> **变更类型**:接口合并 + 定价模型说明
> **在线文档**
> - 局域网http://192.168.100.236:8080/doc.html → `1. 管理端 - 产品管理`
> - 公网https://api.test.1814.love:9443/doc.html需认证
---
## 一、创建产品和Step1基础信息合并为一个接口
### 旧接口(已删除)
| 接口 | 说明 |
|------|------|
| ~~POST /admin/product/item~~ | ~~独立创建接口,已删除~~ |
| ~~PUT /admin/product/item/{id}/basic~~ | ~~独立Step1保存,已删除~~ |
### 新接口
**`POST /admin/product/item/basic`** — 创建+更新合一
- **productId 不传** = 创建新产品(草稿),返回新 productId
- **productId 传了** = 更新已有产品,返回原 productId
### 创建时请求示例productId不传
```json
{
"productType": "CORE",
"name": "额吉的故乡·亲子版",
"tripDays": 6,
"lineId": 100,
"coverImageUrl": "https://...",
"seasons": ["summer"],
"tags": ["亲子"]
}
```
- `productType` **创建时必传**CORE/GROUP/CUSTOM
- `version` **创建时不传**
- 其他字段可选,创建时可以只传最少信息,也可以一次性填完全部
### 更新时请求示例productId传已有ID
```json
{
"productId": 2043246204711550977,
"version": 0,
"name": "额吉的故乡·亲子版(修改)",
"tripDays": 6,
"lineId": 100,
"coverImageUrl": "https://...",
"seasons": ["summer", "autumn"],
"tags": ["亲子", "研学"],
"tiers": [
{"tierSeq": 1, "tierName": "舒适"},
{"tierSeq": 2, "tierName": "豪华"}
]
}
```
- `version` **更新时必传**(从详情接口获取,乐观锁校验)
- `productType` 更新时传了也会被忽略(创建后不可改)
### 响应
```json
{
"code": 200,
"message": "成功",
"data": 2043246204711550977
}
```
返回 `Long` 类型的产品ID创建时是新ID,更新时是原ID
---
## 二、定价模型:哪种产品用哪个接口
### 核心规则
| 产品类型 | 定价模型 | 用户选什么 | 用哪组接口 |
|---------|---------|-----------|-----------|
| **CORE**(核心产品) | 价格日历 | 用户从日历选出发日期 | `price-calendar` 系列 |
| **CUSTOM**(私人定制) | 价格日历 | 同上 | `price-calendar` 系列 |
| **GROUP**(小蒙马) | 班期制 | 用户从班期列表选第N期 | `schedule` 系列 |
### 前端判断逻辑
```
if (productType === 'CORE' || productType === 'CUSTOM') {
// Step4 显示【价格日历】界面
// 用 price-calendar 系列接口
} else if (productType === 'GROUP') {
// Step4 显示【班期管理】界面
// 用 schedule 系列接口
}
```
### 价格日历接口CORE / CUSTOM 产品用)
| 场景 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 查询价格日历 | GET | `/admin/product/item/{id}/price-calendar?month=2026-07&tierSeq=1` | 按月+档位查询 |
| 批量设置价格 | POST | `/admin/product/item/{id}/price-calendar/batch` | 按日期范围设价 |
| 删除价格区间 | DELETE | `/admin/product/item/{id}/price-calendar` | 按日期范围删除 |
**批量设置请求示例**
```json
{
"productId": 123,
"version": 3,
"startDate": "2026-07-01",
"endDate": "2026-07-31",
"tierSeq": 1,
"priceType": "PEAK",
"adultSellPrice": 4980,
"childSellPrice": 3980,
"toddlerDiscount": -500,
"infantPrice": 0,
"dailyStock": 10
}
```
**价格日历查询响应**
```json
[
{
"id": 1,
"productId": 123,
"tierSeq": 1,
"date": "2026-07-01",
"priceType": "PEAK",
"adultSellPrice": 4980,
"childSellPrice": 3980,
"toddlerDiscount": -500,
"infantPrice": 0,
"dailyStock": 10,
"sold": 2
}
]
```
### 班期接口GROUP 小蒙马产品用)
| 场景 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 班期列表 | GET | `/admin/product/item/{id}/schedule/list` | 返回全部班期 |
| 创建班期 | POST | `/admin/product/item/{id}/schedule` | 不传batchId |
| 修改班期 | PUT | `/admin/product/item/{id}/schedule` | 传batchId |
| 删除班期 | DELETE | `/admin/product/item/{id}/schedule/{scheduleId}` | 有订单不可删 |
| 取消班期 | POST | `/admin/product/item/{id}/schedule/{scheduleId}/cancel` | 触发退款 |
| 批量创建 | POST | `/admin/product/item/{id}/schedule/batch-create` | 按重复模式 |
| 班期团队查询 | GET | `/admin/product/item/{id}/schedule/team?batchId=xxx` | 团队成员 |
| 班期团队保存 | PUT | `/admin/product/item/{id}/schedule/team?batchId=xxx` | 全量替换 |
**创建班期请求示例**
```json
{
"productId": 123,
"batchName": "第1期",
"departureDate": "2026-07-01",
"enrollmentDeadline": "2026-06-30",
"adultPrice": 4980,
"childPrice": 3980,
"toddlerDiscount": -500,
"infantPrice": 0,
"maxParticipants": 20,
"maxRooms": 10,
"productStockLimit": 20
}
```
**班期列表响应**
```json
[
{
"batchId": 456,
"productId": 123,
"batchNo": "B20260701001",
"batchName": "第1期",
"departureDate": "2026-07-01",
"endDate": "2026-07-06",
"enrollmentDeadline": "2026-06-30",
"adultPrice": 4980,
"childPrice": 3980,
"toddlerDiscount": -500,
"infantPrice": 0,
"maxParticipants": 20,
"enrolledCount": 8,
"maxRooms": 10,
"bookedRooms": 4,
"productStockLimit": 20,
"batchStatus": "ENROLLING",
"version": 0
}
]
```
**批量创建班期请求示例**
```json
{
"productId": 123,
"startDate": "2026-07-01",
"endDate": "2026-09-30",
"repeatMode": "WEEKLY",
"dayOfWeek": 1,
"adultPrice": 4980,
"childPrice": 3980,
"maxParticipants": 20,
"maxRooms": 10
}
```
### 价格日历 vs 班期对比
| 维度 | 价格日历CORE/CUSTOM | 班期GROUP |
|------|----------------------|-------------|
| 定价粒度 | 每天独立价格 | 每期一个固定价格 |
| 库存 | 按天dailyStock=每天可接几单) | 按期maxParticipants=总人数+maxRooms=总房间数) |
| 档位 | 支持多档tierSeq区分 | 单一档位 |
| 用户选择 | C端日历选日期 | C端列表选第N期 |
| 团队配置 | 无 | 每期可配领队/摄影师等 |
| 价格类型 | 平日/旺季/节假日/特价(颜色区分) | 无(每期统一价) |
### 班期状态说明
| 状态 | 中文 | 说明 |
|------|------|------|
| ENROLLING | 报名中 | 正常接受报名 |
| NEARLY_FULL | 即将满员 | 剩余房间≤阈值默认2间 |
| FULL | 已满 | 剩余房间=0 |
| FINISHED | 已结束 | 出发日期已过 |
| CANCELLING | 取消中 | 有订单,退款处理中 |
| CANCELLED | 已取消 | 取消完成 |
---
## 三、后端与前端名词对照
| 后端术语 | 后端字段 | 前端术语 | 说明 |
|---------|---------|---------|------|
| 产品线 | lineId / lineName | **主题** | 如"额吉的故乡""草原环线" |
| 产品 | productId / name | **版本** | 如"亲子版""旷野版""舒适版" |
| 档位 | tierSeq / tierName / tierCount | **规格** | 如"舒适""豪华",tierCount=规格数量 |
**前端展示映射**
- 主题列表 → 调 `/admin/product/line/list`
- 版本列表 → 调 `/admin/product/item/list`tierCount=该版本有几个规格)
- 规格详情 → 在产品详情的 `tiers` 字段中(`[{tierSeq:1, tierName:"舒适"}, {tierSeq:2, tierName:"豪华"}]`