docs(changelog): 补录 order-v2 接口变更说明(04-17 订单详情重构/04-20 出行人·物资清单·assignment/04-21 酒店 dayNumber) 7 篇

这个提交包含在:
yaosutu 2026-04-23 16:35:06 +08:00
父节点 6ae58d8e8e
当前提交 3894e88ba9
共有 7 个文件被更改,包括 994 次插入170 次删除

查看文件

@ -1,94 +1,241 @@
# 接口变更记录 — 2026-04-17
# C端订单详情页接口变更 — 2026-04-17
> **服务** hl-order-service-v2 · **类型** feat · **说明** C端订单详情页重构详情接口返回值变更 + 新增6个弹窗接口
## 变更总览
- **hl-order-service-v2**
- MpOrderC端: 详情接口返回值从 `OrderDetailVO` 改为 `MpOrderDetailVO`
- MpOrderC端: 新增6个服务详情弹窗接口
> **服务** hl-order-service-v2端口8094· **类型** feat
> **前端调用路径**: 网关(8080) → hl-mp-service(8085) → hl-order-service-v2(8094)
> **前端实际请求前缀**: `GET /mp/order/`mp-service 需同步新增 BFF 转发层)
---
## hl-order-service-v2
## 一、已改接口1个
### MpOrderC端/内部)
### ✏️ `GET /mp/order/{orderId}` — 订单详情
**请求参数**:不变(路径参数 orderId
**返回值变更**:整体结构从 `OrderDetailVO` 改为 `MpOrderDetailVO`
#### 新增字段
| 字段 | 类型 | 必有 | 说明 | 示例 |
| --- | --- | --- | --- | --- |
| `serviceItems` | `List` | ✅ | 服务包含摘要列表,每项含 type/title/summary/clickable | 见下方 |
| `notIncluded` | `String` | 否 | 不含说明 | `"往返大交通、个人消费"` |
| `priceBreakdown` | `Object` | 否 | 价格明细新订单有值,历史订单null | 见下方 |
| `balancePayMethodLabel` | `String` | 否 | 尾款方式标签 | `"落地后由领队收取"` |
| `refundProgress` | `Object` | 否 | 退款进度(退款中/已取消时有值) | 见下方 |
| `tripProgress` | `Object` | 否 | 行程进度(仅行程中状态有值) | 见下方 |
| `invoiceStatus` | `String` | ✅ | 发票状态 | `"AFTER_TRIP"` |
| `productTypeLabel` | `String` | ✅ | 产品类型中文 | `"核心产品"` |
#### 删除的字段(前端不再使用)
`totalCost`, `surchargeAmount`, `pendingUpgradeAmount`, `depositRatio`, `balanceProofUrl`, `balancePayMethod`, `remark`, `checklistConfirmed`, `unlockRequestedAt`, `confirmedAt`, `readyAt`, `creatorAdminId`, `creatorName`, `mchId`, `mchName`, `sharerOpenid`, `productSnapshot`, `expiryMinutes`, `timeline`, `processStatus`, `processStatusLabel`, `discountReason`, `discounts`, `surcharges`, `transportSegments`, `roomInfo`, `hotelAssignments`, `hotelAssignmentDetails`, `vehicleInfo`, `refundPolicy`, `refundPolicyId`, `contactName`, `contactPhone`
#### 保留不变的字段
`orderId`, `orderNo`, `groupCode`, `productId`, `productName`, `productCoverUrl`, `productType`, `departureDate`, `returnDate`, `tripDays`, `tripNights`, `adultCount`, `childCount`, `youngChildCount`, `babyCount`, `createTime`, `status`, `statusLabel`, `displayStatus`, `displayStatusLabel`, `cancelReason`, `cancelledAt`, `completedAt`, `expiryTime`, `totalPrice`, `depositAmount`, `balanceAmount`, `paidAmount`, `paymentType`, `paymentTypeLabel`, `paidAt`, `payMethodLabel`, `discountAmount`, `refundAmount`, `contracts`, `insurances`, `travelers`, `todos`, `reviewed`, `customizerId`, `customizerName`, `customizerAvatarUrl`, `customizerQrUrl`
---
### ✏️ `GET` /internal/mp/order/{orderId} — 订单详情(**返回值变更**
## 二、新增接口6个弹窗
**变更前**返回 `OrderDetailVO`(管理端通用),**变更后**返回 `MpOrderDetailVO`C端专用
> 用户点击 `serviceItems` 列表中某项时按需调用,不需要在详情页一次性请求。
> 每个接口都需要传 userIdmp-service 从 token 中获取后透传)。
**删除的字段**管理端专属,C端不再返回:
### 🆕 `GET /mp/order/{orderId}/tickets` — 门票清单
| 删除字段 | 说明 |
| --- | --- |
| `totalCost` | 总成本(仅管理员可见) |
| `surchargeAmount` | 费用增加总额 |
| `pendingUpgradeAmount` | 待确认差价 |
| `depositRatio` | 订金比例 |
| `balanceProofUrl` | 尾款凭证URL |
| `balancePayMethod` | 尾款支付方式代码 |
| `remark` | 订单备注 |
| `checklistConfirmed` | 清单确认状态 |
| `unlockRequestedAt` | 解锁请求时间 |
| `confirmedAt` | 确认时间 |
| `readyAt` | 就绪时间 |
| `creatorAdminId` | 创建人管理员ID |
| `creatorName` | 创建人姓名 |
| `mchId` / `mchName` | 商户号/名称 |
| `sharerOpenid` | 分享人openid |
| `productSnapshot` | 产品快照JSON |
| `expiryMinutes` | 支付时限分钟数 |
| `timeline` | 时间线列表 |
| `processStatus` / `processStatusLabel` | 内部流程状态 |
| `discountReason` | 优惠原因 |
| `discounts` / `surcharges` | 优惠/附加费明细列表 |
| `transportSegments` | 交通信息列表 |
| `roomInfo` / `hotelAssignments` / `hotelAssignmentDetails` | 房间/酒店分配 |
| `vehicleInfo` | 车辆信息JSON |
| `refundPolicy` / `refundPolicyId` | 退款政策 |
| `contactName` / `contactPhone` | 联系人(出行人列表中已有) |
**请求参数**:路径参数 `orderId`
**新增的字段**:
**返回值** `MpTicketListVO`
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| 🆕 `serviceItems` | `List<ServiceItemVO>` | 服务包含摘要列表,见下方结构 |
| 🆕 `notIncluded` | `String` | 不含说明(如"往返大交通、个人消费" |
| 🆕 `priceBreakdown` | `PriceBreakdownVO` | 价格明细(按人头+优惠+总额),见下方结构 |
| 🆕 `balancePayMethodLabel` | `String` | 尾款方式标签(如"落地后由领队收取" |
| 🆕 `refundProgress` | `RefundProgressVO` | 退款进度(退款中/已取消时有值),见下方结构 |
| 🆕 `tripProgress` | `TripProgressVO` | 行程进度(仅行程中状态有值),见下方结构 |
| 🆕 `invoiceStatus` | `String` | 发票状态:`ISSUED`=已开/`PENDING`=待开/`NOT_ISSUED`=未开/`AFTER_TRIP`=出行后开 |
| 🆕 `productTypeLabel` | `String` | 产品类型中文标签 |
**保留不变的字段**: `orderId`, `orderNo`, `groupCode`, `productId`, `productName`, `productCoverUrl`, `productType`, `departureDate`, `returnDate`, `tripDays`, `tripNights`, `adultCount`, `childCount`, `youngChildCount`, `babyCount`, `createTime`, `status`, `statusLabel`, `displayStatus`, `displayStatusLabel`, `cancelReason`, `cancelledAt`, `completedAt`, `expiryTime`, `totalPrice`, `depositAmount`, `balanceAmount`, `paidAmount`, `paymentType`, `paymentTypeLabel`, `paidAt`, `payMethodLabel`, `discountAmount`, `refundAmount`, `contracts`, `insurances`, `travelers`, `todos`, `reviewed`, `customizerId`, `customizerName`, `customizerAvatarUrl`, `customizerQrUrl`
---
### 新增结构体说明
#### ServiceItemVO服务包含摘要项
| `hint` | `String` | 顶部提示语 |
| `items` | `List` | 门票列表 |
| `items[].seq` | `Integer` | 序号1开始 |
| `items[].scenicName` | `String` | 景点名称 |
| `items[].coverUrl` | `String` | 景点封面图(可能为空) |
| `items[].dayNumber` | `Integer` | 第几天 |
| `items[].originalPrice` | `BigDecimal` | 门票原价/人可能为null |
| `items[].included` | `Boolean` | 是否已含 |
| `totalValue` | `BigDecimal` | 门票总价值/人可能为null |
| `footerText` | `String` | 底部文案 |
**响应示例**
```json
{
"type": "HOTEL",
"title": "住宿",
"summary": "5晚精选当地酒店",
"clickable": true
"code": 200,
"data": {
"hint": "以下景点门票已包含在套餐内,无需另购",
"items": [
{ "seq": 1, "scenicName": "莫日格勒河", "coverUrl": null, "dayNumber": 2, "originalPrice": 80.00, "included": true },
{ "seq": 2, "scenicName": "根河湿地", "coverUrl": null, "dayNumber": 3, "originalPrice": 120.00, "included": true }
],
"totalValue": 200.00,
"footerText": "全部已含·无需再付"
}
}
```
---
### 🆕 `GET /mp/order/{orderId}/hotels` — 住宿清单
**请求参数**:路径参数 `orderId`
**返回值** `MpHotelListVO`
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `type` | `String` | `HOTEL`/`MEAL`/`VEHICLE`/`GUIDE`/`PHOTOGRAPHER`/`TICKET`/`INSURANCE` |
| `title` | `String` | 服务标题 |
| `summary` | `String` | 摘要描述 |
| `clickable` | `Boolean` | 是否可点击查看弹窗详情 |
| `hint` | `String` | 顶部提示语(如"5晚精选当地酒店" |
| `items` | `List` | 酒店列表 |
| `items[].hotelName` | `String` | 酒店名称 |
| `items[].coverUrl` | `String` | 酒店封面图(可能为空) |
| `items[].dayNumber` | `Integer` | 第几天入住 |
| `items[].hotelType` | `String` | 酒店类型(如"5星"/"特色民宿",可能为空) |
| `items[].roomType` | `String` | 房型(如"大床房",可能为空) |
| `footerNote` | `String` | 底部备注 |
#### PriceBreakdownVO价格明细
**响应示例**
```json
{
"code": 200,
"data": {
"hint": "5晚精选当地酒店",
"items": [
{ "hotelName": "海拉尔铂尔曼大酒店", "coverUrl": null, "dayNumber": 1, "hotelType": "", "roomType": "大床房" }
],
"footerNote": "实际入住酒店以出行前确认为准"
}
}
```
---
### 🆕 `GET /mp/order/{orderId}/meals` — 餐饮清单
**请求参数**:路径参数 `orderId`
**返回值** `MpMealListVO`
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `hint` | `String` | 顶部提示语(如"已含5早8正餐" |
| `specialMeals` | `List` | 特色正餐列表 |
| `specialMeals[].dayNumber` | `Integer` | 第几天 |
| `specialMeals[].mealName` | `String` | 餐名 |
| `specialMeals[].mealType` | `String` | 餐型(午餐/晚餐) |
| `specialMeals[].description` | `String` | 菜品描述 |
| `stats` | `Object` | 餐饮统计 |
| `stats.breakfast` | `String` | 早餐统计(如"5餐·酒店自助" |
| `stats.specialDinner` | `String` | 特色正餐统计(如"3餐" |
| `stats.regularDinner` | `String` | 日常正餐统计(如"5餐·当地特色餐厅" |
| `footerNote` | `String` | 底部备注 |
**响应示例**
```json
{
"code": 200,
"data": {
"hint": "已含1早2正餐",
"specialMeals": [
{ "dayNumber": 2, "mealName": "手把肉宴", "mealType": "午餐", "description": "含奶茶/手把肉" }
],
"stats": { "breakfast": "1餐·酒店自助", "specialDinner": "1餐", "regularDinner": "1餐·当地特色餐厅" },
"footerNote": "对食物有过敏请提前告知领队"
}
}
```
---
### 🆕 `GET /mp/order/{orderId}/vehicle` — 用车详情
**请求参数**:路径参数 `orderId`
**返回值** `MpVehicleDetailVO`
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `hint` | `String` | 顶部提示语 |
| `vehicleName` | `String` | 车型名称 |
| `coverUrl` | `String` | 车型图片(可能为空) |
| `description` | `String` | 车型描述/特点(可能为空) |
| `matchRule` | `String` | 匹配规则说明 |
**响应示例**
```json
{
"code": 200,
"data": {
"hint": "一家一车不拼团·全程同一辆车",
"vehicleName": "商务车",
"coverUrl": null,
"description": "",
"matchRule": "匹配规则:根据出行人数自动配车"
}
}
```
---
### 🆕 `GET /mp/order/{orderId}/guide` — 领队详情
**请求参数**:路径参数 `orderId`
**返回值** `MpGuideInfoVO`
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `name` | `String` | 姓名可能为null |
| `avatarUrl` | `String` | 头像可能为null |
| `role` | `String` | 角色标签(固定"主领队"或"领队" |
| `phone` | `String` | 电话可能为null |
| `remark` | `String` | 简介可能为null |
> ⚠️ 产品服务快照扩展完成前,除 `role` 外所有字段可能为 null
---
### 🆕 `GET /mp/order/{orderId}/photographer` — 摄影详情
**请求参数**:路径参数 `orderId`
**返回值** `MpPhotographerInfoVO`
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `name` | `String` | 姓名可能为null |
| `avatarUrl` | `String` | 头像可能为null |
| `role` | `String` | 角色标签(固定"摄影师" |
| `phone` | `String` | 电话可能为null |
| `remark` | `String` | 简介可能为null |
> ⚠️ 同领队,产品服务快照扩展完成前字段可能为 null
---
## 三、新增结构体详细说明
### serviceItems服务包含摘要
详情接口返回的 `serviceItems` 是一个数组,每项代表一个服务类别:
```json
[
{ "type": "HOTEL", "title": "住宿", "summary": "5晚精选当地酒店", "clickable": true },
{ "type": "MEAL", "title": "餐饮", "summary": "5早 8正餐", "clickable": true },
{ "type": "VEHICLE", "title": "用车", "summary": "专属车辆 + 司机", "clickable": true },
{ "type": "GUIDE", "title": "领队", "summary": "全程陪同", "clickable": true },
{ "type": "PHOTOGRAPHER", "title": "摄影", "summary": "全程跟拍 + 精修照片", "clickable": true },
{ "type": "TICKET", "title": "门票", "summary": "4处景点门票", "clickable": true },
{ "type": "INSURANCE", "title": "保险", "summary": "旅行意外险", "clickable": false }
]
```
`clickable=true` 时点击应调用对应弹窗接口:`type=HOTEL``GET /mp/order/{orderId}/hotels`,以此类推。
### priceBreakdown价格明细
```json
{
@ -105,7 +252,9 @@
}
```
#### RefundProgressVO退款进度
> ⚠️ 仅新创建的订单有值,历史订单为 null,前端需做空判断
### refundProgress退款进度
```json
{
@ -122,13 +271,11 @@
}
```
| step.status | 说明 |
| --- | --- |
| `COMPLETED` | 已完成 |
| `ACTIVE` | 进行中(当前步骤) |
| `PENDING` | 待处理 |
step.status 取值:`COMPLETED`=已完成 / `ACTIVE`=进行中 / `PENDING`=待处理
#### TripProgressVO行程进度
> ⚠️ 仅退款中/已取消且有退款时有值,其他状态为 null
### tripProgress行程进度
```json
{
@ -139,104 +286,31 @@
}
```
---
> ⚠️ 仅行程中(displayStatus=TRAVELLING)状态有值,其他状态为 null
### 🆕 `GET` /internal/mp/order/{orderId}/tickets — 门票清单弹窗
### invoiceStatus 取值
**返回** `MpTicketListVO`:
```json
{
"hint": "以下景点门票已包含在套餐内,无需另购",
"items": [
{ "seq": 1, "scenicName": "莫日格勒河", "coverUrl": "...", "dayNumber": 2, "originalPrice": 80.00, "included": true }
],
"totalValue": 340.00,
"footerText": "全部已含·无需再付"
}
```
### 🆕 `GET` /internal/mp/order/{orderId}/hotels — 住宿清单弹窗
**返回** `MpHotelListVO`:
```json
{
"hint": "5晚精选当地酒店",
"items": [
{ "hotelName": "海拉尔铂尔曼大酒店", "coverUrl": "...", "dayNumber": 1, "hotelType": "5星", "roomType": "大床房" }
],
"footerNote": "实际入住酒店以出行前确认为准"
}
```
### 🆕 `GET` /internal/mp/order/{orderId}/meals — 餐饮清单弹窗
**返回** `MpMealListVO`:
```json
{
"hint": "已含5早8正餐",
"specialMeals": [
{ "dayNumber": 2, "mealName": "蒙古包午餐·手把肉宴", "mealType": "午餐", "description": "含奶茶/手把肉/烤包子" }
],
"stats": { "breakfast": "5餐·酒店自助", "specialDinner": "3餐", "regularDinner": "5餐·当地特色餐厅" },
"footerNote": "对食物有过敏请提前告知领队"
}
```
### 🆕 `GET` /internal/mp/order/{orderId}/vehicle — 用车详情弹窗
**返回** `MpVehicleDetailVO`:
```json
{
"hint": "一家一车不拼团·全程同一辆车",
"vehicleName": "别克GL8·商务MPV",
"coverUrl": "...",
"description": "独立航空座椅·后排空调·USB充电",
"matchRule": "匹配规则:根据出行人数自动配车"
}
```
### 🆕 `GET` /internal/mp/order/{orderId}/guide — 领队详情弹窗
**返回** `MpGuideInfoVO`:
```json
{
"name": "巴图",
"avatarUrl": "...",
"role": "主领队",
"phone": "13800001111",
"remark": "10年呼伦贝尔带队经验"
}
```
> ⚠️ 产品服务快照扩展完成前,`name`/`avatarUrl`/`phone`/`remark` 可能为空
### 🆕 `GET` /internal/mp/order/{orderId}/photographer — 摄影详情弹窗
**返回** `MpPhotographerInfoVO`:
```json
{
"name": "李维",
"avatarUrl": "...",
"role": "摄影师",
"phone": "13900002222",
"remark": "自然人像专长"
}
```
> ⚠️ 同领队,产品服务快照扩展完成前字段可能为空
| 值 | 说明 |
| --- | --- |
| `ISSUED` | 已开票 |
| `PENDING` | 开票中 |
| `NOT_ISSUED` | 未开票(已完成订单可申请) |
| `AFTER_TRIP` | 出行后可开 |
---
> ⚠️ **前端注意**:
> 1. 详情接口返回值结构已变更,需按新的 `MpOrderDetailVO` 字段对接
> 2. 6个弹窗接口按需调用用户点击 serviceItems 某项时才调)
> 3. `coverUrl`/`description`/`originalPrice` 等字段在产品服务快照扩展完成前可能为 `null` 或空字符串,请做空判断
> 4. `refundProgress` 仅退款中/已取消且有退款时有值,其他状态为 `null`
> 5. `tripProgress` 仅行程中状态有值,其他状态为 `null`
> 6. `priceBreakdown` 仅新创建的订单有值(历史订单为 `null`),前端做空判断
## 四、mp-service BFF 层需同步新增
以上6个弹窗接口目前在 order-service-v2 的 `/internal/mp/order/` 路径下已就绪。
mp-servicehl-mp-service需要新增对应的 BFF 转发层,路径映射如下:
| 前端调用 | mp-service 转发到 |
| --- | --- |
| `GET /mp/order/{orderId}/tickets` | `GET /internal/mp/order/{orderId}/tickets?userId=xxx` |
| `GET /mp/order/{orderId}/hotels` | `GET /internal/mp/order/{orderId}/hotels?userId=xxx` |
| `GET /mp/order/{orderId}/meals` | `GET /internal/mp/order/{orderId}/meals?userId=xxx` |
| `GET /mp/order/{orderId}/vehicle` | `GET /internal/mp/order/{orderId}/vehicle?userId=xxx` |
| `GET /mp/order/{orderId}/guide` | `GET /internal/mp/order/{orderId}/guide?userId=xxx` |
| `GET /mp/order/{orderId}/photographer` | `GET /internal/mp/order/{orderId}/photographer?userId=xxx` |
> mp-service 从用户 token 中提取 userId,作为查询参数透传给 order-service。

查看文件

@ -0,0 +1,137 @@
# 管理端订单车辆/酒店分配独立 GET 接口 — 2026-04-20
> **服务** hl-order-service-v2端口 8094· **类型** feat · **关联** PR #1009 / #1018
> **使用场景**:管理端订单详情 · 行程安排 Tab · 懒加载车辆/酒店分配数据
---
## 一、新增接口2 个)
### 🆕 `GET /admin/order/{orderId}/vehicle-assignment` — 查询车辆分配列表
**功能**:行程安排 Tab 懒加载。司机电话默认脱敏返回(如 `138****1234`)。订单不存在返回业务异常。
**请求参数**
| 参数 | 位置 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- | --- |
| `orderId` | Path | `Long` | ✅ | 订单ID |
**返回值** `Result<List<VehicleAssignmentVO>>`
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `assignmentId` | `Long` | 分配ID |
| `orderId` | `Long` | 订单ID |
| `vehicleType` | `String` | 车型名称(如"丰田普拉多" |
| `vehicleCount` | `Integer` | 车辆数 |
| `plateNumber` | `String` | 车牌号(如"蒙A·A1234" |
| `driverName` | `String` | 司机姓名 |
| `driverPhone` | `String` | 司机电话(脱敏,如 `138****1234` |
| `remark` | `String` | 备注 |
| `createTime` | `LocalDateTime` | 创建时间 |
**响应示例**
```json
{
"code": 200,
"data": [
{
"assignmentId": 900001,
"orderId": 700001,
"vehicleType": "丰田普拉多",
"vehicleCount": 1,
"plateNumber": "蒙A·A1234",
"driverName": "李师傅",
"driverPhone": "138****1234",
"remark": null,
"createTime": "2026-04-20 10:00:00"
}
]
}
```
---
### 🆕 `GET /admin/order/{orderId}/hotel-assignment` — 查询酒店分配列表
**功能**:行程安排 Tab 懒加载。按家庭/日期返回结构化酒店分配。订单不存在返回业务异常。
**请求参数**
| 参数 | 位置 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- | --- |
| `orderId` | Path | `Long` | ✅ | 订单ID |
**返回值** `Result<List<HotelAssignmentDetailVO>>`
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `assignmentId` | `Long` | 分配ID |
| `orderId` | `Long` | 订单ID |
| `familyIndex` | `Integer` | 家庭序号从1开始 |
| `hotelId` | `Long` | 酒店ID资源服务 |
| `hotelName` | `String` | 酒店名称 |
| `roomTypeId` | `Long` | 房型ID资源服务 |
| `roomType` | `String` | 房型名称 |
| `assignmentDate` | `LocalDate` | 分配日期 |
| `upgradePrice` | `BigDecimal` | 手动覆盖升级差价null=使用系统计算) |
| `remark` | `String` | 备注 |
**响应示例**
```json
{
"code": 200,
"data": [
{
"assignmentId": 800001,
"orderId": 700001,
"familyIndex": 1,
"hotelId": 500001,
"hotelName": "海拉尔铂尔曼大酒店",
"roomTypeId": 500101,
"roomType": "豪华大床房",
"assignmentDate": "2026-07-01",
"upgradePrice": null,
"remark": null
}
]
}
```
---
## 二、与已有接口关系
| 接口 | 作用 | 状态 |
| --- | --- | --- |
| `PUT /admin/order/{orderId}/hotel-assignment` | 按天按家庭分配酒店 | 已有(未变) |
| `POST /admin/order/{orderId}/hotel-assignment/preview` | 升级差价预览 | 已有(未变) |
| 新增的两个 `GET` | 独立查询,供列表懒加载 | 本期新增 |
订单详情接口 `GET /admin/order/{orderId}` 原有 `hotelAssignmentDetails` / `vehicleInfo` 等字段保持不变;新增的独立 GET 用于避免一次性加载全量订单详情时拉取重量级分配数据。
---
## 三、数据库变更
**无**。底层 `order_hotel_assignment` / `order_vehicle_assignment` 表未改。
---
## 四、错误码
HTTP 始终返回 200,错误码在 `Result.code` 中。
| code | 触发 | 说明 |
| --- | --- | --- |
| 200 | 正常 | 成功(无分配数据返回空列表) |
| 400 | 订单不存在 | `BusinessException` |
---
## 五、关联
- PR: [wx/HL#1018](https://git.1814.love:8443/wx/HL/pulls/1018)

查看文件

@ -0,0 +1,132 @@
# 订单出行人 MP 端 CRUD 接口新增 — 2026-04-20
> **服务** hl-order-service-v2端口 8094· **类型** feat · **关联** Issue #1020 / PR #1022
> **前端调用路径**: 网关(8080) → hl-mp-service(8085) → hl-order-service-v2(8094)
> **前端实际请求前缀**: `/mp/order/{orderId}/traveler`4 个接口)
---
## 一、能力概述
给小程序端补齐**订单出行人** CRUD 能力,对应原型 **L4xYN 乘坐人员勾选列表**、**Bf9jC 添加人员弹窗**。
| 原型节点 | 功能 | 主要接口 |
| --- | --- | --- |
| L4xYN pplList | 乘坐人员勾选列表 | `GET /mp/order/{orderId}/traveler` |
| Bf9jC | 添加人员弹窗 | `POST /mp/order/{orderId}/traveler` |
| Bf9jC编辑 | 修改出行人 | `PUT /mp/order/{orderId}/traveler/{travelerId}` |
| Bf9jC删除 | 删除出行人 | `DELETE /mp/order/{orderId}/traveler/{travelerId}` |
**注意区分两套"出行人"模型**
| 维度 | 路径 | 说明 |
| --- | --- | --- |
| 用户常用出行人 | `/mp/user/traveler/*` | user-service 管,已有 |
| **订单出行人**(本次新增) | `/mp/order/{orderId}/traveler/*` | order-v2 的 `order_traveler` 表 |
---
## 二、接口清单
鉴权user token登录态
| 方法 | 路径 | 用途 |
| --- | --- | --- |
| GET | `/mp/order/{orderId}/traveler` | 查某订单的出行人列表 |
| POST | `/mp/order/{orderId}/traveler` | 新增出行人到某订单 |
| PUT | `/mp/order/{orderId}/traveler/{travelerId}` | 修改出行人(字段为 null 保持原值不变) |
| DELETE | `/mp/order/{orderId}/traveler/{travelerId}` | 删除出行人 |
---
## 三、请求体(`MpOrderTravelerSaveReqVO`
```jsonc
{
"name": "张三", // 必填,≤50 字
"idCardType": "ID_CARD", // 字典 id_card_type
"idCardNo": "110101199001011234", // 必填
"phone": "13800000000",
"gender": "1", // 1=男 2=女
"birthday": "1990-01-01",
"travelerType": "ADULT", // 默认 ADULT,字典 traveler_type
"nationality": "中国",
"emergencyContact": "李四",
"emergencyPhone": "13900000000",
"email": "zhangsan@example.com"
}
```
**字典取值**
- `idCardType`: `ID_CARD` 身份证 / `PASSPORT` 护照 / `HK_MACAO_PASS` 港澳通行证 / `TAIWAN_PASS` 台湾通行证 / `OTHER` 其他
- `travelerType`: `ADULT` 成人 / `CHILD` 儿童 / `YOUNG_CHILD` 幼儿 / `BABY` 婴儿
**后端自动处理**
- 身份证18 位)自动解析 `birthday` + `gender`(前端可不传)
- 同订单证件号重复检查(重复抛业务错误)
---
## 四、响应体
### 列表 `GET` 响应
```jsonc
{
"code": 200,
"data": [
{
"travelerId": 10001, // Long,注未强制 String现有约定
"name": "张三",
"travelerType": "ADULT",
"travelerTypeLabel":"成人",
"idCardType": "ID_CARD",
"idCardTypeLabel": "身份证",
"idCardNo": "110101199001011234",
"gender": "1",
"birthday": "1990-01-01",
"phone": "13800000000",
"nationality": "中国",
"emergencyContact": "李四",
"emergencyPhone": "13900000000",
"email": "zhangsan@example.com"
}
]
}
```
### 新增/修改返回
返回单个对象(同列表元素结构)。
### 删除返回
```jsonc
{ "code": 200, "data": null }
```
### 约定
- 所有枚举字段都配 `xxxLabel` 中文标签
- 空数据返回 `[]`,不是 `null`
- 时间格式统一 `yyyy-MM-dd`(出生日期)/ `yyyy-MM-dd HH:mm:ss`(含时间字段)
---
## 五、前端接入建议
**L4xYN 乘坐人员勾选列表**
1. 打开页面 → `GET /mp/order/{orderId}/traveler` 拉取订单已有出行人
2. 用户勾选 → 把 travelerId 传给**到达信息**接口的 `travelerIds` 字段
**Bf9jC 添加人员弹窗**
1. 可选:先调 `GET /mp/user/traveler`(已有)让用户从常用库选一个 → 填到表单里
2. 用户补全/修改字段(含 OCR 扫描身份证填入,OCR 用小程序原生插件前端做)
3. 提交 `POST /mp/order/{orderId}/traveler`
---
## 六、关联
- Issue: [wx/HL#1020](https://git.1814.love:8443/wx/HL/issues/1020)
- PR: [wx/HL#1022](https://git.1814.love:8443/wx/HL/pulls/1022)(已合并到 dev

查看文件

@ -0,0 +1,128 @@
# C端「行李推荐弹窗」独立接口 — 2026-04-20
> **服务** hl-order-service-v2端口 8094 + hl-mp-service端口 8085· **类型** feat · **关联** PR #1041 / #1042
> **前端调用路径**: 网关(8080) → hl-mp-service(8085) → hl-order-service-v2(8094)
---
## 一、新增接口1 个)
### 🆕 `GET /mp/order/{orderId}/supplies-checklist` — 订单备品清单(行李推荐弹窗)
**功能**:对应小程序订单详情原型 `zgNiD` 行李推荐弹窗。从 `order_info.product_snapshot` 解析 `supplies`(按 `category` 分组,排除 `hasCost=true` 的成本项)+ `supplement.equipmentAdvice`(装备建议富文本)。
**请求参数**
| 参数 | 位置 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- | --- |
| `orderId` | Path | `Long` | ✅ | 订单ID |
> `userId` 由 mp-service 从 token 中获取后透传给 order-service,前端不传。
**返回值** `Result<MpSuppliesChecklistRespVO>`
| 字段 | 类型 | 必有 | 说明 |
| --- | --- | --- | --- |
| `orderId` | `Long` | ✅ | 订单 ID |
| `categories` | `List<MpSuppliesCategoryVO>` | ✅ | 备品清单按分类分组(无推荐时为空列表) |
| `equipmentAdvice` | `String` | 否 | 装备建议富文本HTML,快照无值时为 null |
**`MpSuppliesCategoryVO`**
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `category` | `String` | 分类名(如"衣物"、"配件" |
| `items` | `List<MpSuppliesItemVO>` | 该分类下的备品列表 |
**`MpSuppliesItemVO`**
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `suppliesName` | `String` | 备品名称(如"防晒霜" |
| `category` | `String` | 分类(与父级同) |
| `quantity` | `Integer` | 数量 |
| `billingType` | `String` | 计费方式(`PER_PERSON`=按人 / `PER_QUANTITY`=按件) |
| `sortOrder` | `Integer` | 排序 |
> ⚠️ 相比管理端 `OrderSuppliesVO`,C 端 VO 已去除 `hasCost``unitPrice` 等成本字段。
**请求示例**
```
GET /mp/order/2043935542092980226/supplies-checklist
```
**响应示例**
```json
{
"code": 200,
"message": "操作成功",
"data": {
"orderId": 2043935542092980226,
"categories": [
{
"category": "衣物",
"items": [
{ "suppliesName": "冲锋衣", "category": "衣物", "quantity": 1, "billingType": "PER_PERSON", "sortOrder": 1 },
{ "suppliesName": "速干裤", "category": "衣物", "quantity": 2, "billingType": "PER_PERSON", "sortOrder": 2 }
]
},
{
"category": "配件",
"items": [
{ "suppliesName": "防晒霜", "category": "配件", "quantity": 1, "billingType": "PER_QUANTITY", "sortOrder": 1 }
]
}
],
"equipmentAdvice": "<p>呼伦贝尔 7 月早晚温差大,建议携带薄款冲锋衣。</p>"
}
}
```
**空推荐响应示例**(快照无 supplies 与 equipmentAdvice
```json
{
"code": 200,
"message": "操作成功",
"data": {
"orderId": 2043935542092980226,
"categories": [],
"equipmentAdvice": null
}
}
```
---
## 二、mp-service BFF 转发
| 前端调用 | mp-service 转发到 |
| --- | --- |
| `GET /mp/order/{orderId}/supplies-checklist` | `GET /internal/mp/order/{orderId}/supplies-checklist` |
---
## 三、数据库变更
**无**。数据来自下单时固化的 `order_info.product_snapshot`
---
## 四、错误码
HTTP 始终返回 200,错误码在 `Result.code` 中。
| code | 触发 | 说明 |
| --- | --- | --- |
| 200 | 正常 | 成功(快照缺失时 categories 为空列表,equipmentAdvice 为 null |
| 400 | 订单不存在 | `BusinessException` |
---
## 五、关联
- PR: [wx/HL#1042](https://git.1814.love:8443/wx/HL/pulls/1042)
- 原型节点: `zgNiD` — 行李推荐弹窗
- 相关字段: `OrderDetailVO` 已同步新增 `supplies` / `equipmentAdvice` 字段,见 `2026-04-20_order-v2_order-detail-supplies-fields.md`

查看文件

@ -0,0 +1,86 @@
# 订单详情新增 supplies / equipmentAdvice 强类型字段 — 2026-04-20
> **服务** hl-order-service-v2端口 8094· **类型** feat · **关联** PR #1026 / #1031
> **前端调用路径**: 网关(8080) → hl-mp-service(8085) → hl-order-service-v2(8094)
---
## 一、现有接口字段新增(无路径/参数变更)
### ✏️ 订单详情接口 — 新增 2 字段
影响接口:
- `GET /mp/order/{orderId}` — C 端订单详情(`MpOrderDetailVO`
- `GET /admin/order/{orderId}` — 管理端订单详情(`OrderDetailVO`
两个接口共享底层 `OrderDetailQueryService`,均同步增加以下字段:
| 字段 | 类型 | 必有 | 说明 |
| --- | --- | --- | --- |
| `supplies` | `List<OrderSuppliesVO>` | 否 | 订单备品列表(来自下单时固化的产品快照) |
| `equipmentAdvice` | `String` | 否 | 装备建议富文本HTML,来自 `supplement.equipmentAdvice` |
**`OrderSuppliesVO` 字段**
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `id` | `Long` | 备品ID快照中的产品备品ID |
| `suppliesName` | `String` | 备品名称(如"帐篷" |
| `category` | `String` | 分类(如"户外装备" |
| `hasCost` | `Boolean` | 是否涉及成本 |
| `billingType` | `String` | 计费方式(`PER_PERSON`=按人 / `PER_QUANTITY`=按件) |
| `unitPrice` | `BigDecimal` | 单价 |
| `quantity` | `Integer` | 数量 |
| `sortOrder` | `Integer` | 排序 |
> ⚠️ `OrderSuppliesVO` 含**完整成本字段**`hasCost` / `unitPrice`),与 C 端"行李推荐弹窗"使用的 `MpSuppliesItemVO`(去掉了成本字段)不同。
**数据来源**:后端装配时从 `order_info.product_snapshot` JSON 解析 `supplies` 数组与 `supplement.equipmentAdvice` 字符串,填充为强类型字段。`productSnapshot` 原字段保持不变,**兼容现有前端**。
**降级行为**:快照为 `null`/非法/缺失子节点时,`supplies` 置为空列表,`equipmentAdvice` 置为 `null`,接口正常返回。
---
## 二、响应示例(新增字段部分)
```json
{
"code": 200,
"data": {
"orderId": 2043935542092980226,
"...": "(其余字段未变)",
"supplies": [
{
"id": 600001,
"suppliesName": "帐篷",
"category": "户外装备",
"hasCost": true,
"billingType": "PER_QUANTITY",
"unitPrice": 80.00,
"quantity": 2,
"sortOrder": 1
}
],
"equipmentAdvice": "<p>呼伦贝尔 7 月早晚温差大,建议携带薄款冲锋衣。</p>"
}
}
```
---
## 三、其他字段保持不变
所有现有字段(`orderId``productName``departureDate``travelers``insurances` 等)均未改动。
---
## 四、数据库变更
**无**。数据来自已有的 `order_info.product_snapshot` JSON 字段。
---
## 五、关联
- PR: [wx/HL#1031](https://git.1814.love:8443/wx/HL/pulls/1031)
- 相关接口:`GET /mp/order/{orderId}/supplies-checklist`(独立行李推荐弹窗),见 `2026-04-20_order-v2_mp-supplies-checklist.md`

查看文件

@ -0,0 +1,154 @@
# TripDetailVO 扩出发准备清单字段 — 2026-04-20
> **服务** hl-order-service-v2端口 8094· **类型** feat · **关联** Issue #1024 / PR #1025
> **前端调用路径**: 网关(8080) → hl-mp-service(8085) → hl-order-service-v2(8094)
> **前端实际请求前缀**: `GET /mp/trip/{orderId}`**无新接口**,扩字段)
---
## 一、能力概述
补齐原型 **ew2Kk 出发准备页的 prepSec 清单区块**。其余数据(倒计时 / 带队团队 / 行程概览 / 合同保险状态)已经在 `TripDetailVO` 中。
**⚠️ 无新接口**:扩现有 `GET /mp/trip/{orderId}` 的返回体,在 `TripDetailVO` 加一个字段 `preTripChecklist`
| 触发条件 | 行为 |
| --- | --- |
| `tripPhase == "BEFORE_START"` | `preTripChecklist` 填充 6 项清单 |
| `tripPhase == "IN_PROGRESS"` | `preTripChecklist``null` |
| `tripPhase == "ENDED"` | `preTripChecklist``null` |
---
## 二、接口清单
**无新接口**。使用现有:
| 方法 | 路径 | 变化 |
| --- | --- | --- |
| GET | `/mp/trip/{orderId}` | 返回体新增 `preTripChecklist` 字段 |
---
## 三、新增字段结构(`PreTripChecklistVO`
```jsonc
{
"preTripChecklist": {
"completedCount": 3, // 已完成项数
"totalCount": 6, // 总项数
"items": [
{
"key": "CONTRACT_SIGN", // 项 key
"title": "签署旅行合同", // 标题
"subtitle": "合同已准备,请尽快签署", // 副标题
"status": "WARNING", // DONE / PENDING / WARNING
"statusLabel": "紧急",
"actionType": "NAVIGATE", // NAVIGATE / CONFIRM / CONTACT_CS / null
"actionPayload": { // 前端按 actionType 解析
"pageKey": "contract_sign",
"orderId": "1000",
"contractId": "9001"
}
},
{
"key": "DEPOSIT_PAID",
"title": "订金已支付",
"subtitle": "¥2000 已支付",
"status": "DONE",
"statusLabel": "已完成",
"actionType": null,
"actionPayload": null
}
// ...共 6 项
]
}
}
```
---
## 四、清单 6 项 + 状态规则
| Key | 标题 | DONE 条件 | WARNING 条件 | 其他→PENDING |
| --- | --- | --- | --- | --- |
| `DEPOSIT_PAID` | 订金/全款支付 | `paidAmount >= 应付`FULL→totalPrice / DEPOSIT→depositAmount | — | 金额不足 |
| `TRAVELER_INFO` | 出行人完整度 | `validateTravelers.isComplete=true` | 有出行人信息缺失 | 人数不够 |
| `ARRIVAL_INFO` | 接送机信息 | arrivals 和 departures 都有 | — | 缺任一方向 |
| `CONTRACT_SIGN` | 合同签署 | contract.status=`SIGNED` | `PREPARING` / `UNSIGNED` | 无合同 |
| `INSURANCE` | 保险承保 | insurance.status=`INSURED` | `FAILED` | `PENDING` / 无保险 |
| `CHECKLIST_CONFIRMED` | 出行清单确认 | `OrderInfo.checklistConfirmed=true` | — | 未确认 |
### actionType 语义
| 值 | 前端应做 |
| --- | --- |
| `NAVIGATE` | 跳转小程序页面(按 `actionPayload.pageKey` 映射) |
| `CONFIRM` | 弹确认对话框(如"确认出行清单" |
| `CONTACT_CS` | 打开客服会话 |
| `null` | 不可操作DONE 状态) |
### pageKey 映射建议(前端维护)
| pageKey | 小程序路径 |
| --- | --- |
| `order_pay` | 支付页 |
| `traveler_list` | 出行人列表 |
| `arrival_form` | 到达信息表单 |
| `contract_sign` | 合同签署 |
| `checklist_confirm` | 清单确认 |
### 排序规则
后端已按 **WARNING > PENDING > DONE** 排序(紧急项靠前),前端直接渲染即可。
---
## 五、示例
### BEFORE_START 阶段完整响应(节选)
```jsonc
{
"code": 200,
"data": {
"orderId": "1000",
"tripPhase": "BEFORE_START",
"countdownDays": 12,
"departureDate": "2026-07-01",
"productName": "草原环线体验",
"guideName": "巴图", // 带队团队
"guidePhone": "138****5678",
"itinerarySummary": [...], // 行程概览
"contracts": [...],
"insurances": [...],
"preTripChecklist": { // ← 新增字段
"completedCount": 3,
"totalCount": 6,
"items": [...]
}
}
}
```
### IN_PROGRESS 阶段响应
```jsonc
{
"code": 200,
"data": {
"orderId": "1000",
"tripPhase": "IN_PROGRESS",
"todayDayNumber": 3,
"todayTitle": "莫日格勒河 → 额尔古纳",
"preTripChecklist": null // ← 非 BEFORE_START 阶段为 null
}
}
```
---
## 六、关联
- Issue: [wx/HL#1024](https://git.1814.love:8443/wx/HL/issues/1024)
- PR: [wx/HL#1025](https://git.1814.love:8443/wx/HL/pulls/1025)(已合并到 dev

查看文件

@ -0,0 +1,113 @@
# 酒店分配接口 date → dayNumber — 2026-04-21
> **服务** hl-order-service-v2端口 8094· **类型** refactor · **关联** Issue #1049 / PR #1051
> **破坏性变更**:请求入参字段名由 `date` 改为 `dayNumber`
---
## 一、影响接口
### ✏️ `PUT /admin/order/{orderId}/hotel-assignment` — 分配酒店(管理端)
**请求参数变更**:每个 `assignments[]` 元素的「日期字段」从 `date``LocalDate`)改为 `dayNumber``Integer`,第几天,从 1 开始)。
**变更对比**
| 旧字段 | 新字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- | --- |
| ~~`date`~~ | **`dayNumber`** | `Integer` | ✅ | 第几天(从 1 开始,≥1 |
**其他字段保持不变**`familyIndex` · `hotelId` · `hotelName` · `roomTypeId` · `roomType` · `upgradePrice` · `remark`
**新请求示例**
```json
PUT /admin/order/700001/hotel-assignment
{
"assignments": [
{
"familyIndex": 1,
"hotelId": 2023714929877450753,
"hotelName": "呼伦贝尔香格里拉大酒店",
"roomTypeId": 3002000000000000013,
"roomType": "大床房",
"dayNumber": 1,
"remark": ""
},
{
"familyIndex": 1,
"hotelId": 2023714929877450753,
"hotelName": "呼伦贝尔香格里拉大酒店",
"roomTypeId": 3002000000000000013,
"roomType": "大床房",
"dayNumber": 2
}
]
}
```
> ⚠️ 真实入住日期由后端按 `order.departureDate + dayNumber - 1` 现算,前端传递时**不再需要知道订单出发日期**。
---
### ✏️ `GET /admin/order/{orderId}/hotel-assignment` — 查询酒店分配列表(管理端)
**返回值字段变更**:新增 `dayNumber` 字段;`assignmentDate` 字段**保留**Service 层按 `order.departureDate + dayNumber - 1` 现算填充,前端展示逻辑无需改)。
**`HotelAssignmentDetailVO` 字段**
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `assignmentId` | `Long` | 分配ID |
| `orderId` | `Long` | 订单ID |
| `familyIndex` | `Integer` | 家庭序号从1开始 |
| `hotelId` | `Long` | 酒店ID |
| `hotelName` | `String` | 酒店名称 |
| `roomTypeId` | `Long` | 房型ID |
| `roomType` | `String` | 房型名称 |
| **`dayNumber`** | `Integer` | **新增**第几天从1开始 |
| `assignmentDate` | `LocalDate` | 入住日期(后端现算,保留) |
| `upgradePrice` | `BigDecimal` | 手动覆盖升级差价 |
| `remark` | `String` | 备注 |
---
### ✏️ `GET /mp/order/{orderId}/hotels` — C 端订单住宿弹窗
`MpHotelItemVO` 同步新增 `dayNumber` 字段;`assignmentDate` 保留(后端现算)。
---
## 二、数据库变更
**已在测试服执行**(本 changelog 生成时):
```sql
ALTER TABLE order_hotel_assignment
ADD COLUMN day_number INT NOT NULL COMMENT '第几天(从1开始,与meal/scenic assignment一致)' AFTER room_type;
ALTER TABLE order_hotel_assignment DROP COLUMN assignment_date;
```
历史数据按 `DATEDIFF(assignment_date, order.departure_date) + 1` 回填。
> 生产部署顺序必须 **先跑迁移 SQL 再重启服务**,否则老代码写入会因 `assignment_date` 列缺失而失败。
---
## 三、错误码
HTTP 始终返回 200,错误码在 `Result.code` 中。
| code | 触发 | 说明 |
| --- | --- | --- |
| 200 | 正常 | 成功 |
| 400 | `dayNumber` 缺失 | `第几天不能为空` |
| 400 | `dayNumber < 1` | `第几天必须大于等于1` |
---
## 四、关联
- Issue: [wx/HL#1049](https://git.1814.love:8443/wx/HL/issues/1049)
- PR: [wx/HL#1051](https://git.1814.love:8443/wx/HL/pulls/1051)(已合并到 dev
- 前置原因:原 `assignment_date` 在订单出发日变更时需要级联更新,且与 `order_meal_assignment` / `order_scenic_assignment``day_number` 字段设计不一致