文件
hl-api-changelog/changelogs-v2/2026-09/11_7440_团期车务派单只读入口-新增接口-管理后台.md
T
API Changelog Bot和Claude Opus 5 78ddcae40e
changelog-filename-gate / validate (push) Successful in 3s
docs(changelog): #7440 团期车务派单只读入口——看板三端点 + GROUP_FLEET 双团会话(已部署实测 861ebff0c)
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>
2026-09-11 13:24:48 +08:00

15 KiB
原始文件 Blame 文件历史

schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
schema ticket title consumer author change_type backend_status gateway_status frontend_status frontend_owner frontend_ref target_release verified_at status_note updated_at base
hl-changelog/v2 7440 团期车务派单只读入口——看板三端点 + 内部读接口 + GROUP_FLEET 双团会话 admin wx(GIT) 新增接口 deployed verified pending 2026-09-11 2026-09-11 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 车务未读数

请求示例

{
  "departDateFrom": "2026-09-01",
  "departDateTo": "2026-09-30",
  "page": 1,
  "pageSize": 20
}

响应示例

{
  "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
}

空数据 / 降级响应

{
  "code": 200,
  "data": {"total": 0, "records": []},
  "success": true
}

错误响应

{
  "code": 600013,
  "message": "排班查询参数非法: departDateFrom 不能晚于 departDateTo",
  "success": false
}
{
  "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 权威服务日
days List 逐日派车状态
transferPendingTotal Integer 全团接送机未配计数
conversationKey String 会话键

请求示例

GET /admin/fleet/group-dispatch/batches/1934567890123456789/overview

响应示例

{
  "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
}

空数据 / 降级响应

无。

错误响应

{
  "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 ✅ 1-50个 资源ID集合
dateFrom Query LocalDate ✅ - 起始日
dateTo Query LocalDate ✅ ≤31天 结束日

出参字段表

字段 类型 说明
resourceType String 资源维度
resourceId Long 资源ID
resourceLabel String 车牌/司机名
days List 排班日历

请求示例

GET /admin/fleet/group-dispatch/resource-schedule?resourceType=VEHICLE&resourceIds=1&dateFrom=2026-09-12&dateTo=2026-09-30

响应示例

{
  "code": 200,
  "data": [
    {
      "resourceType": "VEHICLE",
      "resourceId": 1,
      "resourceLabel": "蒙A12345",
      "days": []
    }
  ],
  "success": true
}

空数据 / 降级响应

返回空days列表。

错误响应

{
  "code": 600014,
  "message": "不支持的资源类型: BOAT",
  "success": false
}
{
  "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

请求示例

{
  "groupBatchId": 1934567890123456789
}

响应示例

{
  "code": 200,
  "data": {
    "conversationKey": "GROUP_FLEET:1934567890123456789",
    "conversationId": 1934567890123456789,
    "currentSide": "GROUP_ADMIN"
  },
  "success": true
}

空数据 / 降级响应

无。

错误响应

{
  "code": 281018,
  "message": "无权访问该团期配车会话",
  "success": false
}
{
  "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
GET /admin/fleet/group-dispatch/batches/{id}/overview
GET /admin/fleet/group-dispatch/resource-schedule
VEHICLE_MANAGER 200,返回真实数据
同上三个 ROOM_MANAGER / ADMIN 403「无权限访问车务管理,请切换到车务角色」
POST /v3/internal/group-batch/vehicle-dispatch-candidates
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 本单

十、相关文档

关联 / 联系人

链接

联系人

  • 后端负责人: @wx