docs: add fleet chat vehicle requirement contract
这个提交包含在:
父节点
09e2753f5b
当前提交
c7aec1217b
@ -0,0 +1,296 @@
|
|||||||
|
# 【前端对接·管理后台】车务会话有效用车需求守卫与调整页接送机时间
|
||||||
|
|
||||||
|
> **Issue**: [wx/HL#4829](https://git.1814.love:8443/wx/HL/issues/4829)
|
||||||
|
> **服务**: hl-user-service + hl-order-service-v3
|
||||||
|
> **日期**: 2026-07-08
|
||||||
|
> **影响范围**: 订单详情「联系车务」、调整订单车辆页、车务聊天
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 结论
|
||||||
|
|
||||||
|
- 车务会话必须建立在“当前 active 用车需求”之后;没有有效用车需求时,后端会拒绝打开车务会话和向 `FLEET:{orderId}` 直接发消息。
|
||||||
|
- 调整订单车辆页新增大交通接送机/站时间摘要;没有任何可展示时间时返回 `暂无接送机时间`。
|
||||||
|
- 车辆需求车型组合仍按整段行程生效,不支持“前几天一辆车、后几天另一辆车”的分天换车型需求。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 前端必须处理
|
||||||
|
|
||||||
|
| 场景 | 前端处理 |
|
||||||
|
|------|----------|
|
||||||
|
| 订单详情联系车务按钮 | 读 `GET /v3/admin/order/{id}/itinerary` 的 `canContactFleet`。为 `false` 时禁用/隐藏按钮,并展示 `contactFleetDisabledReason`。 |
|
||||||
|
| 车务聊天开窗兜底 | `POST /admin/message/chat/open-fleet` 返回 `281013` 时提示后端 message,不要继续打开空会话。 |
|
||||||
|
| 车务聊天直接发消息兜底 | 对 `FLEET:{orderId}` 调 `POST /admin/message/chat/{conversationKey}/messages` 返回 `281013` 时提示后端 message。 |
|
||||||
|
| 调整订单车辆页顶部红框 | 读 `GET /v3/admin/order/{id}/adjustment/snapshot?scope=VEHICLE_REQ` 的 `vehicleTransportSummary`;有 `displayText` 显示摘要,没有则显示 `emptyText`。 |
|
||||||
|
| 车辆需求车型组 | 继续提交 `fleet[].vehicleType/seats/count`,每组默认覆盖整段行程;不要增加前几天/后几天的分段车型 UI。 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 接口变更
|
||||||
|
|
||||||
|
### 3.1 订单行程 Tab
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /v3/admin/order/2074303545149980674/itinerary
|
||||||
|
Authorization: Bearer <admin-token>
|
||||||
|
```
|
||||||
|
|
||||||
|
新增字段:
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `canContactFleet` | boolean | 是否允许联系车务;true 表示已有当前 active 用车需求。 |
|
||||||
|
| `contactFleetDisabledReason` | string/null | 不可联系车务原因;`canContactFleet=false` 时返回。 |
|
||||||
|
|
||||||
|
无有效用车需求响应示例:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "成功",
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"hotelGroup": {
|
||||||
|
"requirement": {
|
||||||
|
"requirementId": "90001",
|
||||||
|
"status": "DONE"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"vehicleGroup": null,
|
||||||
|
"unreadMessageCount": 0,
|
||||||
|
"canContactFleet": false,
|
||||||
|
"contactFleetDisabledReason": "请先提交有效用车需求后再联系车务"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
已有有效用车需求响应示例:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "成功",
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"vehicleGroup": {
|
||||||
|
"requirement": {
|
||||||
|
"requirementId": "91011223344",
|
||||||
|
"version": 1,
|
||||||
|
"status": "PENDING",
|
||||||
|
"vehicleTypeSummary": "BUSINESS×1 / SUV×1",
|
||||||
|
"specialTags": ["中文司机"],
|
||||||
|
"remark": "司机会蒙语"
|
||||||
|
},
|
||||||
|
"assignments": []
|
||||||
|
},
|
||||||
|
"canContactFleet": true,
|
||||||
|
"contactFleetDisabledReason": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 打开车务会话
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /admin/message/chat/open-fleet
|
||||||
|
Authorization: Bearer <admin-token>
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"orderId": "2074303545149980674",
|
||||||
|
"peerAdminId": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
成功响应示例:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "成功",
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"conversationKey": "FLEET:2074303545149980674",
|
||||||
|
"isNew": false,
|
||||||
|
"order": {
|
||||||
|
"orderNo": "HL20260707092437709",
|
||||||
|
"customerName": "测试客户",
|
||||||
|
"productName": "测试核心产品-单档-固定订金",
|
||||||
|
"tripDays": 3,
|
||||||
|
"adultCount": 2,
|
||||||
|
"childCount": 0
|
||||||
|
},
|
||||||
|
"thread": {
|
||||||
|
"conversationKey": "FLEET:2074303545149980674",
|
||||||
|
"messages": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
无有效用车需求失败响应:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 281013,
|
||||||
|
"message": "请先提交有效用车需求后再联系车务",
|
||||||
|
"success": false,
|
||||||
|
"data": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 发送车务消息
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /admin/message/chat/FLEET:2074303545149980674/messages
|
||||||
|
Authorization: Bearer <admin-token>
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"content": "司机联系方式发我",
|
||||||
|
"contentType": "TEXT"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
说明:
|
||||||
|
|
||||||
|
- 仅订单维度键 `FLEET:{orderId}` 会执行有效用车需求守卫。
|
||||||
|
- 历史 pair 私聊键如 `FLEET:{bizId}:{minAdminId}:{maxAdminId}` 不走本守卫。
|
||||||
|
|
||||||
|
无有效用车需求失败响应同 `281013`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 281013,
|
||||||
|
"message": "请先提交有效用车需求后再联系车务",
|
||||||
|
"success": false,
|
||||||
|
"data": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.4 调整订单车辆页快照
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /v3/admin/order/2074303545149980674/adjustment/snapshot?scope=VEHICLE_REQ
|
||||||
|
Authorization: Bearer <admin-token>
|
||||||
|
```
|
||||||
|
|
||||||
|
新增字段:`vehicleTransportSummary`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "成功",
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"basic": {
|
||||||
|
"orderNo": "HL20260707092437709",
|
||||||
|
"customerName": "测试客户",
|
||||||
|
"totalAmount": "6210.00"
|
||||||
|
},
|
||||||
|
"vehicleRequirement": {
|
||||||
|
"id": "91011223344",
|
||||||
|
"version": 1,
|
||||||
|
"status": "PENDING",
|
||||||
|
"fleet": [
|
||||||
|
{
|
||||||
|
"vehicleType": "BUSINESS",
|
||||||
|
"seats": 7,
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"specialTags": ["中文司机"],
|
||||||
|
"remark": "需要大空间后备箱"
|
||||||
|
},
|
||||||
|
"vehicleTransportSummary": {
|
||||||
|
"hasPickupTime": true,
|
||||||
|
"displayText": "接:2026-07-23 10:15 海拉尔东山机场 CA1234;送:2026-07-25 15:20 海拉尔站 K99",
|
||||||
|
"emptyText": null,
|
||||||
|
"arrivals": [
|
||||||
|
{
|
||||||
|
"direction": "ARRIVAL",
|
||||||
|
"directionLabel": "到达",
|
||||||
|
"actionLabel": "接",
|
||||||
|
"timeType": "ARRIVE_TIME",
|
||||||
|
"time": "2026-07-23T10:15:00",
|
||||||
|
"station": "海拉尔东山机场",
|
||||||
|
"transportType": "FLIGHT",
|
||||||
|
"transportTypeLabel": "飞机",
|
||||||
|
"transportNo": "CA1234",
|
||||||
|
"pickupRequired": true,
|
||||||
|
"pickupRemark": "T3 出口举牌",
|
||||||
|
"travelerNames": ["张三", "李四"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"departures": [
|
||||||
|
{
|
||||||
|
"direction": "DEPARTURE",
|
||||||
|
"directionLabel": "离开",
|
||||||
|
"actionLabel": "送",
|
||||||
|
"timeType": "DEPART_TIME",
|
||||||
|
"time": "2026-07-25T15:20:00",
|
||||||
|
"station": "海拉尔站",
|
||||||
|
"transportType": "TRAIN",
|
||||||
|
"transportTypeLabel": "火车",
|
||||||
|
"transportNo": "K99",
|
||||||
|
"pickupRequired": true,
|
||||||
|
"pickupRemark": "提前 2 小时送站",
|
||||||
|
"travelerNames": ["张三", "李四"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"editableTabLocksHint": ["VEHICLE_REQ"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
无接送机时间响应示例:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "成功",
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"vehicleRequirement": null,
|
||||||
|
"vehicleTransportSummary": {
|
||||||
|
"hasPickupTime": false,
|
||||||
|
"displayText": null,
|
||||||
|
"emptyText": "暂无接送机时间",
|
||||||
|
"arrivals": [],
|
||||||
|
"departures": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
字段说明:
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `hasPickupTime` | boolean | 是否有至少一条可展示时间。 |
|
||||||
|
| `displayText` | string/null | 后端拼好的简短摘要,适合顶部红框直接展示。 |
|
||||||
|
| `emptyText` | string/null | 无时间时固定为 `暂无接送机时间`。 |
|
||||||
|
| `arrivals[]` | array | 到达批次,时间优先取 `arriveTime`,自驾取 `selfDriveEta`。 |
|
||||||
|
| `departures[]` | array | 离开批次,时间优先取 `departTime`,自驾取 `selfDriveEta`。 |
|
||||||
|
| `timeType` | string | `ARRIVE_TIME` / `DEPART_TIME` / `SELF_DRIVE_ETA`。 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 测试覆盖
|
||||||
|
|
||||||
|
后端已覆盖:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mvn -pl hl-user-service "-Dtest=ChatManagerTest,ConversationKeyUtilTest" test
|
||||||
|
mvn -pl hl-order-service-v3 -am "-Dtest=HouseOrderChatSummaryServiceTest,AdjustmentServiceTest,OrderDetailServiceTest" -DfailIfNoTests=false test
|
||||||
|
```
|
||||||
|
|
||||||
|
覆盖点:
|
||||||
|
|
||||||
|
- `open-fleet` 无 active 用车需求返回 `281013`,不创建车务成员行。
|
||||||
|
- `FLEET:{orderId}` 发送消息前执行同一守卫。
|
||||||
|
- 订单摘要返回 `vehicleRequirementId / vehicleRequirementStatus / canContactFleet`。
|
||||||
|
- 行程 Tab 返回 `canContactFleet / contactFleetDisabledReason`。
|
||||||
|
- 调整快照有大交通时间时返回接/送明细,无时间时返回 `暂无接送机时间`。
|
||||||
正在加载...
x
在新工单中引用
屏蔽一个用户