14 KiB
schema, ticket, title, consumer, backend, gateway, frontend, base, generated
| schema | ticket | title | consumer | backend | gateway | frontend | base | generated |
|---|---|---|---|---|---|---|---|---|
| hl-changelog/v1 | 5186 | 排车中订单恢复派车派人入口并补齐改派上下文 | admin | verified | verified | pending | dev-v3 | 2026-07-23T16:10:00+08:00 |
Fleet:排车中订单恢复“派车派人”入口
服务: hl-fleet-service
Issue: #5186
日期: 2026-07-23
影响范围: 管理后台车务派单看板及订单派车流程
⚠️ 关键变化
排车状态为 holding 或 holding_urgent 时,订单并非不可操作:后端现在返回 canAssign=true,并在 availableActionCodes 中下发 CHANGE_ASSIGNMENT,允许车务继续进入“派车派人”流程调整司机或车辆。
2026-07-23 契约修订:改派候选查询需要用 orderId + requirementId + fleetItemIndex 精确定位当前订单的当前用车需求槽位。看板列表、详情顶层和详情内每个有效派车组现均稳定返回字符串形式的 requirementId,前端直接透传,不自行推导。
变更接口
| 接口 | 方法 | 路径 | 变更类型 |
|---|---|---|---|
| 派单看板列表 | GET | /admin/fleet/board/orders |
响应字段取值扩展、新增字段 |
| 派单看板详情 | GET | /admin/fleet/board/orders/:orderId |
新增字段 |
请求参数和写接口路径均未改变。
二、响应契约
records[] 中以下字段按服务端返回值处理:
assignmentStatus |
canAssign |
availableActionCodes |
前端行为 |
|---|---|---|---|
unassigned |
true |
包含 ASSIGN |
展示“派车派人”,提交既有创建派单接口 |
unassigned_urgent |
true |
包含 ASSIGN |
展示“派车派人”,提交既有创建派单接口 |
holding |
true |
包含 CHANGE_ASSIGNMENT |
展示“改派”,提交既有 changeAssignment 改派接口 |
holding_urgent |
true |
包含 CHANGE_ASSIGNMENT |
展示“改派”,提交既有 changeAssignment 改派接口 |
assigned / completed / canceled |
false |
不包含上述可派动作 | 不展示入口 |
前端不要再用 assignmentStatus === 'unassigned' 自行推断入口,也不要因为订单已有司机或车辆就隐藏按钮。入口以 canAssign === true 为第一判断,具体提交模式以 availableActionCodes 为准。
排车中进入流程属于调整当前有效派单,不是新增第二条有效派单;继续复用现有改派请求、基线差异提示、司机车辆档期冲突提示和刷新逻辑。
改派候选上下文
| 响应位置 | 新增字段 | 类型 | 用途 |
|---|---|---|---|
列表 data.records[] |
requirementId |
string |
当前卡片所属用车需求 ID |
详情 data |
requirementId |
string |
当前有效用车需求 ID |
详情 data.currentAssignment |
requirementId |
string |
当前派车组所属用车需求 ID |
详情 data.activeAssignments[] |
requirementId |
string |
每个有效派车组所属用车需求 ID |
进入改派候选查询时:
orderId取列表返回的数字订单 ID;requirementId优先取详情顶层同名字段,按具体派车组操作时可取该组的同名字段;fleetItemIndex取当前卡片或当前派车组字段;- 三者必须原样透传给候选接口,不得使用团号、订单号或数组位置替代;
orderId、requirementId均按字符串处理,避免 JavaScript 大整数精度丢失。
当前 v2.1 候选请求组装已经读取 order.requirementId;后端部署后,从列表进入并合并详情时会获得该字段,无需前端猜测需求 ID。
排车中入口与向导状态
测试环境现状仍有一处前端状态错位:看板卡片已经显示“排车中”,点击“派车派人”后虽然按 CHANGE_ASSIGNMENT 进入 reassign 模式,但 resolveAssignFlowRestoreState(order, mode) 对所有非 confirmHold 模式固定返回 step: 1,导致向导错误高亮“订单详情”,底部也显示“下一步 · 排车”。
前端需要统一按后端状态和动作码恢复入口语义:
assignmentStatus=holding/holding_urgent且动作码包含CHANGE_ASSIGNMENT时,卡片按钮文案显示“改派”,不要继续显示“派车派人”;- 从该入口打开时保持
mode=reassign,向导直接进入第 2 步“排车”,第 1 步“订单详情”显示已完成; - 第 2 步带出当前司机、车辆,允许只更换其中一项;提交继续调用既有
changeAssignment,不得新增第二条有效派单; - “司机已确认/查看待确认”入口仍使用
confirmHold并恢复第 3 或第 4 步,不能被本次改派逻辑影响; - 首次待派车订单仍从第 1 步开始,按钮仍为“派车派人”。
以上仅是前端状态机和展示文案调整,后端不新增接口或字段。
holding 的用户可见状态文案
holding 是后端技术状态码,表示车辆和司机已经锁定、派单通知已经发出,当前正在等待司机回复。面向车务人员时不能继续显示“排车中”,应统一显示为“待确认”:
- 看板卡片主状态:
holding显示“待确认”,holding_urgent显示“待确认即将超时”; - 状态筛选、数量汇总和图例使用同一套“待确认”文案;
- 卡片上的司机回执徽标可显示“待回复”,用于补充说明,不能与主状态“排车中”形成两个不同口径;
- 技术值仍保持
holding/holding_urgent,接口请求参数、状态判断、颜色和改派动作码均不改变; - 首次尚未锁定车辆和司机的
unassigned继续显示“待派车”,确认完成后的assigned继续显示“已派车”。
当前 v2.1 的 ORDER_STATUS_META、FILTER_STATUS_OPTIONS 以及后端 assignmentStatusLabel 仍含“排车中”旧文案。管理后台应以本节用户口径覆盖展示;如直接消费后端 label,前端需按状态码归一,避免同页出现“排车中”和“待确认”两套名称。
待确认订单的“继续派车”入口
待确认订单必须同时保留“继续派车”和“改派”两个入口:
availableActionCodes包含RECORD_DRIVER_CONFIRMATION时显示主按钮“继续派车”,点击复用现有onConfirmHold(order),以mode=confirmHold打开派单弹窗;confirmHold根据后端stageCode/driverConfirmedAt恢复流程:等待司机回复时进入第 3 步“待确认”,已登记司机确认时进入第 4 步“确认执行”;availableActionCodes包含CHANGE_ASSIGNMENT时另行显示“改派”,点击进入第 2 步重新选择车辆或司机;- 两个按钮不得互相替代:“继续派车”推进当前有效派单,“改派”修改当前有效派单;
- “复制行程单链接”是独立只读能力,复制后端为当前有效派单签发的司机 H5 链接,不参与派单状态流转。
当前 v2.1@6e6a11bf 的 resolveBoardRowActions() 仍检查已经废弃的 CONFIRM 动作码,而后端生命周期实际下发 RECORD_DRIVER_CONFIRMATION,因此截图中“继续派车/司机已确认”按钮没有渲染。前端改为消费真实动作码即可,无需后端增加兼容别名。
看板复制司机 H5 行程单链接
看板不再维护独立的“发行程单”抽屉,也不在前端模拟发送成功。这里不是打开订单详情的“打印行程单”,而是把后端已经为当前有效派单签发的 H5 链接复制到剪贴板,车务再通过微信等渠道发给司机。司机可在手机浏览器中独立打开,不需要登录管理后台。
- 将看板按钮文案由“发行程单”改为“复制行程单链接”,事件名同步改为
copy-itinerary-link,避免继续表达成“发送”; - 点击时先调用既有看板详情接口
GET /admin/fleet/board/orders/{orderId},不要调用订单打印接口; - 默认复制
currentAssignment.itineraryUrl;如果入口明确针对某一条有效派单,则复制对应activeAssignments[].itineraryUrl; - 链接必须直接使用后端返回值,前端不得自行拼接 H5 地址、token、订单 ID 或派单 ID;
- 优先使用
navigator.clipboard.writeText(itineraryUrl);当前管理后台可能运行在 HTTP 内网环境,必须同时提供临时textarea + document.execCommand('copy')降级实现; - 复制成功提示“行程单链接已复制,可发送给司机”;
itineraryUrl为空时不得复制或提示成功,应提示“行程单链接暂不可用,请确认已派车且 H5 配置正常”;- 删除/停用看板自己的
ItinerarySendSheet.vue、消息模板和本地message.success('已发送行程单')假流程; - 不复用
PrintItineraryModal.vue,不调用GET /v3/admin/order/{orderId}/print-itinerary;订单详情的“打印行程单”继续作为面向车务的独立打印能力保留; - 链接包含签名 token,前端日志、埋点和错误提示不得记录或展示完整 URL;
- 改派成功后必须重新拉取详情并使用新派单的
itineraryUrl,不能继续缓存或复制旧派单链接。
后端链接已绑定当前订单与具体派单,有效期至行程结束后 7 天;公开 H5 接口会校验签名、有效期和派单归属,并实时读取行程数据。复制动作本身不改变派单状态,也不产生“已发送”记录。
建议前端按以下逻辑落地(函数名可按现有工程调整):
async function onCopyItineraryLink(order: BoardOrder) {
const orderId = resolveBoardOrderId(order)
const detail = await getBoardOrderDetail(orderId)
const itineraryUrl = detail.currentAssignment?.itineraryUrl?.trim()
if (!itineraryUrl) {
message.error('行程单链接暂不可用,请确认已派车且 H5 配置正常')
return
}
try {
if (navigator.clipboard && window.isSecureContext) {
await navigator.clipboard.writeText(itineraryUrl)
} else {
copyTextByTextarea(itineraryUrl)
}
message.success('行程单链接已复制,可发送给司机')
} catch {
message.error('复制失败,请稍后重试')
}
}
function copyTextByTextarea(text: string) {
const textarea = document.createElement('textarea')
textarea.value = text
textarea.setAttribute('readonly', '')
textarea.style.position = 'fixed'
textarea.style.opacity = '0'
document.body.appendChild(textarea)
textarea.select()
const copied = document.execCommand('copy')
document.body.removeChild(textarea)
if (!copied) throw new Error('copy failed')
}
三、不影响范围
canRejectRequirement仍只在未派阶段可能为true;排车中不得重新开放“驳回用车需求”。- 已派车、已完成、已取消状态不会因本次变更开放派车入口。
- 无数据库、Redis、MQ、候选请求字段或错误码变更。
四、前端自测清单
holding订单显示“改派”按钮,点击后带出当前司机、车辆并进入调整流程。holding_urgent同样显示“改派”并进入调整流程。holding/holding_urgent + CHANGE_ASSIGNMENT卡片按钮显示“改派”,打开后直接高亮第 2 步“排车”,第 1 步为已完成。- 首次待派车仍从第 1 步开始;
confirmHold仍恢复第 3/4 步,三种入口互不串态。 holding/holding_urgent在卡片、筛选、汇总和图例统一显示“待确认/待确认即将超时”,页面不再出现“排车中”旧文案。- 技术状态值仍为
holding,改派、司机确认和超时判断不因文案变化而改变。 - 待确认订单在
RECORD_DRIVER_CONFIRMATION可用时显示“继续派车”,点击以confirmHold恢复第 3/4 步。 - “继续派车”和“改派”同时存在且职责分离;前端不再检查不存在的
CONFIRM动作码。 - 待确认或已派车且存在当前有效派单时,看板显示“复制行程单链接”。
- 点击后通过看板详情取得并复制
currentAssignment.itineraryUrl,不调用订单打印接口、不在前端拼接链接。 - HTTPS/localhost 使用 Clipboard API,HTTP 内网环境可通过降级方案正常复制。
- 复制成功提示“行程单链接已复制,可发送给司机”;链接为空或复制失败时给出明确错误且不误报成功。
- 复制出的链接可由司机在手机浏览器中独立打开,无需登录管理后台,并展示当前派单的实时行程。
- 看板不再使用
ItinerarySendSheet或模拟“已发送行程单”,改派后不会复制旧派单链接。 - 打开排车步骤时,候选请求同时携带字符串
orderId、requirementId和当前fleetItemIndex,不再出现“改派候选查询必须携带当前订单ID、用车需求ID和车型项索引”。 - 提交时调用既有
changeAssignment,不调用创建派单接口。 assigned、completed、canceled不误显示入口。- 调整成功后刷新看板,页面只保留一组当前有效派单。
验证证据
- 后端提交:
aaeb01242;PR:wx/HL#5190,已合并dev-v3。 - 状态矩阵、生命周期动作、改派上下文及排车中改派保护已有定向测试覆盖;
BoardOrderServiceTest与BoardControllerTest共 49 项通过。 mvn -f hl-fleet-service/pom.xml spotless:check通过。mvn -pl hl-fleet-service -am verify通过。- 测试环境 Fleet 滚动部署任务
3458b3ab成功,8087、8187 两实例健康。 - 网关按团号
26-7042验证:列表与详情 HTTP/code 200,requirementId在列表、详情顶层、currentAssignment和activeAssignments[]均存在;携带orderId + requirementId + fleetItemIndex + excludeAssignmentId调用候选接口 HTTP/code 200,返回 19 辆车、19 名司机候选。 - 当前前端
v2.1已从order.requirementId组装候选请求;但截至v2.1@6e6a11bf,resolveAssignFlowRestoreState对reassign仍固定恢复第 1 步,且排车中入口文案仍为“派车派人”,需要按上方状态规则调整。