--- schema: "hl-changelog/v2" ticket: "8621" title: "派车三个读口补齐状态中文名,枚举码不再裸下发(含 #8620 用车控制状态口径澄清)" consumer: "admin" author: "wx(GIT)" change_type: "修改接口" backend_status: "deployed" gateway_status: "not_required" frontend_status: "not_required" frontend_owner: "" frontend_ref: "" target_release: "" verified_at: "" status_note: "三个既有管理后台读口各新增中文名字段,纯新增、无删除、无改名、无取值变化:(1) GET /admin/fleet/board/orders 的 records[] 新增 baseAssignmentStatusLabel(代表日行落库派单态中文名,与既有 baseAssignmentStatus 恒成对非空;它与 assignmentStatusLabel 是两个不同口径——前者是落库态、不含派生态,后者是覆写后的有效态、会出现临期加急派生态);(2) GET /admin/fleet/group-dispatch/pending-batches 的 records[] 新增 batchStatusName(团期生命周期状态中文名,九态全覆盖)与 dispatchProgressLabel(配车进度中文名,未开始/部分排车/已排满);(3) GET /admin/fleet/group-dispatch/batches/{groupBatchId}/overview 的 days[].vehicles[] 新增 statusLabel(派车状态中文名,已派车/已确认,字典另含已取消)。三个字典的共同不变量:码为 null 则中文名为 null(不编默认文案),码非空则中文名必非空;未登记的新码原样回落成码本身,不抛异常也不返回 null——所以前端渲染时不要假设这一格一定是中文,但不必为未知码写空值兜底。这批字段存在的唯一目的是把码→中文的字典收成后端单源(CODE_RULES §15.7),前端本地映射表请改为直接渲染后端下发值:本地表在遇到未登记新码时会显示空白,后端值至少是码本身。同时随 #8620 澄清一条既有字段的读法(字段名与取值零变化):orders[].vehicleControlStatus 是订单级单值、行程用车与接送机两类共用一格,非 DONE 只代表两类里至少一类没齐、说不出是哪一类;要分辨哪类没齐请读同级按类别拆开的字段(travelRequirementStatus / transferDeclared / transferPendingCount)。三个端点的入参、分页、过滤、排序、错误码(100001 / 600012 / 600013 / 401)与其余响应字段均未变化。" updated_at: "2026-09-30" base: "dev-v3" --- # 车务派车读口:状态中文名补齐,枚举码不再裸下发 > **存放目录**: 二期(order-v3/fleet)→ `changelogs-v2/2026-09/` ## ⚠️ 关键变化 - **三个既有读口共新增 4 个中文名字段,纯新增**:`records[].baseAssignmentStatusLabel`(派单看板订单清单)、`records[].batchStatusName` + `records[].dispatchProgressLabel`(待配车团期清单)、`days[].vehicles[].statusLabel`(团期配车总览)。 - **既有字段一个没动**:`assignmentStatus` / `assignmentStatusLabel` / `baseAssignmentStatus` / `batchStatus` / `dispatchProgress` / `vehicles[].status` 的字段名、类型、取值域、语义与本次改动前逐字相同;入参、分页、过滤、排序、错误码也未变。 - **三个字典共用同一组不变量**:码为 `null` ⇒ 中文名同为 `null`(不编默认文案);码非空 ⇒ 中文名必非空;**未登记的新码原样回落成码本身**,既不抛异常也不返回 `null`。所以前端**不需要**为「没见过的码」写空值兜底分支,但**渲染时不要假设这一格一定是中文**(回落时它就是那个码)。 - **前端请停用本地的码 → 中文映射表**,直接渲染后端下发的中文名字段。本地表在遇到未登记新码时渲染成空白,而后端值至少是码本身;这批字段存在的唯一理由就是把字典收成后端单源(CODE_RULES §15.7)。 - 🔴 **`baseAssignmentStatusLabel` 与 `assignmentStatusLabel` 不是一回事,别混用**:前者是**落库态**中文名(不派生、不被当前需求口径覆写,永远是 6 个落库态之一),后者是**覆写后的有效态**中文名(可能对应 `unassigned_urgent` / `holding_urgent` 这类派生态)。要展示「落库态 vs 有效态」并排对照(陈旧定稿排查场景)才需要前者;常规状态列继续用后者。 - 🔴 **`vehicleControlStatus` 是订单级单值、两类共用一格**(#8620,本次只澄清读法,字段与取值零变化):它非 `DONE` 只说明「行程用车与接送机里至少一类没齐」,**说不出是哪一类**。要分辨请读同级按类别拆开的字段(`travelRequirementStatus` / `transferDeclared` / `transferPendingCount`)。 - **`CANCELLED`(已取消)在派车状态字典里有中文名**。团期配车总览的逐车项 `status` 正常只会出现 `ASSIGNED` / `CONFIRMED`(已取消的派车行不进总览),但字典三码全覆盖,前端若自行构造筛选项按两值即可。 ## 一、背景(选填) 这批读口此前把枚举码裸下发:`baseAssignmentStatus`、`batchStatus`、`dispatchProgress`、`vehicles[].status` 四处只有码、没有中文名,而同一行上别的状态字段(如 `assignmentStatusLabel`、`requirementKindLabel`)早已由后端下发中文名。结果是前端必须在本地再维护一份码 → 中文的映射表,这份表与后端枚举是两份真源:后端加一个码,前端那格就渲染成空白,而且没有任何信号提示。本次把这四处补齐成「码 + 中文名成对下发」,字典的唯一来源放在后端枚举里。 ## 二、变更接口清单 | # | 接口 | 方法 | 路径 | 变更类型 | 说明 | |---|------|------|------|----------|------| | 1 | 派单看板订单清单 | GET | `/admin/fleet/board/orders` | 修改 | `records[]` 新增 `baseAssignmentStatusLabel`(落库派单态中文名) | | 2 | 待配车团期清单 | GET | `/admin/fleet/group-dispatch/pending-batches` | 修改 | `records[]` 新增 `batchStatusName`(团期状态中文名)与 `dispatchProgressLabel`(配车进度中文名) | | 3 | 团期配车总览 | GET | `/admin/fleet/group-dispatch/batches/{groupBatchId}/overview` | 修改 | `days[].vehicles[]` 新增 `statusLabel`(派车状态中文名);`orders[].vehicleControlStatus` 读法澄清(#8620) | ## 三、接口详情 ### 1. 派单看板订单清单 `GET /admin/fleet/board/orders` **VO**: `BoardOrderPageReqVO → BoardOrderPageRespVO` #### 使用场景 车务派单看板的订单清单(list / grid 两视图共用)。本次变更只在每行上多给一个中文名字段,供「落库态 vs 有效态」并排展示的排查场景使用;常规状态列继续用 `assignmentStatusLabel`。 #### 入参 入参本次**零变化**,为便于自洽联调完整列出(全部 query 参数,全部选填)。 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | |------|------|------|------|------|------| | statuses | query | String[] | 否 | `unassigned` / `unassigned_urgent` / `holding` / `holding_urgent` / `assigned` / `canceled` / `completed` | 多状态筛选,含派生态,任一命中即返;空=不过滤 | | status | query | String | 否 | 同 `statuses` 取值域 | `statuses` 的别名,单值或逗号分隔,与 `statuses` 合并 | | startDayFrom | query | LocalDate | 否 | `YYYY-MM-DD` | 日期区间起,与行程区间重叠(非仅出团日);单边只约束一侧 | | startDayTo | query | LocalDate | 否 | `YYYY-MM-DD` | 日期区间止 | | startDate | query | LocalDate | 否 | `YYYY-MM-DD` | `startDayFrom` 的兼容别名,未传 `startDayFrom` 时生效 | | endDate | query | LocalDate | 否 | `YYYY-MM-DD` | `startDayTo` 的兼容别名,未传 `startDayTo` 时生效 | | vehicleTypeKeys | query | String[] | 否 | — | 车型大类多选;未派按需求车型、已派按实际车辆大类过滤 | | typeKeys | query | String[] | 否 | — | `vehicleTypeKeys` 的兼容别名,未传前者时生效 | | driverName | query | String | 否 | — | 司机姓名模糊搜索 | | keyword | query | String | 否 | — | 统一文字搜索:司机 / 联系人 / 团号 / 订单号 / 当前定制师显示名任一包含 | | contactName | query | String | 否 | — | 联系人(客户名)模糊搜索 | | contactKeyword | query | String | 否 | — | `contactName` 的兼容别名 | | teamNo | query | String | 否 | — | 团号模糊搜索(仅匹配真实团号,不匹配订单号) | | groupBatchId | query | Long | 否 | — | 运营团期 ID 精确筛选 | | orderKind | query | String | 否 | `ALL` / `NORMAL` / `GROUP`,其余值返 100001 | 订单归属粗筛;不传或空串=`ALL`。`NORMAL` 与 `groupBatchId` 同传逻辑互斥,返空列表不报错 | | requirementKind | query | String | 否 | `TRAVEL` / `TRANSFER`,其余值返 100001 | 用车需求类别筛选;不传或空串=不过滤 | | consultantId | query | Long | 否 | — | 当前负责定制师管理员 ID 精确筛选(下拉值由看板汇总接口下发) | | plannerName | query | String | 否 | — | 定制师姓名模糊搜索(兼容旧前端) | | consultantName | query | String | 否 | — | `plannerName` 的别名 | | variant | query | String | 否 | `list`(默认)/ `grid`,其余值返 100001 | 视图 | | page | query | Integer | 否 | ≥ 1,默认 1 | 页码;`pageNo` 是其兼容别名 | | pageSize | query | Integer | 否 | 1~100,默认 20 | 每页条数 | #### 出参 `Result` 只列与本次变更直接相关的字段;`records[]` 其余字段与本次改动前完全一致。 | 字段 | 类型 | 说明 | |------|------|------| | records | Array | 订单行列表,维度=当前有效用车需求;同一 `requirementId` 只返回一条 | | records[].assignmentStatus | String | 当前派单状态码(含派生 `unassigned_urgent` / `holding_urgent`,会按当前需求口径覆写);**未变** | | records[].assignmentStatusLabel | String | 当前派单状态中文名(有效态口径);**未变** | | records[].baseAssignmentStatus | String | 代表日行落库基础状态码(不派生、不覆写):`unassigned` / `holding` / `assigned` / `canceled` / `exception` / `completed`;**未变** | | records[].baseAssignmentStatusLabel | String | 🆕 落库基础状态中文名,与 `baseAssignmentStatus` 恒成对非空:待派车 / 待确认执行 / 已派车 / 已取消 / 异常 / 已完结。**永远不会出现派生态对应的文案**(派生态只进 `assignmentStatus`);未登记码原样回落成码本身 | | total | Long | 总条数 | | page | Integer | 当前页码 | | pageSize | Integer | 每页条数 | #### 请求示例 ```http GET /admin/fleet/board/orders?variant=list&startDayFrom=2026-10-01&startDayTo=2026-10-31&page=1&pageSize=20 Authorization: Bearer {token} ``` #### 响应示例 ```json { "code": 200, "message": "成功", "data": { "records": [ { "id": "2103998277441093633", "orderNo": "HL202610080031", "teamNo": "T26-4128", "orderId": "2103998277441093632", "customerName": "周雅", "headcount": 4, "startDate": "2026-10-08", "endDate": "2026-10-12", "requirementKind": "TRAVEL", "requirementKindLabel": "行程用车", "assignmentStatus": "unassigned_urgent", "assignmentStatusLabel": "待派车", "baseAssignmentStatus": "unassigned", "baseAssignmentStatusLabel": "待派车", "manualUrgent": false, "canAssign": true } ], "total": 1, "page": 1, "pageSize": 20 }, "success": true } ``` #### 空数据 / 降级响应 - 无命中:`data.records` 返回空数组 `[]`,`total` 为 `0`,不返回 `null`,不报错。 - `records[]` 有行时 `baseAssignmentStatus` 与 `baseAssignmentStatusLabel` **必定同时非空**:落库态取自派单行的 `assignment_status`(NOT NULL);订单还没有落库派单行时走虚拟待派卡,落库态固定 `unassigned`、中文名固定「待派车」,不会出现「有码没中文名」或「有中文名没码」的半边状态。 - `order-v3` 整体不可达时,行上的日期、紧急态、排序会回退派单快照口径(本次未改这条既有降级路径),`baseAssignmentStatusLabel` 仍照常下发(它只依赖 fleet 本域落库行)。 #### 错误响应 ```json { "code": 100001, "message": "参数非法: variant 仅支持 list/grid,传入非法值:card", "data": null, "success": false } ``` - `100001 参数非法: {0}`:`variant` 非 `list`/`grid`、`orderKind` 非 `ALL`/`NORMAL`/`GROUP`、`requirementKind` 非 `TRAVEL`/`TRANSFER`、`page` < 1、`pageSize` 越界。 - `401`:未登录或令牌失效。注意测试环境网关对失效令牌返回 **HTTP 200 + 信封 `code: 401`**,前端拦截器请按信封 `code` 判定,不要只看 HTTP 状态行。 #### 业务边界 - `baseAssignmentStatusLabel` 与 `assignmentStatusLabel` 走**同一份**映射(`AssignmentStatusEnum.labelOf`),只是喂进去的码不同:前者喂落库态、后者喂覆写后的有效态。所以同一行上两个中文名可能不同(例:落库 `assigned`「已派车」而有效态被当前需求口径覆写成「待派车」),**这不是数据错误**,正是本字段要暴露的对照。 - 派生态 `unassigned_urgent` / `holding_urgent` 只出现在 `assignmentStatus`,`baseAssignmentStatus` 与其中文名永远是 6 个落库态之一。前端若拿 `baseAssignmentStatusLabel` 当加急标识会永远读不到加急,加急请读 `assignmentStatus` 或 `manualUrgent` / `urgentBadge`。 - 落库态 `exception`(异常)在筛选入参 `statuses` 的取值域里**没有**对应筛选项,但它会作为 `baseAssignmentStatus` 的值出现在响应里,中文名「异常」。 - 中文名不参与任何筛选与排序,只是展示字段;按状态筛选一律传码。 --- ### 2. 待配车团期清单 `GET /admin/fleet/group-dispatch/pending-batches` **VO**: `GroupDispatchPendingBatchPageReqVO → PageResult` #### 使用场景 车务「待配车团期」列表页。本次每行多给两个中文名:团期生命周期状态与配车进度,前端可直接渲染,不再需要本地两张映射表。 #### 入参 入参本次**零变化**,完整列出。 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | |------|------|------|------|------|------| | departDateFrom | query | LocalDate | 否 | `YYYY-MM-DD` | 出发日区间起;单边只约束一侧 | | departDateTo | query | LocalDate | 否 | `YYYY-MM-DD` | 出发日区间止 | | keyword | query | String | 否 | 长度 ≤ 50,超长返 600013 | 团号 / 团期名称模糊搜索 | | dispatchProgress | query | String | 否 | `NOT_STARTED` / `PARTIAL` / `FULL`,其余值返 600013 | 按配车进度筛选;不传=不过滤 | | page | query | Integer | 否 | ≥ 1,默认 1 | 页码 | | pageSize | query | Integer | 否 | 1~100,默认 20 | 每页条数 | #### 出参 `Result>` | 字段 | 类型 | 说明 | |------|------|------| | records | Array | 待配车团期行列表 | | records[].groupBatchId | String | 运营团期 ID(雪花 ID 以字符串下发) | | records[].batchNo | String | 团号 | | records[].batchName | String | 团期名称 | | records[].batchStatus | String | 团期生命周期状态码;**未变** | | records[].batchStatusName | String | 🆕 团期状态中文名,与 `batchStatus` 恒成对非空。九态见「六.5」;未登记码原样回落成码本身 | | records[].departDate | String | 出发日 `YYYY-MM-DD` | | records[].endDate | String | 结束日 `YYYY-MM-DD` | | records[].serviceDayCount | Integer | 服务天数 | | records[].enrolledOrders | Integer | 已报名子订单数 | | records[].enrolledPeople | Integer | 已报名人数 | | records[].requirementConfirmed | Boolean | 团期用车需求是否已确认 | | records[].vehicleReady | Boolean | 车辆是否已就绪 | | records[].dispatchedDayCount | Integer | 已排车天数 | | records[].dispatchProgress | String | 配车进度码:`NOT_STARTED` / `PARTIAL` / `FULL`;**未变** | | records[].dispatchProgressLabel | String | 🆕 配车进度中文名,与 `dispatchProgress` 恒成对非空:未开始 / 部分排车 / 已排满 | | records[].transferPendingCount | Integer | 接送机未配计数;`null` = 未取到(**不是 0**,#8593) | | records[].unreadCount | Integer | 未读会话消息数;依赖服务不可达时退化为 `0` | | total | Long | 总条数 | | page | Integer | 当前页码 | | pageSize | Integer | 每页条数 | #### 请求示例 ```http GET /admin/fleet/group-dispatch/pending-batches?departDateFrom=2026-10-01&departDateTo=2026-10-31&dispatchProgress=PARTIAL&page=1&pageSize=20 Authorization: Bearer {token} ``` #### 响应示例 ```json { "code": 200, "message": "成功", "data": { "records": [ { "groupBatchId": "2104839654727618562", "batchNo": "T26-3963", "batchName": "呼伦贝尔环线 10/06 团", "batchStatus": "RESOURCE_PREPARING", "batchStatusName": "资源准备中", "departDate": "2026-10-06", "endDate": "2026-10-10", "serviceDayCount": 5, "enrolledOrders": 6, "enrolledPeople": 18, "requirementConfirmed": false, "vehicleReady": false, "dispatchedDayCount": 2, "dispatchProgress": "PARTIAL", "dispatchProgressLabel": "部分排车", "transferPendingCount": 1, "unreadCount": 3 } ], "total": 1, "page": 1, "pageSize": 20 }, "success": true } ``` #### 空数据 / 降级响应 - 无命中:`records` 为空数组 `[]`,`total` 为 `0`。 - `batchStatusName` 由 order-v3 随团期候选项一起下发,fleet **原样透传、不在本域二次映射**(避免两份字典)。团期状态码为 `null` 时该中文名同为 `null`,后端不编默认文案;前端遇到这一格为 `null` 时请渲染成空白或「—」,不要回填「未知」这类自造文案。 - `dispatchProgressLabel` 与 `dispatchProgress` 在同一次判定里算出,不存在「码与文案分别算出来后对不上」的窗口,二者恒一致。 - `transferPendingCount` 的 `null` 与 `unreadCount` 的 `0` 是两条互相独立的软依赖退化路径,任一退化都不影响本次新增的两个中文名字段。 #### 错误响应 ```json { "code": 600013, "message": "排班查询参数非法: dispatchProgress 仅支持 NOT_STARTED/PARTIAL/FULL", "data": null, "success": false } ``` - `600013 排班查询参数非法: {0}`:`dispatchProgress` 取值非法、`keyword` 超长、分页参数越界。 - `600012 团期配车基线不可达,请稍后重试`:团期基线数据读不到;本端点不会用空列表冒充成功。 - `401`:未登录或令牌失效(网关返 HTTP 200 + 信封 `code: 401`)。 #### 业务边界 - 中文名只用于展示。`dispatchProgress` 入参筛选仍只接受码(`NOT_STARTED` / `PARTIAL` / `FULL`),传中文名会按非法值返 600013。 - 团期状态字典是 order-v3 的九态全集(见「六.5」),本列表按「待配车」语义筛选后实际只会出现其中一部分;前端若要构造状态筛选下拉,请从本列表返回值里去重收集,不要按九态硬编码全集。 - `batchStatusName` 与团期管理列表页(order-v3 团期分页)的同名字段来自**同一个**转换方法,两页面上同一个团期的状态文案恒一致。 - 未登记的团期状态码回落成码本身(不抛异常),所以这一格可能出现英文码——前端不需要兜底,但列宽与换行请按可能出现英文码来设计。 --- ### 3. 团期配车总览 `GET /admin/fleet/group-dispatch/batches/{groupBatchId}/overview` **VO**: `Long groupBatchId(路径参数)→ GroupDispatchOverviewRespVO` #### 使用场景 单个团期的配车总览:逐服务日的车辆卡片 + 本团子订单的用车控制状态。本次在逐车项上补齐派车状态中文名,并澄清 `orders[].vehicleControlStatus` 的读法(#8620)。 #### 入参 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | |------|------|------|------|------|------| | groupBatchId | path | Long | 是 | 雪花 ID,正整数 | 运营团期 ID | #### 出参 `Result` 只列与本次变更直接相关的字段;其余字段与本次改动前完全一致。 | 字段 | 类型 | 说明 | |------|------|------| | groupBatchId | String | 运营团期 ID(字符串下发) | | batchNo | String | 团号 | | days | Array | 逐服务日节点 | | days[].tripDate | String | 服务日 `YYYY-MM-DD` | | days[].vehicles | Array | 该日已排车辆项 | | days[].vehicles[].dispatchId | String | 派车行 ID | | days[].vehicles[].vehiclePlate | String | 车牌 | | days[].vehicles[].vehicleModel | String | 车型 | | days[].vehicles[].driverName | String | 司机姓名 | | days[].vehicles[].status | String | 派车状态码,取值 `ASSIGNED` / `CONFIRMED`;**未变** | | days[].vehicles[].statusLabel | String | 🆕 派车状态中文名,与 `status` 恒成对非空:已派车 / 已确认(字典另含 `CANCELLED` 已取消,正常不出现在本列表) | | days[].vehicleCount | Integer | 该日车辆数 | | days[].dispatched | Boolean | 该日是否已排车 | | orders | Array | 本团子订单的用车覆盖情况 | | orders[].vehicleControlStatus | String | **订单级单值,行程用车与接送机两类共用一格**(#8620 澄清,取值与字段名未变);非 `DONE` 只代表两类里至少一类没齐,说不出是哪一类 | | orders[].travelRequirementStatus | String | 行程用车需求状态(按类别拆开的字段之一) | | orders[].transferDeclared | Boolean | 是否声明了接送机 | | orders[].transferPendingCount | Integer | 该订单接送机未覆盖段数 | | transferPendingTotal | Integer | 全团接送机未覆盖段数合计 | #### 请求示例 ```http GET /admin/fleet/group-dispatch/batches/2104839654727618562/overview Authorization: Bearer {token} ``` #### 响应示例 ```json { "code": 200, "message": "成功", "data": { "groupBatchId": "2104839654727618562", "batchNo": "T26-3963", "departDate": "2026-10-06", "endDate": "2026-10-10", "requirementConfirmed": false, "vehicleReady": false, "days": [ { "tripDate": "2026-10-06", "vehicles": [ { "dispatchId": "2104840113194905601", "vehicleId": "1902233114509312002", "vehiclePlate": "蒙E13572", "vehicleModel": "丰田考斯特", "driverId": "1902233114509312050", "driverName": "李广宇", "driverPhone": "13847001234", "status": "ASSIGNED", "statusLabel": "已派车", "remark": null, "groupCode": "A" } ], "vehicleCount": 1, "dispatched": true } ], "missingDates": ["2026-10-09", "2026-10-10"], "orders": [ { "orderId": "2104839654727618570", "orderNo": "HL202610060012", "teamNo": "T26-3963", "customerName": "周雅", "headcount": 4, "vehicleControlStatus": "PENDING_REVIEW", "travelRequirementId": "2104839777884160001", "travelRequirementStatus": "PENDING_REVIEW", "transferDeclared": true, "transferPendingCount": 1 } ], "transferPendingTotal": 1, "conversationKey": "GROUP_FLEET:2104839654727618562" }, "success": true } ``` #### 空数据 / 降级响应 - 某服务日还没排车:`days[].vehicles` 为空数组 `[]`,`vehicleCount` 为 `0`,`dispatched` 为 `false`;该日期同时出现在 `missingDates` 里。 - `vehicles[]` 有项时 `status` 与 `statusLabel` **必定同时非空**(派车行的状态列 NOT NULL);不存在「有码没中文名」的半边状态。 - 团期没有任何子订单时 `orders` 为空数组,`transferPendingTotal` 为 `0`。 #### 错误响应 ```json { "code": 600012, "message": "团期配车基线不可达,请稍后重试", "data": null, "success": false } ``` - `600012 团期配车基线不可达,请稍后重试`:团期基线数据读不到;不会用空总览冒充成功。 - `401`:未登录或令牌失效(网关返 HTTP 200 + 信封 `code: 401`)。 #### 业务边界 - `statusLabel` 的字典含三个码(`ASSIGNED` 已派车 / `CONFIRMED` 已确认 / `CANCELLED` 已取消),但本总览只装载未取消的派车行,所以实际只会读到前两个。前端构造状态筛选或图例时按两值即可,不必为「已取消」留位置。 - 🔴 `orders[].vehicleControlStatus` 是**订单级单值**,行程用车与接送机两类共用这一格(#8620)。它非 `DONE` **不能**推断「行程用车没齐」,也不能推断「接送机没齐」——只能推断「至少一类没齐」。要落到具体类别,读 `travelRequirementStatus`(行程用车那一类)与 `transferDeclared` / `transferPendingCount`(接送机那一类)。 - `vehicleControlStatus` 的取值域是 order-v3 的需求状态集:`PENDING` / `PROCESSING` / `DONE` / `PENDING_REVIEW` / `REJECTED_TO_CONSULTANT` / `REJECTED_TO_ADMIN`。本次未新增、未删除取值。 - 本端点的 `statusLabel` 与派车详情等其它读口的派车状态文案同源(同一份枚举字典),不会出现两处对同一状态给不同中文名的情况。 - 中文名不参与任何筛选、排序或统计;`vehicleCount`、`transferPendingTotal`、`missingDates` 的口径本次未变。 ## 四、契约约束与正确调用方式(接口类必写) 1. **只增不改**:本次三个端点各只新增字段,没有删除、没有改名、没有取值域变化。前端已有代码不改也不会坏;要拿到中文名才需要改。 2. **中文名与码成对读,成对判空**:`码 == null ⇒ 中文名 == null`、`码 != null ⇒ 中文名 != null`。判「这一格有没有值」只需判其中一个;两个都判是冗余的,但**不要**出现「码为 null 却期待中文名有值」的分支——那条路不存在。 3. **未登记码原样回落成码本身**:四个字典(派单落库态 / 团期生命周期 / 配车进度 / 派车状态)的中文名解析都不抛异常、不返回 `null`。后端将来加码时,前端这一格会显示英文码而不是空白。**所以前端不要写「中文名为空就显示码」的兜底**(永远进不去),但**要**按「这一格可能是英文码」设计列宽与样式。 4. **停用本地映射表**:读到中文名字段后请删掉前端本地那份码 → 中文的表。两份字典并存时,后端加码 = 前端空白,而且没有报错、没有告警,只有用户看到一格空白。 5. **筛选仍传码**:`statuses` / `status` / `dispatchProgress` / `requirementKind` / `orderKind` 一律只接受码。传中文名会按非法值报 100001(看板)或 600013(待配车清单)。 6. **落库态与有效态分清**:要展示「当前状态」用 `assignmentStatusLabel`;要展示「落库真实状态」用 `baseAssignmentStatusLabel`。用后者当状态列会让加急态与陈旧定稿覆写这两类信息全部消失。 7. **`vehicleControlStatus` 不可用于判别类别**(#8620):它是两类共用的单值。要按类别展示或筛选,用 `travelRequirementStatus` / `transferDeclared` / `transferPendingCount`,或走看板清单的 `requirementKind` 维度。 8. **错误信封统一按 `code` 判**:业务失败与入参校验一律 HTTP 200 + 信封 `code`;测试环境网关对失效令牌也返回 HTTP 200 + `code: 401`。只看 HTTP 状态行的拦截器会把「已掉登录」当成功。 ## 五、数据库行为 三个端点均为只读查询,本次改动**不涉及任何 DDL 与 DML**:没有新增表、没有新增列、没有 Flyway 脚本、没有写入。新增的中文名字段全部在内存里由枚举字典解析出来,不落库、不参与任何 SQL 过滤或分组,因此既有的按状态码筛选 / 统计的查询路径读数一律不变。 ## 六、边界行为 | 场景 | 行为 | |------|------| | 状态码为 `null` | 对应中文名同为 `null`,后端不编默认文案 | | 状态码为未登记的新值 | 中文名回落成码本身,不抛异常、不返回 `null` | | 订单无落库派单行(虚拟待派卡) | `baseAssignmentStatus` 固定 `unassigned`,`baseAssignmentStatusLabel` 固定「待派车」 | | 同一行落库态与有效态不同 | 两个中文名不同,属预期(正是本字段的用途),不是数据错误 | | 派生态(临期加急 / hold 超时) | 只进 `assignmentStatus`;`baseAssignmentStatus` 与其中文名永远是 6 个落库态之一 | | 团期状态中文名的来源服务读不到 | 该格为 `null`(与码同生同灭),不影响同行其它字段 | | 团期配车总览里有已取消的派车行 | 不装载进 `days[].vehicles`,所以 `statusLabel` 实际读不到「已取消」 | | 无命中 / 无数据 | 列表返空数组,不返 `null`;不用空数据冒充成功以外的语义 | ## 六.5、枚举 / 数据字典 **落库派单状态**(`baseAssignmentStatus` → `baseAssignmentStatusLabel`,6 个落库态) | 码 | 中文名 | |----|--------| | unassigned | 待派车 | | holding | 待确认执行 | | assigned | 已派车 | | canceled | 已取消 | | exception | 异常 | | completed | 已完结 | 派生态 `unassigned_urgent`(→待派车)与 `holding_urgent`(→待确认执行)只出现在 `assignmentStatus`,**不会**出现在 `baseAssignmentStatus`。 **团期生命周期状态**(`batchStatus` → `batchStatusName`,九态) | 码 | 中文名 | |----|--------| | RECRUITING | 招募中 | | RESOURCE_PREPARING | 资源准备中 | | MATERIAL_PREPARING | 物料准备中 | | PENDING_DEPARTURE | 待出发 | | TRAVELLING | 出行中 | | TRIP_FINISHED | 出行完毕 | | REVIEWING | 核单中 | | SETTLED | 已结算 | | CANCELLED | 已取消 | **配车进度**(`dispatchProgress` → `dispatchProgressLabel`) | 码 | 中文名 | |----|--------| | NOT_STARTED | 未开始 | | PARTIAL | 部分排车 | | FULL | 已排满 | **派车状态**(`vehicles[].status` → `statusLabel`) | 码 | 中文名 | 是否出现在配车总览 | |----|--------|------------------| | ASSIGNED | 已派车 | 是 | | CONFIRMED | 已确认 | 是 | | CANCELLED | 已取消 | 否(已取消的派车行不装载进总览) | **订单级用车控制状态**(`vehicleControlStatus`,本次未改取值,仅澄清读法) | 码 | 语义 | |----|------| | PENDING | 待处理 | | PROCESSING | 处理中 | | DONE | 两类都已齐 | | PENDING_REVIEW | 待审核 | | REJECTED_TO_CONSULTANT | 已驳回定制师 | | REJECTED_TO_ADMIN | 已驳回管理员 | ## 六.6、修改前后对比 | 端点 | 字段 | 改动前 | 改动后 | |------|------|--------|--------| | `GET /admin/fleet/board/orders` | `records[].baseAssignmentStatusLabel` | 字段不存在(前端只能本地映射 `baseAssignmentStatus`) | 新增,与码恒成对非空 | | `GET /admin/fleet/group-dispatch/pending-batches` | `records[].batchStatusName` | 字段不存在(只有 `batchStatus` 裸码) | 新增,与码恒成对非空,与团期管理列表页同源 | | `GET /admin/fleet/group-dispatch/pending-batches` | `records[].dispatchProgressLabel` | 字段不存在(只有 `dispatchProgress` 裸码) | 新增,与码在同一次判定里算出 | | `GET /admin/fleet/group-dispatch/batches/{groupBatchId}/overview` | `days[].vehicles[].statusLabel` | 字段不存在(只有 `status` 裸码) | 新增,与码恒成对非空 | | `GET /admin/fleet/group-dispatch/batches/{groupBatchId}/overview` | `orders[].vehicleControlStatus` | 字段与取值相同,但文档未说明它是两类共用的订单级单值 | 字段与取值**完全不变**;文档明确:非 `DONE` 只代表至少一类没齐,判类别须读按类别拆开的字段(#8620) | ## 六.7、影响评估 - **前端必须改的**:无。不改一行也不会坏——四个字段都是新增,既有字段与取值零变化。 - **前端应当改的**:删掉本地的四张码 → 中文映射表,改读后端下发的中文名。收益是后端加码时不再出现静默空白格;不改的风险是本地表与后端字典分叉,且分叉无任何报错信号。 - **前端可能读错的一处**:把 `baseAssignmentStatusLabel` 当成「当前状态」显示在状态列 ⇒ 加急态与陈旧定稿覆写全部丢失。状态列仍应用 `assignmentStatusLabel`。 - **前端可能读错的另一处**(#8620):把 `vehicleControlStatus` 当成「行程用车状态」或「接送机状态」的单一来源 ⇒ 在只报接送机、或只报行程用车的订单上会给出误导性展示。判类别必须读按类别拆开的字段。 - **兼容性**:JSON 新增字段对已有前端反序列化无影响(未知字段忽略 / 多出字段不解析)。响应体每行增大 4 个短字符串量级,分页上限 100 行,体积影响可忽略。 - **无副作用面**:不涉及写入、不涉及事务、不涉及消息、不涉及权限判定,也不改任何筛选与统计口径。 ## 七、不影响范围 - 三个端点的**入参**:字段、别名、默认值、校验规则、错误码全部未变。 - 三个端点的**分页、过滤、排序、聚合去重**口径全部未变。 - 三个端点的**既有响应字段**:名称、类型、取值域、语义全部未变,包括 `assignmentStatus` / `assignmentStatusLabel` / `baseAssignmentStatus` / `batchStatus` / `dispatchProgress` / `vehicles[].status` / `orders[].vehicleControlStatus`。 - **错误码**未新增、未删除、未改文案(100001 / 600012 / 600013 / 401)。 - **写接口**:派车提交、派车确认、需求打回等写路径本次一行未改。 - **网关路由**:三个端点都是既有路由,`/admin/fleet/**` 已配置,本次无新增路由。 - **数据库**:无 DDL、无 DML、无 Flyway 脚本。 - **小程序端**:本次改动全部落在管理后台读口,小程序端零影响。 ## 八、测试环境已验证 本次改动的可验证面是「码 → 中文名」的映射与成对不变量,已由下列自动化用例覆盖(`hl-fleet-service` + `hl-order-service-v3`): | 覆盖点 | 用例 | |--------|------| | 派车状态三码各返约定中文名(含正常读不到的 `CANCELLED`) | `GroupDispatchStatusTest#labelOf_allDeclaredCodes_returnsChineseLabel` | | 派车状态:码非空 ⇒ 中文名必非空,且中文名不等于码本身 | `GroupDispatchStatusTest#labelOf_codeNotNull_labelNeverNull` | | 派车状态:未知码原样回落不抛异常,`null` 返 `null` | `GroupDispatchStatusTest#labelOf_unknownCodeOrNull_fallsBackWithoutThrowing` | | 配车进度三档各返约定中文名 | `GroupDispatchProgressTest#labelOf_allDeclaredCodes_returnsChineseLabel` | | 配车进度:码非空 ⇒ 中文名必非空 | `GroupDispatchProgressTest#labelOf_codeNotNull_labelNeverNull` | | 配车进度:未知码回落、`null` 返 `null`;`isValid` 只认三档 | `GroupDispatchProgressTest#labelOf_unknownCodeOrNull_fallsBackWithoutThrowing`、`#isValid_onlyDeclaredCodes` | | 待配车清单:团期状态中文名原样透传上游、fleet 不做二次映射 | `GroupDispatchQueryServiceTest`(`#8621` 待配车清单用例) | | 配车总览逐车项:`status` 与 `statusLabel` 恒成对非空 | `GroupDispatchQueryServiceTest`(`#8621` 逐车项用例) | | 团期候选项下发状态中文名:与团期列表同一份映射,码非空则中文名必非空;码为 `null` 时中文名同为 `null`、不编默认文案 | `GroupBatchVehicleDispatchQueryServiceTest`(`#8621` 两个用例) | | 看板订单行:落库态中文名与 `baseAssignmentStatus` 恒成对非空;虚拟待派卡也给中文名 | `BoardOrderServiceTest`(`#8621` 用例) | ## 九、相关历史 PR - PR #8622(本次):`feat(fleet,order-v3): 派车读口补齐状态中文名,枚举码不再裸下发(#8620 #8621)`。 - #8593:待配车团期清单 `transferPendingCount` 由硬编码 0 改为真值,并引入 `null` = 未取到语义。 - #8518:看板清单 `requirementKind` 入参与 `requirementKindLabel` 出参(同一「后端下发中文名」方向的先例)。 - #7535:枚举中文名由枚举归属服务下发、后缀命名约定(`batchStatusName` 用 `Name` 而非 `Label` 的由来)。 ## 十、相关文档 - `docs/CODE_RULES.md` §15.7:对称子域禁镜像重复 / 字典字面量单源——本次四个字段的立项依据。 - `docs/CODE_RULES.md` §3:VO 命名与 `@ApiModelProperty` 约定。 - Swagger:`hl-fleet-service` → `看板` 与 `团期配车` 分组,三个端点的字段注释已同步更新(含 `allowableValues`)。 ## 关联 / 联系人 ### 链接 - 工单 #8621(补中文名)、#8620(`vehicleControlStatus` 订单级单值口径澄清) - PR #8622 ### 联系人 - 后端:wx - 前端:mmg(管理后台 hl-ui)