12 KiB
schema, ticket, title, consumer, change_type, author, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
| schema | ticket | title | consumer | change_type | author | backend_status | gateway_status | frontend_status | frontend_owner | frontend_ref | target_release | verified_at | status_note | updated_at | base |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hl-changelog/v2 | 5712 | 车辆核单 FLEET 行核算金额放开可编辑(amount 不再撞 584109) | admin | 修改接口 | yaosutu(GIT) | deployed | verified | implemented | mmg | a9ddbd48 | PR #5715 已合并 dev-v3;PUT /v3/admin/order/{orderId}/settlement/step3/vehicles 对 FLEET 来源行的 amount 字段从只读放开为可编辑,结构字段仍受 584109 保护。前端若把 amount 渲染为只读输入框,应放开为可编辑。 | 2026-08-08 | dev-v3 |
【修改接口·管理后台】车辆核单 FLEET 行核算金额放开可编辑(#5712)
PR: #5715 | 服务: hl-order-service-v3 | 更新时间: 2026-08-08
1. 接口背景
核单 Step3 车辆 Tab 的全量保存接口此前对 FLEET(车务)来源行 的 amount(核算金额)做只读保护:前端把 GET 回显的金额改大/改小后回传,会被错误码 584109「车务来源字段不可直接修改或删除」拦截,接口虽然返回 200 但 message 提示、金额实际不变。
业务诉求:核单人员需要能对车务来源的核算金额做手工修正(实际结算价与车务快照价不一致的场景,与住宿/门票核单的人工调价口径一致)。本次放开 FLEET 行 amount 可编辑,改完即生效、不留审计痕。
2. 变更清单
| # | 接口 | 方法 | 路径 | 变更类型 | 前端动作 |
|---|---|---|---|---|---|
| 1 | 全量保存车辆核单草稿 | PUT | /v3/admin/order/{orderId}/settlement/step3/vehicles |
行为放开(字段零变化) | FLEET 行 amount 输入框由只读改可编辑 |
| 2 | 查询车辆核单草稿 | GET | /v3/admin/order/{orderId}/settlement/step3/vehicles |
出参语义变化 | items[].amount 现返回覆盖层修正后金额 |
3. 接口详情
- 使用场景:核单人员在订单核单 Step3 车辆 Tab 维护车辆核单明细(全量覆盖式保存)。
- 认证:需要管理后台登录态(Bearer Token)。
- 幂等性:是,按订单维度全量覆盖式保存,重复提交相同载荷结果一致。
- 限流:未声明接口专属限流。
4. 接口入参
4.1 路径参数
| 字段 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
orderId |
Path | Long | 是 | 订单 ID |
4.2 请求体字段
| 字段 | 类型 | 必填 | 校验规则 | 本次是否放开 |
|---|---|---|---|---|
items |
Array | 是 | 全量明细 | — |
items[].id |
Long | 条件必填 | 既有行必传;新增手工行为 null | 否(仍受 584109 保护) |
items[].sourceType |
String | 是 | FLEET / MANUAL |
否 |
items[].serviceDate |
String(date) | 是 | yyyy-MM-dd |
否(仍受 584109 保护) |
items[].vehicleId |
Long | 条件必填 | FLEET 行必传 | 否(仍受 584109 保护) |
items[].vehiclePlate |
String | 否 | 最长 64 | 否(仍受 584109 保护) |
items[].vehicleModelId |
Long | 否 | — | 否(仍受 584109 保护) |
items[].vehicleModelName |
String | 否 | 最长 128 | 否(仍受 584109 保护) |
items[].driverId |
Long | 否 | — | 否(仍受 584109 保护) |
items[].driverName |
String | 否 | 最长 64 | 否(仍受 584109 保护) |
items[].amount |
Decimal | 是 | 非负、最多 2 位小数 | 本次放开为可编辑 |
items[].paymentMethod |
String | 是 | CASH_PAID / SIGNED / COMPANY_PAID |
否(仍受 584109 保护) |
items[].settlementConfirmStatus |
String | 是 | UNCONFIRMED / CONFIRMED |
否(本就可改) |
items[].remark |
String | 否 | 最长 500 | 否(本就可改) |
items[].voucherUrls |
String[] | 否 | 最多 9 个 URL | 否(本就可改) |
FLEET 行编辑约定:
vehicleFeeLineId(即 GET 回显的items[].id)、serviceDate、vehicleId、vehiclePlate、vehicleModelId、vehicleModelName、driverId、driverName、paymentMethod这 9 个车务来源结构字段不允许改,前端应把这些字段原样回传(来自 GET step3/vehicles 的回显值),只允许改amount(以及remark/voucherUrls/settlementConfirmStatus)。改了结构字段仍撞584109。
5. 出参字段
成功响应为统一 Result 结构,code=200。data 出参字段(orderId / totalAmount / allConfirmed / settlementReady / blockReasonCode / items / frozen)结构无变化。
唯一语义变化:GET items[].amount 现在返回覆盖层修正后的金额(改完再查就是新值),不再被 fleet 快照价覆盖。
6. 枚举 / 数据字典
本次不涉及枚举新增或改值。paymentMethod(CASH_PAID/SIGNED/COMPANY_PAID)、settlementConfirmStatus(UNCONFIRMED/CONFIRMED)、sourceType(FLEET/MANUAL)取值不变。
7. 错误码
| code | 含义 | 触发场景 |
|---|---|---|
584109 |
车务来源字段不可直接修改或删除 | 改了 FLEET 行的结构字段(serviceDate/vehicleId/vehiclePlate/vehicleModelId/vehicleModelName/driverId/driverName/paymentMethod/vehicleFeeLineId)或试图删除 FLEET 行 |
400 |
请求数据格式错误 | amount 为负数 / 小数位超过 2 位 / 数值超出范围 / 其他 Bean 校验失败 |
8. 示例
8.1 典型成功 —— FLEET 行 amount 由 800 改为 950
请求:
PUT /v3/admin/order/2084000000000002978/settlement/step3/vehicles
Authorization: Bearer <token>
Content-Type: application/json
{
"items": [
{
"id": "9001",
"sourceType": "FLEET",
"serviceDate": "2026-08-08",
"vehicleId": "301",
"vehiclePlate": "蒙A88888",
"vehicleModelId": "21",
"vehicleModelName": "丰田汉兰达",
"driverId": "45",
"driverName": "张师傅",
"amount": "950.00",
"paymentMethod": "COMPANY_PAID",
"settlementConfirmStatus": "UNCONFIRMED",
"remark": "实际结算价高于快照",
"voucherUrls": []
}
]
}
响应:
{"code": 200, "message": "success", "data": {"saved": true}, "success": true}
随后 GET 同一订单 step3/vehicles,items[].amount 返回 "950.00"。
8.2 边界情况 —— amount 改为 0.00 仍合法
场景说明:金额下限为 0.00,0 元合法(不是"未填")。
请求:
PUT /v3/admin/order/2084000000000002978/settlement/step3/vehicles
Authorization: Bearer <token>
Content-Type: application/json
{
"items": [
{
"id": "9001",
"sourceType": "FLEET",
"serviceDate": "2026-08-08",
"vehicleId": "301",
"vehiclePlate": "蒙A88888",
"vehicleModelId": "21",
"vehicleModelName": "丰田汉兰达",
"driverId": "45",
"driverName": "张师傅",
"amount": "0.00",
"paymentMethod": "COMPANY_PAID",
"settlementConfirmStatus": "UNCONFIRMED",
"remark": null,
"voucherUrls": []
}
]
}
响应:
{"code": 200, "message": "success", "data": {"saved": true}, "success": true}
8.3 业务失败 —— 改了 FLEET 行结构字段 vehiclePlate 撞 584109
场景说明:仅放开 amount;结构字段(如车牌)仍受保护。
请求:
PUT /v3/admin/order/2084000000000002978/settlement/step3/vehicles
Authorization: Bearer <token>
Content-Type: application/json
{
"items": [
{
"id": "9001",
"sourceType": "FLEET",
"serviceDate": "2026-08-08",
"vehicleId": "301",
"vehiclePlate": "蒙A99999",
"vehicleModelId": "21",
"vehicleModelName": "丰田汉兰达",
"driverId": "45",
"driverName": "张师傅",
"amount": "950.00",
"paymentMethod": "COMPANY_PAID",
"settlementConfirmStatus": "UNCONFIRMED",
"remark": null,
"voucherUrls": []
}
]
}
响应:
{"code": 584109, "message": "车务来源字段不可直接修改或删除", "data": null, "success": false}
9. 业务边界
- 适用场景:FLEET 行
amount可任意改(非负、最多 2 位小数);改完即生效,不留审计痕,与住宿/门票核单人工调价口径一致。 - 不适用场景:FLEET 行的结构字段(车牌 / 司机 / 服务日期 / 车型 / 付款方式 / 行 id)仍不允许改;如需换车换司机请走车务派单链路,不要在核单页改。
- 特殊边界:
amount改为0.00是合法值,不是"清空";MANUAL 行的所有字段本就可改,本次无变化。
10. 修改前后对比
10.1 字段级对比
| 字段 | 原来 | 现在 |
|---|---|---|
FLEET 行 amount |
只读;改值撞 584109(PUT 返回 200 但 message 提示、金额不变) |
可编辑;值合法即落库 |
| FLEET 行结构字段(车牌/司机/日期/车型/付款方式) | 只读,撞 584109 |
仍只读,撞 584109(不变) |
GET items[].amount |
返回 fleet 快照价 | 返回覆盖层修正后金额 |
10.2 行为级对比
| 行为 | 原来 | 现在 |
|---|---|---|
| 前端把 FLEET 行 amount 改大/改小回传 | 被 584109 拦截,金额不变 |
正常保存,GET 回读新值 |
| 前端改 FLEET 行 vehiclePlate | 584109 |
584109(不变) |
11. 影响评估 / 回滚
11.1 影响评估
- 是否破坏向后兼容:否。接口签名、字段、错误码零变化;仅放开一个字段的编辑限制。
- 前端是否必须同步上线:否。旧前端继续把 amount 渲染为只读输入框不影响功能;但建议尽快放开为可编辑以匹配新口径。
11.2 回滚方案
- 回滚即恢复 amount 只读保护,旧前端(amount 只读)天然兼容;已改为可编辑的新前端在旧后端上保存会重新撞
584109,需前后端同批回滚。
12. 注意事项
- 本次仅放开
amount;不要把 FLEET 行其他结构字段也放开为可编辑。 - 前端在 FLEET 行编辑表单里,
amount用 number input 即可,提交前按"非负、最多 2 位小数"做一次本地校验可减少 400。 - 若前端历史上有"FLEET 行 amount 改了被静默回滚"的 workaround(如改完强刷 GET 重新渲染),本次后可保留也可简化,无破坏性。
13. 关联 / 联系人
13.1 链接
13.2 联系人
- 后端负责人: @yaosutu (yst)
前端实证确认(2026-08-08 mmg,hl-admin@a9ddbd48)
- 前端 FLEET 行 amount 此前确为只读:
returnDetailAdapter.js adaptVehicleRows对 FLEET 行editableFields=['confirmStatus','note'](缺 amount),CategoryTablerowFieldEditable据此把 amount 渲染为只读。 - 修复:FLEET 行 editableFields 改为
['amount','confirmStatus','note'],amount 输入框放开可编辑;结构字段(车牌/司机/日期/车型/付款方式/id)仍不在 editableFields,保持只读(与后端 584109 保护一致)。凭证列由canEditRowVoucher独立判定(不看 editableFields),本就开放,无需改。 - 保存链路
buildVehicleSaveRequest本就把row.amount透传进items[].amount、结构字段从source.*原样回传,无需改——金额改完随全量保存生效。 - 验证:settlement 全量定向 vitest 93/93 通过(含更新
editableFields断言);checkpoint 全绿。