--- schema: "hl-changelog/v2" ticket: "5862" title: "派单操作日志补全操作人、操作时间与改派资源快照" consumer: "admin" author: "lc(GIT)" change_type: "修改接口" backend_status: "deployed" gateway_status: "verified" frontend_status: "not_required" frontend_owner: "" frontend_ref: "" target_release: "" verified_at: "" status_note: "PR #5869 已合入 dev-v3 并部署 TEST;真实登录经 Gateway 验证操作时间、操作人、动作摘要及历史改派降级契约。现有管理端可直接展示,无前端代码变更。" updated_at: "2026-08-11" base: "dev-v3" --- # 车务派单:操作日志补全操作人、操作时间与改派资源快照 > **服务**: hl-fleet-service(8087) > **PR**: #5869 > **Issue**: #5862 > **日期**: 2026-08-11 > **影响范围**: 管理端车务看板订单详情和“查看日志”中的派单操作记录 --- ## ⚠️ 关键变化 - 操作日志现在稳定返回 `time`、`operatorName`、`opTypeLabel` 和 `summary`,操作人按“企业微信姓名 → 系统用户名 → 系统”的顺序解析。 - 改派日志新增结构化 `changeDetail`。新日志保存操作当时的新旧车牌、司机姓名快照,不再要求调用方解析 `detailJson` 中的 ID 后查询当前车辆或司机档案。 - 历史日志没有快照时保持兼容:展示字段允许按 ID 查询当前档案,`dataCompleteness` 明确返回 `HISTORICAL_PARTIAL`,不得把当前档案值误认为操作时快照。 ## 一、变更接口清单 | # | 接口 | 方法 | 路径 | 变更类型 | 说明 | |---|---|---|---|---|---| | 1 | 派单操作时间线 | GET | `/admin/fleet/orders/{orderId}/operation-log` | 响应增强 | 日志行补全操作信息与结构化改派详情 | | 2 | 车务看板订单详情 | GET | `/admin/fleet/board/orders/{orderId}` | 响应增强 | `operationLog.records[]` 同步返回相同字段 | 两个接口沿用原有路径、鉴权和分页契约,不新增请求字段。 ## 二、接口详情 ### 1. 派单操作时间线 `GET /admin/fleet/orders/{orderId}/operation-log` **响应模型**: `Result` #### 入参 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | |---|---|---|---|---|---| | orderId | Path | String | 是 | Long 字符串 | 订单 ID | | page | Query | Integer | 否 | 默认 1 | 页码 | | pageSize | Query | Integer | 否 | 默认 50,最大 200 | 每页条数 | | sortBy | Query | String | 否 | `time,desc` / `time,asc` | 默认按操作时间倒序 | | keyword | Query | String | 否 | 最长 32 字 | 按展示后的摘要、操作人等内容搜索 | | startDate | Query | LocalDateTime | 否 | ISO 8601 | 操作时间起点 | | endDate | Query | LocalDateTime | 否 | ISO 8601 | 操作时间终点 | #### 日志行出参 | 字段 | 类型 | 说明 | |---|---|---| | id | String / null | 日志 ID;合成里程碑记录可为 null | | time | String | 操作时间,格式 `yyyy-MM-dd HH:mm:ss` | | opType | String | 操作类型英文枚举 | | opTypeLabel | String | 可直接展示的中文动作名称 | | summary | String | 后端生成的操作摘要,改派时包含前后资源和生效日 | | operatorName | String | 企业微信姓名优先,无企业微信姓名时使用系统用户名;自动任务为“系统” | | effectiveDate | String / null | 生效日期,格式 `yyyy-MM-dd` | | detailJson | String / null | 兼容保留的原始明细 JSON,不建议前端再自行解析 ID | | changeDetail | Object / null | 改派结构化详情;非改派动作返回 null | #### `changeDetail` 字段 | 字段 | 类型 | 说明 | |---|---|---| | changeDimensions | String[] | 变更维度:`VEHICLE`、`DRIVER`、`VEHICLE_FEE` | | previousVehicleId / newVehicleId | String / null | 原车、新车 ID | | previousVehiclePlateSnapshot / newVehiclePlateSnapshot | String / null | 操作当时的原车牌、新车牌快照;历史无快照时为 null | | previousVehiclePlate / newVehiclePlate | String / null | 展示值;优先使用快照,历史数据才按 ID 降级查询当前档案 | | previousDriverId / newDriverId | String / null | 原司机、新司机 ID | | previousDriverNameSnapshot / newDriverNameSnapshot | String / null | 操作当时的原司机、新司机姓名快照;历史无快照时为 null | | previousDriverName / newDriverName | String / null | 展示值;优先使用快照,历史数据才按 ID 降级查询当前档案 | | effectiveDate / endDate | String / null | 本次变更的生效日和结束日 | | previousUsedDays | Integer / null | 生效日前原资源在同一槽位已使用的有效服务日数;历史未知为 null | | affectedServiceDates | String[] | 本次实际变更的服务日期,支持非连续日期集合 | | affectedDays | Integer / null | 本次实际变更服务日数;历史未知为 null | | reason | String / null | 变更原因 | | dataCompleteness | String | `COMPLETE` 或 `HISTORICAL_PARTIAL` | #### 完整快照响应示例 ```json { "code": 200, "message": "成功", "data": { "records": [ { "id": "2086386125831561218", "time": "2026-08-11 15:05:14", "opType": "change_completed", "opTypeLabel": "修改派单完成", "summary": "lc 修改派单完成:蒙A-E2E99王信 → 蒙A-E2E01道尔吉,生效日 2026-08-23", "operatorName": "lc", "effectiveDate": "2026-08-23", "detailJson": "{...}", "changeDetail": { "changeDimensions": ["VEHICLE", "DRIVER"], "previousVehicleId": "2086000000000000001", "previousVehiclePlateSnapshot": "蒙A-E2E99", "previousVehiclePlate": "蒙A-E2E99", "previousDriverId": "2086000000000000002", "previousDriverNameSnapshot": "王信", "previousDriverName": "王信", "newVehicleId": "2086000000000000003", "newVehiclePlateSnapshot": "蒙A-E2E01", "newVehiclePlate": "蒙A-E2E01", "newDriverId": "2086000000000000004", "newDriverNameSnapshot": "道尔吉", "newDriverName": "道尔吉", "effectiveDate": "2026-08-23", "endDate": "2026-08-25", "previousUsedDays": 2, "affectedServiceDates": ["2026-08-23", "2026-08-24", "2026-08-25"], "affectedDays": 3, "reason": "调整车辆与司机", "dataCompleteness": "COMPLETE" } } ], "total": 1, "page": 1, "pageSize": 50 }, "success": true } ``` #### 历史日志降级示例 ```json { "previousVehiclePlateSnapshot": null, "previousVehiclePlate": "蒙A-E2E99", "previousDriverNameSnapshot": null, "previousDriverName": "王信", "newVehiclePlateSnapshot": null, "newVehiclePlate": "蒙A-E2E01", "newDriverNameSnapshot": null, "newDriverName": "道尔吉", "previousUsedDays": null, "affectedServiceDates": [], "affectedDays": null, "dataCompleteness": "HISTORICAL_PARTIAL" } ``` ### 2. 车务看板订单详情 `GET /admin/fleet/board/orders/{orderId}` 订单详情原有 `operationLog.records[]` 复用上述日志行模型。本次同步增加并补全 `time`、`opTypeLabel`、`summary`、`operatorName` 和 `changeDetail`,字段含义及历史降级规则与独立操作时间线接口一致。 ## 三、修改前后对比 ### 字段级对比 | 字段 | 修改前 | 修改后 | |---|---|---| | time | 部分操作记录展示字段不完整 | 每条可展示记录返回标准操作时间 | | operatorName | 可能只有泛化角色名或缺失 | 企业微信姓名优先,系统用户名兜底,自动任务显示“系统” | | summary / opTypeLabel | 动作信息不完整或需要调用方拼装 | 返回中文动作名称和可直接展示的完整摘要 | | detailJson | 调用方需解析车辆、司机 ID,且查询结果会受当前档案变化影响 | 兼容保留,不再作为稳定展示契约 | | changeDetail | 无 | 返回新旧车辆、司机、使用天数、影响日期及完整性标记 | | 车牌与司机姓名 | 可能展示当前档案值,无法证明操作当时名称 | 新日志保存操作时快照;历史日志明确标记降级状态 | ### 行为级对比 | 场景 | 修改前 | 修改后 | |---|---|---| | 操作人展示 | 可能无法识别具体人员 | 企微姓名优先,无企微姓名时显示系统用户名 | | 换车或换司机 | 仅凭 ID 无法稳定还原前后资源 | 直接返回操作当时的新旧车牌与司机姓名快照 | | 历史无快照 | 容易把当前档案误当作历史事实 | 可降级展示,但通过 `HISTORICAL_PARTIAL` 明确说明不完整 | | 车辆费用单独变化 | 可能被误写成换车或换司机 | `changeDimensions` 单独标记 `VEHICLE_FEE`,动作摘要按实际维度生成 | ## 四、契约约束与兼容边界 - 调用方应优先读取结构化 `changeDetail`;`detailJson` 仅为兼容字段,不保证适合作为长期展示数据源。 - `*Snapshot` 是操作时事实;不带 `Snapshot` 的车牌、司机展示字段可能是历史数据按 ID 查询当前档案后的降级值。 - 只有本次操作应保存的车牌和司机姓名快照均齐全时,`dataCompleteness` 才返回 `COMPLETE`;存量日志不会伪造快照。 - 仅变更车辆、仅变更司机、同时变更车辆与司机、仅变更车辆费用,均以 `changeDimensions` 的实际值为准。 - ID 按字符串返回,调用方不得转换为 JavaScript Number。 - 本次不改变接口路径、请求参数、权限、分页、排序和统一 `Result` 响应结构。 - 快照仅包含车牌和司机姓名,不新增手机号、证件号或其他敏感信息。 ## 五、前端影响 `frontend_status=not_required`。现有管理端已经可以直接展示操作时间、操作人和后端摘要,本次 TEST 页面已看到“原车牌/原司机 → 新车牌/新司机”的改派结果,无需同步修改前端代码。其他调用方如仍解析 `detailJson`,应逐步改为优先消费 `changeDetail`。 ## 六、验证与测试证据 - PR #5869 已合入 `dev-v3`,合并提交:`2d9c6ba4f8af1ad997b8b6e3ba7d215b9754ae66`;TEST 的 Fleet 服务双实例健康。 - 使用真实登录身份经 TEST Gateway 调用 `GET /admin/fleet/orders/{orderId}/operation-log` 返回 200。订单 `26-3420` 的 10 条记录均具有非空操作时间、动作、操作人和摘要。 - TEST 管理端订单 `26-6436` 的日志页面直接展示 `蒙A-E2E99/王信 → 蒙A-E2E01/道尔吉`、动作、生效日、操作人和时间。 - 同一订单 3 条存量改派记录均返回 `HISTORICAL_PARTIAL`,且 `changeDetail` 快照、展示值、使用天数和受影响日期等契约字段完整存在,历史无快照字段保持 null。 - #5862 定向自动化测试 620 项通过;Fleet 扩大测试 3604 项通过、0 失败、0 错误、7 跳过;固定端口 MySQL 集成测试 11/11 通过。 - 为避免通知、派单和审计副作用,TEST 验收未提交新的改派操作;新写日志 `COMPLETE` 快照路径由自动化测试覆盖,测试业务数据状态未改变。 - 工单验收标准 14/14 已勾选,验收记录已写入,Issue #5862 已关闭。 ## 七、不影响范围 - 不新增或修改数据库结构。 - 不修改管理端、小程序、H5 或其他前端代码。 - 不改变派单状态机、派单确认、司机通知、保险、结算和车辆费用计算规则。 - 不回填或改写历史日志;历史记录只做只读降级展示。 ## 关联 - Issue: #5862 - PR: #5869 - 后端合并提交: `2d9c6ba4f8af1ad997b8b6e3ba7d215b9754ae66` - 联系人: @lc