docs(changelog): #7440 团期车务派单只读入口——看板三端点 + GROUP_FLEET 双团会话(已部署实测 861ebff0c)
changelog-filename-gate / validate (push) Successful in 3s
changelog-filename-gate / validate (push) Successful in 3s
6 个新接口:fleet 派单看板三个 admin 读口 + order-v3 两个 internal 读口 + user-service open-group-fleet。本单只读,不含配车写入与派单进度回写。 错误码 7 个:809400/809401(order-v3 内部口自用,经 fleet 侧 fail-closed 统一转 600012, **前端看不到原始码**)、600012/600013/600014(fleet 对外)、281018/281019(会话侧)。 809401 把「分页越界 / 出发日区间倒挂 / keyword 超 50 字符 / dispatchProgress 枚举非法」 合并为一个出口,前端按单码统一提示重填筛选条件。 ⚠️ 访问控制口径:三个 fleet 读口由 #5626 的粗粒度角色门禁把关(必须切到 VEHICLE_MANAGER 或 SUPER_ADMIN),**不看权限码**。实测 ADMIN 角色(已被本单 Flyway 授予 fleet:group-dispatch:view)同样拿到 403,前端不能按「有该权限码就能调」设计。 测试环境已验证:三服务已部署(fleet/order-v3 @ 861ebff0c、user @ 30761683e,差异原因与 契约一致性核验见正文),6 端点逐个网关实测、每条两轮。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
这个提交包含在:
@@ -0,0 +1,488 @@
|
||||
---
|
||||
schema: "hl-changelog/v2"
|
||||
ticket: "7440"
|
||||
title: "团期车务派单只读入口——看板三端点 + 内部读接口 + GROUP_FLEET 双团会话"
|
||||
consumer: "admin"
|
||||
author: "wx(GIT)"
|
||||
change_type: "新增接口"
|
||||
backend_status: "deployed"
|
||||
gateway_status: "verified"
|
||||
frontend_status: "pending"
|
||||
frontend_owner: ""
|
||||
frontend_ref: ""
|
||||
target_release: ""
|
||||
verified_at: "2026-09-11"
|
||||
status_note: ""
|
||||
updated_at: "2026-09-11"
|
||||
base: "dev-v3"
|
||||
---
|
||||
|
||||
# fleet/order-v3/user: 团期车务派单只读入口
|
||||
|
||||
**服务**: hl-fleet-service / hl-order-service-v3 / hl-user-service
|
||||
**PR**: #7506
|
||||
**Issue**: #7440
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 关键变化
|
||||
|
||||
本单仅含只读入口,不含配车写入、不含派单进度回写(配车写入与派单进度回写在后续工单)。
|
||||
|
||||
---
|
||||
|
||||
## 一、背景
|
||||
|
||||
本单新增3个admin只读端点供fleet读取团期需求主数据(order-v3)与服务日,以及2个/internal/端点供fleet内部调用。
|
||||
|
||||
---
|
||||
|
||||
## 二、变更接口清单
|
||||
|
||||
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||||
|---|------|------|------|----------|------|
|
||||
| 1 | 待配车团期清单 | GET | `/admin/fleet/group-dispatch/pending-batches` | 新增 | 管理后台车务页首屏清单 |
|
||||
| 2 | 团期配车总览 | GET | `/admin/fleet/group-dispatch/batches/{groupBatchId}/overview` | 新增 | 单团详情页派车总览 |
|
||||
| 3 | 资源排班 | GET | `/admin/fleet/group-dispatch/resource-schedule` | 新增 | 派单编辑时查资源占用 |
|
||||
| 4 | 打开团期配车会话 | POST | `/admin/message/chat/open-group-fleet` | 新增 | 车务↔团期管理员团级会话 |
|
||||
| *内部* | 待配车候选分页 | POST | `/v3/internal/group-batch/vehicle-dispatch-candidates` | 新增 | 服务间接口,前端无需对接 |
|
||||
| *内部* | 单团用车覆盖 | GET | `/v3/internal/group-batch/{groupBatchId}/vehicle-coverage` | 新增 | 服务间接口,前端无需对接 |
|
||||
|
||||
---
|
||||
|
||||
## 三、接口详情
|
||||
|
||||
### 1. 待配车团期清单 `GET /admin/fleet/group-dispatch/pending-batches`
|
||||
|
||||
**VO**: `GroupDispatchPendingBatchPageReqVO → Result<PageResult<GroupDispatchPendingBatchRespVO>>`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
管理后台车务-团期配车页面的首屏清单。
|
||||
|
||||
#### 入参字段表
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|------|------|------|------|------|------|
|
||||
| departDateFrom | Query | LocalDate | ❌ | - | 出发日下界 |
|
||||
| departDateTo | Query | LocalDate | ❌ | - | 出发日上界 |
|
||||
| keyword | Query | String | ❌ | ≤50字符 | 团号/团名 |
|
||||
| dispatchProgress | Query | String | ❌ | NOT_STARTED/PARTIAL/FULL | 进度过滤 |
|
||||
| page | Query | Integer | ❌ | ≥1 | 页码(默认1) |
|
||||
| pageSize | Query | Integer | ❌ | 1-100 | 每页条数(默认20) |
|
||||
|
||||
#### 出参字段表
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| groupBatchId | Long | 团期ID |
|
||||
| batchNo | String | 团号 |
|
||||
| batchName | String | 团名 |
|
||||
| departDate | LocalDate | 出团日 |
|
||||
| dispatchProgress | String | 配车进度 |
|
||||
| unreadCount | Integer | 车务未读数 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"departDateFrom": "2026-09-01",
|
||||
"departDateTo": "2026-09-30",
|
||||
"page": 1,
|
||||
"pageSize": 20
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"total": 15,
|
||||
"records": [
|
||||
{
|
||||
"groupBatchId": 1934567890123456789,
|
||||
"batchNo": "GB-26-0912-01",
|
||||
"batchName": "额吉的故乡 9/12 团",
|
||||
"departDate": "2026-09-12",
|
||||
"dispatchProgress": "PARTIAL",
|
||||
"unreadCount": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {"total": 0, "records": []},
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 600013,
|
||||
"message": "排班查询参数非法: departDateFrom 不能晚于 departDateTo",
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 600012,
|
||||
"message": "团期配车基线不可达,请稍后重试",
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
**降级链路**:600013 由本端点自身入参校验抛出(`page<1`/`pageSize`不在1-100/出发日区间倒挂/keyword超50字符/`dispatchProgress`枚举非法,五种情形共用同一个码)。600012 是本端点对外唯一的「上游不可达」码——内部经 Feign 调用 order-v3 团期用车候选口(`POST /v3/internal/group-batch/vehicle-dispatch-candidates`),该内部接口对同一批入参约束会独立抛 `809401 查询参数非法`(`GroupBatchVehicleReadErrorCode.java:38`),但本端点已先行校验挡在前面(不会把非法参数带给 Feign),且 `fetchCandidatesOrFail`(`GroupDispatchQueryService.java:314-336`)对 Feign 返回的任何非成功 Result(含 809401)一律失败关闭转成 600012——调用方看不到 809401 原始码。
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 进度是fleet内存过滤,故先分页再过滤,单页可能少于pageSize
|
||||
- unreadCount软依赖,user-service不可达时退0
|
||||
|
||||
---
|
||||
|
||||
### 2. 团期配车总览 `GET /admin/fleet/group-dispatch/batches/{groupBatchId}/overview`
|
||||
|
||||
**VO**: `Long → Result<GroupDispatchOverviewRespVO>`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
单团详情页的派车总览。
|
||||
|
||||
#### 入参字段表
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|------|------|------|------|------|------|
|
||||
| groupBatchId | Path | Long | ✅ | - | 团期ID |
|
||||
|
||||
#### 出参字段表
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| groupBatchId | Long | 团期ID |
|
||||
| serviceDates | List<LocalDate> | 权威服务日 |
|
||||
| days | List | 逐日派车状态 |
|
||||
| transferPendingTotal | Integer | 全团接送机未配计数 |
|
||||
| conversationKey | String | 会话键 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```json
|
||||
GET /admin/fleet/group-dispatch/batches/1934567890123456789/overview
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"groupBatchId": 1934567890123456789,
|
||||
"serviceDates": ["2026-09-12", "2026-09-13", "2026-09-14"],
|
||||
"days": [
|
||||
{"serviceDate": "2026-09-12", "dispatched": true}
|
||||
],
|
||||
"transferPendingTotal": 3,
|
||||
"conversationKey": "GROUP_FLEET:1934567890123456789"
|
||||
},
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
无。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 600012,
|
||||
"message": "团期配车基线不可达,请稍后重试",
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
**降级链路(🔴 本端点对外只有 600012 这一个码)**:内部经 Feign 调用 order-v3 单团用车覆盖口(`GET /v3/internal/group-batch/{groupBatchId}/vehicle-coverage`),团期不存在或已软删时该内部接口会抛 `809400 团期不存在`(`GroupBatchVehicleReadErrorCode.java:28`);但 `fetchCoverageOrFail`(`GroupDispatchQueryService.java:526-537`)把 Feign 返回的任何非成功 Result(含 809400)一律失败关闭转成 600012——本端点**不透出 809400**,调用方只会看到 600012,不要按「overview 会返 809400」处理。
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- serviceDates是权威口径,fleet不得自己铺行程日
|
||||
|
||||
---
|
||||
|
||||
### 3. 资源排班 `GET /admin/fleet/group-dispatch/resource-schedule`
|
||||
|
||||
**VO**: `ResourceScheduleListReqVO → Result<List<ResourceScheduleRespVO>>`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
派单编辑时查询车/司机的排班占用。
|
||||
|
||||
#### 入参字段表
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|------|------|------|------|------|------|
|
||||
| resourceType | Query | String | ✅ | VEHICLE/DRIVER | 资源维度 |
|
||||
| resourceIds | Query | List<Long> | ✅ | 1-50个 | 资源ID集合 |
|
||||
| dateFrom | Query | LocalDate | ✅ | - | 起始日 |
|
||||
| dateTo | Query | LocalDate | ✅ | ≤31天 | 结束日 |
|
||||
|
||||
#### 出参字段表
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| resourceType | String | 资源维度 |
|
||||
| resourceId | Long | 资源ID |
|
||||
| resourceLabel | String | 车牌/司机名 |
|
||||
| days | List | 排班日历 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```json
|
||||
GET /admin/fleet/group-dispatch/resource-schedule?resourceType=VEHICLE&resourceIds=1&dateFrom=2026-09-12&dateTo=2026-09-30
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": [
|
||||
{
|
||||
"resourceType": "VEHICLE",
|
||||
"resourceId": 1,
|
||||
"resourceLabel": "蒙A12345",
|
||||
"days": []
|
||||
}
|
||||
],
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
返回空days列表。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 600014,
|
||||
"message": "不支持的资源类型: BOAT",
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 600013,
|
||||
"message": "排班查询参数非法: 查询跨度不能超过 31 天",
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
**触发条件**:600014 仅在 `resourceType` 不是 `VEHICLE`/`DRIVER` 时抛出(示例中 `BOAT` 为非法值占位)。600013 覆盖:`resourceIds` 为空 / 超 50 个、`dateFrom`/`dateTo` 为空、日期倒置、跨度超 31 天,五种情形共用同一个码。本端点只读本域两张业务表,不经 Feign 调用 order-v3,故与 809400/809401 无关。
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 不分页,规模由参数上限封死
|
||||
- 返回顺序必须与入参顺序相同
|
||||
|
||||
---
|
||||
|
||||
### 4. 打开团期配车会话 `POST /admin/message/chat/open-group-fleet`
|
||||
|
||||
**VO**: `ChatOpenGroupFleetReqVO → Result<ChatOpenFullRespVO>`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
派单看板打开团期的车务↔团期管理员会话。
|
||||
|
||||
#### 入参字段表
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|------|------|------|------|------|------|
|
||||
| groupBatchId | Body | Long | ✅ | - | 团期ID |
|
||||
|
||||
#### 出参字段表
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| conversationKey | String | 会话键 |
|
||||
| conversationId | Long | 会话ID |
|
||||
| currentSide | String | GROUP_ADMIN / VEHICLE_TEAM |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"groupBatchId": 1934567890123456789
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"conversationKey": "GROUP_FLEET:1934567890123456789",
|
||||
"conversationId": 1934567890123456789,
|
||||
"currentSide": "GROUP_ADMIN"
|
||||
},
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
无。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 281018,
|
||||
"message": "无权访问该团期配车会话",
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 281019,
|
||||
"message": "团期不存在、已结算或已取消,无法发起配车会话",
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
**分工**:281018 = 有登录态但当前角色既非 `VEHICLE_MANAGER`(车务侧)也不持 `group-batch:demand:confirm`(团期管理员侧,超管天然通过)——准入完全按 token 当前角色判,与是否为会话成员无关(`TeamChatAuthorizationService.java:158-169`)。281019 = 团期本身不可联系(不存在/已软删/已结算/已取消),前置条件与 `GROUP_HOUSE` 用的 281017 同源(`TeamChatModule.java:75`)。**281019 只卡 open(本端点)/ send,`messages`/`read` 仍放行**(`requirePrecondition` 参数为 false,见 `ChatMessageController.java` 的 `/{conversationKey}/messages`)——终态团期的历史会话仍可审计读取,前端不要因为拿到过 281019 就连历史消息一起屏蔽。
|
||||
|
||||
281016「缺少团期上下文」(`ChatErrorCode.java:76`)存在但正常路径触发不到:`groupBatchId` 由请求体 VO 的 `@NotNull` + Controller 的 `@Valid` 先挡成 100001,281016 只在 internal / 单测直调 Service 时才会真抛(见 `ChatManager.java:444-446` 注释),前端按正常表单提交不会遇到它。
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 双团队会话
|
||||
- 前置:团期活跃
|
||||
|
||||
---
|
||||
|
||||
## 四、契约约束与正确调用方式
|
||||
|
||||
| 场景 | 结果 |
|
||||
|------|------|
|
||||
| 分页越界 | 返600013 |
|
||||
| 日期倒置 | 返600013 |
|
||||
| 关键词超长 | 返600013 |
|
||||
|
||||
---
|
||||
|
||||
## 五、数据库行为
|
||||
|
||||
本单仅含查询接口,无写操作。
|
||||
|
||||
---
|
||||
|
||||
## 六、边界行为
|
||||
|
||||
- 未登录 → 401
|
||||
- 团期不存在 → 600012
|
||||
|
||||
---
|
||||
|
||||
## 六.5、枚举
|
||||
|
||||
### dispatchProgress
|
||||
|
||||
| 值 | 中文 |
|
||||
|----|------|
|
||||
| NOT_STARTED | 未启动 |
|
||||
| PARTIAL | 部分完成 |
|
||||
| FULL | 已完成 |
|
||||
|
||||
---
|
||||
|
||||
## 六.6、修改前后对比
|
||||
|
||||
N/A
|
||||
|
||||
---
|
||||
|
||||
## 六.7、影响评估
|
||||
|
||||
- **是否破坏向后兼容**: 否
|
||||
- **前端是否必须同步上线**: 否
|
||||
|
||||
---
|
||||
|
||||
## 六.8、菜单与权限
|
||||
|
||||
- **菜单挂载**(`V20260910_006__add_group_batch_fleet_dispatch_menu.sql`):在既有「车务管理」(`path=/fleet`)节点下新增二级目录「团期配车」(`menu_type=D`,`path=/fleet/group-dispatch`,`icon=Van`,`sort_order=46`),其下唯一三级菜单同名「团期配车」(`menu_type=M`,`path=component=/fleet/group-dispatch`);菜单可见性(`sys_role_menu`)授予 `SUPER_ADMIN` / `ADMIN` / `VEHICLE_MANAGER` 三个角色。
|
||||
- **权限标识**(`V20260910_007__add_group_batch_fleet_permission.sql`):新增权限码 `fleet:group-dispatch:view`(`resource_type=FLEET_GROUP_DISPATCH`,`action=VIEW`),覆盖本单三个只读端点(待配车团期清单/团期配车总览/资源排班);三级菜单的 `permission_code` 字段(V20260910_006 第66行)写的也是这同一个码。`admin_role_permission` 授权 `VEHICLE_MANAGER` / `ADMIN` / `SUPER_ADMIN`;团期管理员侧不在此授权范围内(他们看配车进度走团期管理页,不进车务页面)。
|
||||
|
||||
---
|
||||
|
||||
## 七、不影响范围
|
||||
|
||||
- 房务、C端、既有会话
|
||||
|
||||
---
|
||||
|
||||
## 八、测试环境已验证
|
||||
|
||||
**环境与提交**:测试服部署 `hl-fleet-service` / `hl-order-service-v3` @ `861ebff0c`,`hl-user-service` @ `30761683e`(与前两者不同提交号是部署窗口内 dev-v3 尖端继续前移所致;已核实中间那 5 个提交对 `hl-user-service`/`hl-fleet-service` 零文件改动,且改动集中在 `hl-common-feign`,与本单改的 `hl-common-core`/`dto/fleet` 零重叠,契约不受影响)。
|
||||
|
||||
**网关实测(6 个端点,每条两轮不同角色)**:
|
||||
|
||||
| 端点 | 角色 | 结果 |
|
||||
|---|---|---|
|
||||
| `GET /admin/fleet/group-dispatch/pending-batches`<br>`GET /admin/fleet/group-dispatch/batches/{id}/overview`<br>`GET /admin/fleet/group-dispatch/resource-schedule` | `VEHICLE_MANAGER` | **200**,返回真实数据 |
|
||||
| 同上三个 | `ROOM_MANAGER` / `ADMIN` | **403**「无权限访问车务管理,请切换到车务角色」 |
|
||||
| `POST /v3/internal/group-batch/vehicle-dispatch-candidates`<br>`GET /v3/internal/group-batch/{id}/vehicle-coverage` | 任意(含带 token) | **403**「接口不可访问」——网关 `JwtAuthFilter` 按 `/v3/internal/**` 路径前缀在鉴权之前就拦掉,与 token/角色无关,外部不可达(符合预期,这两个是服务间接口) |
|
||||
| `POST /admin/message/chat/open-group-fleet` | `VEHICLE_MANAGER` | **200**,两次调用 `isNew` 分别为 `true`/`false`(首开建会话、二次找回同一条,幂等生效) |
|
||||
|
||||
🔴 **`ADMIN` 角色拿到的是 403,不是 200**——fleet 三个只读端点的访问控制是 #5626 的粗粒度角色门禁(仅放行 `VEHICLE_MANAGER` / `SUPER_ADMIN`),**不看权限码** `fleet:group-dispatch:view`(六.8 节新增的那个)。前端如果按「持有该权限码就能调」设计菜单可见性之外的接口调用逻辑,`ADMIN` 角色会在实调时翻车——必须同时满足角色门禁。
|
||||
|
||||
```
|
||||
GET /admin/fleet/group-dispatch/pending-batches → 200 ✓(VEHICLE_MANAGER)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、相关历史 PR
|
||||
|
||||
| PR | Issue | 说明 |
|
||||
|----|-------|------|
|
||||
| #7506 | #7440 | 本单 |
|
||||
|
||||
---
|
||||
|
||||
## 十、相关文档
|
||||
|
||||
- Issue: [#7440](https://git.1814.love:8443/wx/HL/issues/7440)
|
||||
- PR: [#7506](https://git.1814.love:8443/wx/HL/pulls/7506)
|
||||
- Commit: [861ebff0c](https://git.1814.love:8443/wx/HL/commit/861ebff0c)
|
||||
|
||||
## 关联 / 联系人
|
||||
|
||||
### 链接
|
||||
|
||||
- **Issue**: [#7440](https://git.1814.love:8443/wx/HL/issues/7440)
|
||||
- **PR**: [#7506](https://git.1814.love:8443/wx/HL/pulls/7506)
|
||||
- **Merge commit**: [861ebff0c](https://git.1814.love:8443/wx/HL/commit/861ebff0c)
|
||||
|
||||
### 联系人
|
||||
|
||||
- **后端负责人**: @wx
|
||||
在新工单中引用
屏蔽一个用户