--- schema: "hl-changelog/v2" ticket: "9120" title: "派车工作台回收站列表(撤下派车行分页、来源筛选、能否恢复)" consumer: "admin" author: "wx(GIT)" change_type: "新增接口" backend_status: "deployed" gateway_status: "verified" frontend_status: "pending" frontend_owner: "" frontend_ref: "" target_release: "v2.1" verified_at: "2026-10-22" status_note: "后端 PR #9126 已合并 dev-v3(squash ead771c42),已部署<测试服>并双实例 is UP;真登录经网关实测 GET 两个筛选均 HTTP 200 / code 200(测试库当前无撤下行,records 为空,31 字段由单测映射用例覆盖)。本单只读,无表/Flyway/菜单/网关变更。" updated_at: "2026-10-22" base: "dev-v3" --- # 派车工作台回收站列表(新增接口) > 面向:管理后台前端(hl-ui) > 日期:2026-10-22 | 后端:hl-fleet-service(二期 dev-v3) > 范围:**纯新增**一个只读分页接口,供「派车工作台 → 回收站」弹窗列出被撤下的派车行,并显示每行能否恢复。 ## 一、背景(选填) 3.9「撤下派车行」把行置为 CANCELLED 并写撤下日志,撤销后这些行不再出现在派车工作台的正常列表里。回收站是这些行的只读入口:按撤下时间倒序列出,可按团号/司机/车牌/车队名称搜索,可按撤下来源筛选,并逐行告诉前端「此刻能不能恢复、不能恢复时为什么」。点「恢复」不调本接口,仍走 3.10(请求体带本接口返回的 dispatchVehicleId 与 version)。 本单只交付列表;撤下/恢复事务(3.9/3.10)由后续工单接线,故本单上线后列表可能为空,这是数据现状,不是接口异常。 ## 二、变更接口清单 | # | 接口 | 方法 | 路径 | 变更类型 | 说明 | |---|------|------|------|----------|------| | 1 | 回收站列表 | GET | `/admin/fleet/dispatch-recycle/page` | 新增接口 | 撤下派车行分页,按撤下时间倒序;每行带 restorable/unrestorableReason | ## 三、接口详情 ### 1. 回收站列表 `GET /admin/fleet/dispatch-recycle/page` **VO**: `FleetDispatchRecyclePageReqVO` / `FleetDispatchRecycleRespVO` #### 使用场景 派车工作台点「回收站」打开弹窗时调用第一页;改关键词/团/撤下来源时从头查;点「恢复」前用本行 restorable 判断按钮是否可点,不可点时把 unrestorableReason 悬浮显示。 #### 入参 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | |------|------|------|------|------|------| | keyword | Query | String | 否 | 最长 50 字,trim 后空等于不传 | 任意一样包含:团号/司机姓名/车牌/车队名称;不拆词 | | focusDispatchVehicleId | Query | String | 否 | 数字 ID | 命中时排到请求页第一条,原位置不再重复;不命中按正常排序 | | dispatchGroupId | Query | String | 否 | 数字 ID | 只看该团撤下的行 | | cancelSource | Query | String | 否 | MANUAL/UNASSIGN_ALL/NO_VEHICLE/RETIRED/DATE_CHANGED/REQUIREMENT_CANCELLED | 撤下来源;MANUAL 同时包含 cancel_source 为 NULL 的历史行 | | page | Query | Integer | 否 | ≥1,默认 1 | 页码 | | pageSize | Query | Integer | 否 | 1–100,默认 20 | 每页条数 | #### 出参 `Result>` | 字段 | 类型 | 说明 | |------|------|------| | dispatchVehicleId | String | 派车行 ID(雪花号,字符串避免精度丢失) | | version | Integer | 行版本号,点「恢复」时原样回传给 3.10 做乐观锁 | | dispatchGroupId | String | 所属团 ID;团已不存在也照旧返回 | | teamNo | String | 团号;团不存在或老数据为空时为 null | | sourceType | String | 团来源:GROUP/CORE/CUSTOM;团不存在时为 null | | sourceTypeName | String | 团来源中文 | | memberOrderId | String | 成员订单 ID;整行/接送关联的户 | | memberTeamNo | String | 成员团号;为空表示整行或未关联户 | | contactName | String | 联系人姓名,仅团期产品且成员团号为空时有值 | | useType | String | 用车类型:TOUR/PICKUP/DROPOFF/MID_SWAP | | useTypeName | String | 用车类型中文 | | vehicleTypeId | String | 车型 ID | | vehicleTypeName | String | 车型名称 | | fleetTeamId | String | 车队 ID | | fleetTeamName | String | 车队名称 | | driverId | String | 司机 ID | | driverName | String | 司机姓名 | | plate | String | 车牌 | | serviceStartDate | String | 服务开始日 yyyy-MM-dd | | serviceEndDate | String | 服务结束日 yyyy-MM-dd | | amount | String | 金额,两位小数;无金额为 null | | lineStatusBeforeCancel | String | 撤下前状态:PENDING/SENT_TO_FLEET/ASSIGNED | | lineStatusBeforeCancelName | String | 撤下前状态中文 | | cancelledAt | String | 撤下时间 yyyy-MM-dd HH:mm:ss | | cancelReason | String | 撤下原因 | | cancelSource | String | 撤下来源六值之一;老数据为 null 时按 MANUAL 输出 | | cancelSourceName | String | 撤下来源中文 | | cancelOperatorId | String | 撤下操作人 ID;系统或旧系统迁来为 null | | cancelOperatorName | String | 撤下操作人;系统或旧系统迁来为「系统」 | | restorable | Boolean | 此刻能否恢复;true 表示可点恢复 | | unrestorableReason | String | 不能恢复时的提示语,取自 3.10 对应错误码;可恢复为 null | 分页外壳 `data` 另有 `total`(Integer,总条数,不受分页影响)、`page`(Integer,当前页)、`pageSize`(Integer,每页条数);顶层为 `code`/`message`/`data`/`success`/`traceId`。 #### 请求示例 ```http GET /admin/fleet/dispatch-recycle/page?page=1&pageSize=20&keyword=沪A12345&cancelSource=MANUAL Authorization: Bearer ``` #### 响应示例 ```json {"code":200,"message":"成功","data":{"records":[{"dispatchVehicleId":"2103791490167999001","version":3,"dispatchGroupId":"2103791490167888001","teamNo":"HL20261020001","sourceType":"GROUP","sourceTypeName":"团期","memberOrderId":"2103791490167999101","memberTeamNo":"T-0007","contactName":null,"useType":"TOUR","useTypeName":"带团","vehicleTypeId":"2103791490167000001","vehicleTypeName":"7座商务","fleetTeamId":"2103791490166000001","fleetTeamName":"华东车队","driverId":"2103791490165000001","driverName":"王师傅","plate":"沪A12345","serviceStartDate":"2026-10-18","serviceEndDate":"2026-10-20","amount":"3600.00","lineStatusBeforeCancel":"ASSIGNED","lineStatusBeforeCancelName":"已派车","cancelledAt":"2026-10-20 15:12:33","cancelReason":"客户改期","cancelSource":"MANUAL","cancelSourceName":"撤下","cancelOperatorId":"2103791490167934978","cancelOperatorName":"ha_r1_su","restorable":true,"unrestorableReason":null}],"total":1,"page":1,"pageSize":20},"success":true} ``` #### 空数据 / 降级响应 无数据时 `records` 为空数组,`total=0`,HTTP 与业务 code 仍为 200: ```json {"code":200,"message":"成功","data":{"records":[],"total":0,"page":1,"pageSize":20},"success":true} ``` #### 错误响应 参数非法(page<1、pageSize 不在 1–100、keyword 超过 50 字、cancelSource 不在六值、ID 非数字)统一返回 100001;HTTP 状态码按全局约定: ```json {"code":100001,"message":"参数非法: page 必须大于等于 1","data":null,"success":false} ``` #### 业务边界 - 只读,不写库;无幂等/并发语义。 - 只列 `line_status='CANCELLED'` 的行;软删行不出现。 - 排序固定 `cancelled_at DESC, dispatch_vehicle_id DESC`(同秒按 ID 大→小),不接受排序参数。 - `restorable` 是「拉列表那一刻」的判定;点恢复时 3.10 会从头重判,可能由可恢复变为不可恢复。 - 不可恢复提示语来自 3.10 的四个错误码:603009 团不存在、603002 团来源订单已取消、603302 这一户已退团、603110 需求已取消。 - 团不存在时 teamNo/sourceType 等团字段为 null,但该行仍会列出(dispatchGroupId 照旧)。 - 关键词不拆词:整串对团号/司机姓名/车牌/车队名称做包含匹配。 ## 四、契约约束与正确调用方式(接口类必写) ### ✅ 正确 / ❌ 错误 payload 对照 | 场景 | 查询串 | |------|--------| | ✅ 默认第一页 | `?page=1&pageSize=20` | | ✅ 只看某团 | `?page=1&pageSize=20&dispatchGroupId=2103791490167888001` | | ✅ 只看手工撤下 | `?page=1&pageSize=20&cancelSource=MANUAL` | | ❌ pageSize 超过 100 | `?page=1&pageSize=101` → 100001 | | ❌ cancelSource 拼错 | `?cancelSource=manual` → 100001(区分大小写) | ### 切换状态时的必要动作 - 从回收站点「恢复」时,请求体必须带**本行返回的** `dispatchVehicleId` 与 `version`,不要用列表缓存里的旧 version;恢复成功后应重新拉当前页。 - 搜索框输入需 trim;空串等价于不传 keyword,不要传空串以外的占位符。 ## 六、边界行为 - 未登录 → 401(网关拦截)。 - 无权限(缺 `fleet:dispatch-recycle:list`)→ 403(网关/权限拦截)。 - 参数非法 → 100001。 - 无数据 → 200 + 空 records。 - 团/户/需求在列表之后被取消 → 本接口不感知;下次拉列表时 restorable 才变 false。 ## 七、不影响范围(显式声明,帮前端/QA 缩小排查面) - **仅影响**:新增 `GET /admin/fleet/dispatch-recycle/page` 一个只读端点。 - **零影响**: - 派车工作台团列表/详情/建议接口 - `/admin/fleet/dispatch-groups/counts` 的 recycleCount 计算(本接口只读复用其口径) - 3.9 撤下与 3.10 恢复(均不在本单) - 表结构、索引、Flyway、菜单、网关路由(全部沿用现状) ## 八、测试环境已验证 真实登录(`POST /admin/auth/login`,账号 ha_r1_su,非铸 token)后经测试服网关: ```text GET /admin/fleet/dispatch-recycle/page?page=1&pageSize=10 → 200 + code 200,total=0,records=[],page=1,pageSize=10 ✓ GET /admin/fleet/dispatch-recycle/page?page=1&pageSize=10&cancelSource=MANUAL → 200 + code 200,total=0 ✓ GET /admin/fleet/dispatch-groups/counts → 200 + code 200,recycleCount=0 ✓ ``` 说明:测试库当前没有 line_status=CANCELLED 的行(回收站 total 与 /counts 的 recycleCount 双向均为 0),因此响应 records 为空;31 个字段名与顺序由单测映射用例覆盖,不是线上真行核对。前端可先用空列表开发页面骨架,接上 3.9 后自然有数据。 ## 十、相关文档 - 关联 Issue: [wx/HL#9120](https://git.1814.love/wx/HL/issues/9120) - 关联 PR: [wx/HL#9126](https://git.1814.love/wx/HL/pulls/9126) - 设计文档:`docs/fleet-workbench/1-2接口文档.md` 第 12.2 节「回收站」;`docs/fleet-workbench/1-3详细设计.md` F12.2 与 R12 ## 关联 / 联系人 ### 链接 - **Issue**: [#9120](https://git.1814.love/wx/HL/issues/9120) - **PR**: [#9126](https://git.1814.love/wx/HL/pulls/9126) - **Merge commit**: [ead771c42](https://git.1814.love/wx/HL/commit/ead771c42fadd256adeac6a579f84229b396038e) ### 联系人 - **后端负责人**: @wx