hl-api-changelog/changelogs-v2/2026-08/11_5820_主报账人报表出参重构统一字段-修改接口-管理后台.md
yaosutu d362c3acb1
一些检查失败了
changelog-filename-gate / validate (push) Failing after 2s
docs(changelog): 主报账人报账表出参重构统一字段(#5820/#5859)管理后台
破坏性变更通知:顶层平铺汇总字段收拢进 baseInfo、expenseLines 统一 12 扁平字段、
删除 vehicleLines 与 6 个冗余字段、orderHeader 补 returnDate/travelerCount。
对应后端 PR #5839 + #5865,前端必须同步改造。
2026-08-11 18:02:05 +08:00

564 行
25 KiB
Markdown

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

---
schema: "hl-changelog/v2"
ticket: "5820"
title: "主报账人报账表出参重构:顶层三维化 + 支出行统一扁平字段(破坏性变更)"
consumer: "admin"
change_type: "修改接口"
author: "yaosutu(GIT)"
backend_status: "deployed"
gateway_status: "pending"
frontend_status: "pending"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "后端 PR #5839#5820 出参重构)+ PR #5865#5859 删 transferDirection + orderHeader 补 returnDate/travelerCount均已 merge 到 dev-v3 并部署测试服。本次为破坏性出参变更:顶层平铺汇总字段全部移入 baseInfo 子对象、支出行 7 族稀疏字段统一为 12 个扁平字段、vehicleLines 顶层字段删除、baseInfo 删除 6 个冗余字段。前端必须同步改造后才能上线。"
updated_at: "2026-08-11"
base: "dev-v3"
---
# 【⚠️ 修改接口·管理后台】主报账人报账表出参重构:顶层三维化 + 支出行统一扁平字段(#5820 / #5859
## 1. 接口背景
核单结算域的「主报账人报账表」接口,供管理后台在订单核单时查看主报账人(通常是司机)的代收、垫付支出、预支与净额结算情况。
本次重构解决两个历史问题:
1. **出参结构混乱**#5820):原出参把 30+ 个汇总字段平铺在顶层,支出行按费用类别拆成 7 族各自一套字段名(住宿用 hotelName/roomTypeName/stayDate、餐食用 mealName/mealTypeName/mealDate、门票用 scenicName/specName/dayDate、车辆用 vehiclePlate/driverName/serviceDate/dailyPrice……,前端需要为每类支出写一套渲染逻辑,且存在 4 对语义重复的镜像字段。
2. **订单抬头字段不全 + 方向字段冗余**#5859baseInfo.transferDirection 与 transferAmount 正负 / reporterNetAmount 表达的信息重复;orderHeader 缺返回日期与出行人总数。
## 2. 变更清单
| # | 变更 | 类型 |
|---|------|------|
| 1 | 顶层 30+ 平铺汇总字段全部收拢进 baseInfo 子对象 | ⚠️ 破坏性 |
| 2 | expenseLines 支出行由 7 族稀疏字段统一为同一套 12 个扁平字段 | ⚠️ 破坏性 |
| 3 | 顶层 vehicleLines 字段删除(车辆支出行并入 expenseLines,签单/公司直付不再重复列出) | ⚠️ 破坏性 |
| 4 | baseInfo 删除 6 个冗余字段reconNetAmount / driverCollectedTailAmount / publicPrepaidAmount / advanceOutstandingAmount / transferStatus / transferDirection | ⚠️ 破坏性 |
| 5 | 报账口径明确为口径 AexpenseLines 只含报账人垫付CASH_PAID支出 | 🔧 行为变化 |
| 6 | orderHeader 新增 returnDate返回日期、travelerCount出行人总数 | ✨ 新增字段 |
## 3. 接口详情
| 项 | 值 |
|---|---|
| 方法 + 路径 | GET /v3/admin/order/{orderId}/settlement/reports/reimbursement |
| 接口名 | 查询主报账人报账表 |
| 使用场景 | 管理后台订单核单页,查看主报账人代收/垫付/预支/净额结算报表 |
| 认证 | 管理后台 JWT/v3/admin/* 走网关鉴权) |
| 角色限制 | 房务角色HOUSE不可访问,调了会被拦截 |
| 幂等性 | 只读查询,幂等 |
| 限流 | 走网关默认限流,无接口级特殊限流 |
## 4. 接口入参
### 4.1 路径参数
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| orderId | Long | 是 | 订单 ID,必须大于 0 |
### 4.2 请求体
无请求体,无 Query 参数。
## 5. 出参字段
统一响应 Result<SettlementReimbursementReportRespVO>,data 结构如下。
### 5.1 顶层结构
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| baseInfo | Object | 是 | 基础信息(汇总值 + 报账人 + 审计字段),恒下发对象 |
| orderHeader | Object | 否 | 订单头(订单号/团号/产品/客户/出团日期/定制师/出行人构成) |
| incomeLines | Array | 是 | 收入行(司机代收);无数据固定返回空数组 [] |
| expenseLines | Array | 是 | 支出行(统一扁平字段,仅报账人垫付支出);无数据固定返回空数组 [] |
| advanceLines | Array | 是 | 预支明细行(已审批预支逐条);无数据固定返回空数组 [] |
> 顶层**不再有任何平铺的汇总金额字段**,也**不再有 vehicleLines**。
### 5.2 baseInfo 字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long(String) | 核单记录 IDsettlement_recon.recon_id;未生成时为空。Long 序列化为字符串防 JS 精度丢失 |
| orderId | Long(String) | 订单 ID,序列化为字符串 |
| reportStatus | String | 报表状态,枚举GENERATED已生成/ CONFIRMED已确认 |
| reportVersion | Integer | 报表版本号,固定从 1 开始 |
| primaryReporterId | Long(String) | 主报账人人员安排 ID |
| primaryReporterName | String | 主报账人姓名 |
| primaryReporterRole | String | 主报账人角色(如 DRIVER |
| primaryReporterCollectedAmount | BigDecimal | 主报账人代收金额(收入行合计),保留两位小数 |
| approvedAdvanceAmount | BigDecimal | 已审批预支金额(预支行合计),保留两位小数 |
| reportablePaidCostAmount | BigDecimal | 可报账已付成本(支出行合计),保留两位小数 |
| reporterNetAmount | BigDecimal | 报账人净额(代收 + 预支 - 支出);正 = 报账人应转回公司,负 = 公司应补报账人 |
| primaryReporterDueAmount | BigDecimal | 主报账人应收尾款(核单口径),保留两位小数 |
| transferAmount | BigDecimal | 转账金额(净额绝对值),保留两位小数 |
| generatedBy | Long(String) | 生成人 ID |
| generatedByName | String | 生成人姓名 |
| generatedAt | String | 生成时间,格式 yyyy-MM-dd HH:mm:ss |
| confirmedBy | Long(String) | 确认人 ID;未确认时为空 |
| confirmedByName | String | 确认人姓名;未确认时为空 |
| confirmedAt | String | 确认时间,格式 yyyy-MM-dd HH:mm:ss;未确认时为空 |
**转账方向判定**(替代被删的 transferDirection
- reporterNetAmount > 0 → 报账人应转回公司
- reporterNetAmount < 0 公司应补报账人
- transferAmount = |reporterNetAmount|
### 5.3 orderHeader 字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| orderNo | String | 订单号 |
| teamNo | String | 团号订金未支付为 null |
| productName | String | 产品名 |
| productType | String | 产品类型枚举 CORE |
| productTypeName | String | 产品类型中文名字典 product_type 回填 |
| customerName | String | 客户姓名 |
| departDate | String | 出团日期格式 yyyy-MM-dd |
| returnDate | String | **新增**返回日期格式 yyyy-MM-dd |
| consultantName | String | 定制师姓名 |
| travelerCount | Integer | **新增**出行人总数成人+儿童+幼童+婴儿空档按 0 |
| travelerComposition | String | 出行人构成数量为 0 的档不显示全空为 null), "2大 1儿童 1幼童" |
### 5.4 expenseLines 支出行字段表(统一扁平 12 字段)
**所有分类共用同一套字段**前端单 table 渲染即可不用再按类别分叉
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| category | String | | 费用类别 codeHOTEL / TICKET / MEAL / VEHICLE / GUIDE / PHOTOGRAPHER / OTHER_EXPENSE / INSURANCE |
| categoryName | String | | 费用类别中文名字典 settlement_category |
| itemName | String | | 项目名分类特有信息折叠见下方折叠规则表 |
| unitPrice | BigDecimal | | 单价保留两位小数;**无单价概念的分类不输出该键** |
| quantity | BigDecimal | | 数量住宿=房间数,餐食=份数,门票=票数,车辆按天每行=1;**无数量概念的分类不输出该键** |
| amount | BigDecimal | | 实际金额保留两位小数 |
| reimburseAmount | BigDecimal | | 报账金额保留两位小数人员行应报销与金额不同时分别给出其余分类与 amount 相同 |
| paymentMethod | String | | 付款方式报账支出行固定 CASH_PAID |
| paymentMethodName | String | | 付款方式中文名字典 settlement_payment_method缺值回退硬编码), "现金已付" |
| date | String | | 业务日期格式 yyyy-MM-dd住宿=入住日,门票=游玩日,餐食=用餐日,车辆=服务日,人员=结算日) |
| remark | String | | 备注;**无备注时不输出该键** |
| voucherUrls | Array<String> | 否 | 凭证 URL 数组;**无凭证时不输出该键** |
**itemName 折叠规则**(按 category
| category | itemName 格式 | 示例 |
|----------|--------------|------|
| HOTEL | 酒店名-房型 | 呼伦贝尔香格里拉大酒店-大床房 |
| TICKET | 景区名-规格 | 套娃景区-成人票 |
| MEAL | 餐食名(餐类型) | 手把肉套餐(午餐) |
| VEHICLE | 车牌 车型/司机 | 蒙A-E2E01 丰田普拉多/巴雅尔 |
| GUIDE / PHOTOGRAPHER | 人员姓名 | 巴特尔 |
| OTHER_EXPENSE / INSURANCE | 项目名 | 旅游意外险 |
### 5.5 incomeLines 收入行字段表(本次未动)
| 字段 | 类型 | 说明 |
|------|------|------|
| type | String | 行类型 code |
| typeName | String | 行类型中文名(字典 settlement_report_line_type |
| receiptId | Long(String) | 线下收款记录 ID |
| amount | BigDecimal | 收款金额,保留两位小数 |
| channel | String | 收款渠道 code |
| channelName | String | 收款渠道中文名PaymentChannelEnum 枚举 label |
| payType | String | 收款款项类型 code |
| payTypeName | String | 收款款项类型中文名PayType 枚举 label |
| collectorStaffId | Long(String) | 收款人人员安排 ID |
| collectorName | String | 收款人姓名 |
| collectorRole | String | 收款人角色 code |
| collectorRoleName | String | 收款人角色中文名(字典 staff_role |
| receivedAt | String | 收款时间,格式 yyyy-MM-dd HH:mm:ss |
| remark | String | 备注;无备注时为空 |
### 5.6 advanceLines 预支明细行字段表(本次未动)
| 字段 | 类型 | 说明 |
|------|------|------|
| type | String | 行类型 code |
| typeName | String | 行类型中文名(字典 settlement_report_line_type,如 "已审批预支" |
| advanceId | Long(String) | 预支单 ID |
| payeeStaffId | Long(String) | 借款对象人员安排 ID |
| payeeName | String | 借款对象姓名 |
| payeeRole | String | 借款对象角色 code |
| payeeRoleName | String | 借款对象角色中文名(字典 staff_role |
| advanceType | String | 预支类型 code |
| advanceTypeName | String | 预支类型中文名(字典 advance_type,如 "住宿押金" |
| amount | BigDecimal | 预支金额,保留两位小数 |
| purpose | String | 预支用途 |
| voucherUrl | String | 凭证 URL |
| status | String | 预支状态 code |
| statusText | String | 预支状态中文名AdvanceStatus 枚举 label,如 "已通过" |
| submittedAt | String | 提交时间,格式 yyyy-MM-dd HH:mm:ss |
| approvedAt | String | 审批时间,格式 yyyy-MM-dd HH:mm:ss |
| approvedBy | String | 审批人姓名 |
## 6. 枚举 / 数据字典
| 字段 | 来源 | 取值 |
|------|------|------|
| baseInfo.reportStatus | 枚举 | GENERATED已生成/ CONFIRMED已确认 |
| expenseLines.category | 字典 settlement_category | HOTEL住宿/ TICKET门票/游玩项目)/ MEAL餐食/ VEHICLE车辆/ GUIDE导游/ PHOTOGRAPHER摄影师/ OTHER_EXPENSE其他费用/ INSURANCE保险 |
| expenseLines.paymentMethod | 字典 settlement_payment_method | 报账支出行固定 CASH_PAID现金已付 |
| incomeLines.channel | PaymentChannelEnum | 收款渠道枚举 |
| incomeLines.payType | PayType 枚举 | 收款款项类型枚举(如尾款) |
| advanceLines.status | AdvanceStatus 枚举 | 预支状态(如已通过) |
| orderHeader.productType | 字典 product_type | 产品类型 |
**已删除的枚举字段**transferStatus#5816 连带下线、transferDirection#5859 删除,方向由 transferAmount 正负 / reporterNetAmount 表达)。
## 7. 错误码
| code | message | 触发场景 |
|------|---------|----------|
| 581007 | 订单不存在 | orderId 查不到订单 |
| 584088 | 核单凭证数据损坏,请联系管理员处理 | 快照读回时凭证数据异常(脏行),不会抛 500 |
| 400 | 订单 ID 必须大于 0 | orderId 路径参数校验失败 |
## 8. 示例
### 8.1 典型成功
请求:
GET /v3/admin/order/2087088947225038849/settlement/reports/reimbursement
响应(已核单 CONFIRMED 订单,含住宿/门票/餐食/车辆支出 + 一条已审批预支):
```json
{
"code": 200,
"message": "成功",
"data": {
"baseInfo": {
"id": "2087089146102255617",
"orderId": "2087088947225038849",
"reportStatus": "CONFIRMED",
"reportVersion": 1,
"primaryReporterId": "7001",
"primaryReporterName": "巴雅尔",
"primaryReporterRole": "DRIVER",
"primaryReporterCollectedAmount": 0,
"approvedAdvanceAmount": 3000.00,
"reportablePaidCostAmount": 1799.00,
"reporterNetAmount": -4799.00,
"primaryReporterDueAmount": 0,
"transferAmount": 4799.00,
"generatedBy": "2037350531801993218",
"generatedByName": "腰苏图",
"generatedAt": "2026-08-11 16:10:03",
"confirmedBy": "2037350531801993218",
"confirmedByName": "腰苏图",
"confirmedAt": "2026-08-11 16:10:03"
},
"orderHeader": {
"orderNo": "HL20260811001",
"teamNo": "T20260811001",
"productName": "呼伦贝尔草原 5 日游",
"productType": "CORE",
"productTypeName": "核心产品",
"customerName": "张三",
"departDate": "2026-08-29",
"returnDate": "2026-09-02",
"consultantName": "李四",
"travelerCount": 5,
"travelerComposition": "2大 1儿童 1幼童"
},
"incomeLines": [],
"expenseLines": [
{
"category": "HOTEL",
"categoryName": "住宿",
"itemName": "呼伦贝尔香格里拉大酒店-大床房",
"unitPrice": 320.00,
"quantity": 1,
"amount": 320.00,
"reimburseAmount": 320.00,
"paymentMethod": "CASH_PAID",
"paymentMethodName": "现金已付",
"date": "2026-08-29",
"remark": "含早",
"voucherUrls": ["https://oss.example.com/voucher/hotel-1.jpg"]
},
{
"category": "TICKET",
"categoryName": "门票/游玩项目",
"itemName": "套娃景区-成人票",
"unitPrice": 99.00,
"quantity": 1,
"amount": 99.00,
"reimburseAmount": 99.00,
"paymentMethod": "CASH_PAID",
"paymentMethodName": "现金已付",
"date": "2026-08-30"
},
{
"category": "MEAL",
"categoryName": "餐食",
"itemName": "手把肉套餐(午餐)",
"unitPrice": 68.00,
"quantity": 5,
"amount": 340.00,
"reimburseAmount": 340.00,
"paymentMethod": "CASH_PAID",
"paymentMethodName": "现金已付",
"date": "2026-08-30"
},
{
"category": "VEHICLE",
"categoryName": "车辆",
"itemName": "蒙A-E2E01 丰田普拉多/巴雅尔",
"unitPrice": 1000.00,
"quantity": 1,
"amount": 1000.00,
"reimburseAmount": 1000.00,
"paymentMethod": "CASH_PAID",
"paymentMethodName": "现金已付",
"date": "2026-08-29"
}
],
"advanceLines": [
{
"type": "APPROVED_ADVANCE",
"typeName": "已审批预支",
"advanceId": "5001",
"payeeStaffId": "7001",
"payeeName": "巴雅尔",
"payeeRole": "DRIVER",
"payeeRoleName": "司机",
"advanceType": "ACCOMMODATION_DEPOSIT",
"advanceTypeName": "住宿押金",
"amount": 3000.00,
"purpose": "酒店押金",
"voucherUrl": "https://oss.example.com/advance-v1.jpg",
"status": "APPROVED",
"statusText": "已通过",
"submittedAt": "2026-08-28 10:00:00",
"approvedAt": "2026-08-28 12:00:00",
"approvedBy": "财务丙"
}
]
},
"traceId": null,
"success": true
}
```
### 8.2 边界情况
**边界 1零收入零预支零支出**(刚生成报表、尚未录任何行)——三个数组固定返回空数组,不是 null
```json
{
"code": 200,
"data": {
"baseInfo": {
"id": "2087089146102255617",
"orderId": "2087088947225038849",
"reportStatus": "GENERATED",
"reportVersion": 1,
"primaryReporterId": "7001",
"primaryReporterName": "巴雅尔",
"primaryReporterRole": "DRIVER",
"primaryReporterCollectedAmount": 0,
"approvedAdvanceAmount": 0,
"reportablePaidCostAmount": 0,
"reporterNetAmount": 0,
"primaryReporterDueAmount": 0,
"transferAmount": 0,
"generatedBy": "2037350531801993218",
"generatedByName": "腰苏图",
"generatedAt": "2026-08-11 16:10:03",
"confirmedBy": null,
"confirmedByName": null,
"confirmedAt": null
},
"orderHeader": {
"orderNo": "HL20260811001",
"teamNo": null,
"productName": "呼伦贝尔草原 5 日游",
"productType": "CORE",
"productTypeName": "核心产品",
"customerName": "张三",
"departDate": "2026-08-29",
"returnDate": "2026-09-02",
"consultantName": "李四",
"travelerCount": 0,
"travelerComposition": null
},
"incomeLines": [],
"expenseLines": [],
"advanceLines": []
},
"success": true
}
```
**边界 2人员行GUIDE+ 无凭证无备注 + 报销金额与金额不同**——unitPrice/quantity/remark/voucherUrls 键不输出:
```json
{
"category": "GUIDE",
"categoryName": "导游",
"itemName": "巴特尔",
"amount": 500.00,
"reimburseAmount": 450.00,
"paymentMethod": "CASH_PAID",
"paymentMethodName": "现金已付",
"date": "2026-08-31"
}
```
**边界 3门票单价为 0**免费票——unitPrice: 0.0 正常输出,金额 0
```json
{
"category": "TICKET",
"categoryName": "门票/游玩项目",
"itemName": "蓝房子(乌苏浪子湖)-成人票",
"unitPrice": 0.0,
"quantity": 1,
"amount": 0.0,
"reimburseAmount": 0.0,
"paymentMethod": "CASH_PAID",
"paymentMethodName": "现金已付",
"date": "2026-08-31"
}
```
### 8.3 业务失败
**订单不存在**
GET /v3/admin/order/999999999/settlement/reports/reimbursement
```json
{
"code": 581007,
"message": "订单不存在",
"success": false
}
```
**参数校验失败**orderId = 0
GET /v3/admin/order/0/settlement/reports/reimbursement
```json
{
"code": 400,
"message": "订单 ID 必须大于 0",
"success": false
}
```
**房务角色访问被拦**House 角色 JWT 调用):
```json
{
"code": 403,
"message": "无权限访问",
"success": false
}
```
## 9. 业务边界
**适用**
- 订单已进入核单流程(已生成核单记录),查看主报账人维度的结算报表
- 已核单CONFIRMED与核单中GENERATED订单均可调,报表实时计算
**不适用**
- 未发起核单的订单baseInfo.id 等审计字段为空,汇总金额为 0
- 需要看整团(含非报账人支付)口径时用单团核算表接口 GET /v3/admin/order/{orderId}/settlement/reports/group,本接口是报账人视角
**特殊边界**
- **报账口径 A**expenseLines 只含报账人垫付CASH_PAID的支出;签单 / 公司直接付的车务费**不进** expenseLines,前端不要期待在支出行里看到所有成本
- incomeLines 只含报账人代收,线上支付(微信等)不在此列
- 旧快照兼容:历史已确认报表的旧快照数据读回时,旧扁平键静默忽略、落默认空 baseInfo,不会抛 500
## 10. 修改前后对比
### 10.1 顶层结构对比
| 维度 | 修改前 | 修改后 |
|------|--------|--------|
| 汇总字段 | 30+ 个平铺在顶层id/orderId/reportStatus/primaryReporterCollectedAmount/... | 全部收拢进 baseInfo 子对象 |
| 车辆支出 | 顶层独立 vehicleLines 数组(车辆专属字段) | 删除;车辆支出行并入 expenseLinescategory=VEHICLE |
| 订单头 | orderHeader9 字段) | orderHeader11 字段,新增 returnDate/travelerCount |
### 10.2 baseInfo 字段级对比(删除清单)
| 删除字段 | 原位置 | 替代取值 |
|----------|--------|----------|
| reconNetAmount | 顶层平铺 | baseInfo.reporterNetAmount同值镜像 |
| driverCollectedTailAmount | 顶层平铺 | baseInfo.primaryReporterCollectedAmount同值镜像 |
| publicPrepaidAmount | 顶层平铺 | baseInfo.approvedAdvanceAmount同口径 |
| advanceOutstandingAmount | 顶层平铺 | 无替代(该口径废弃,预支看 approvedAdvanceAmount + advanceLines |
| transferStatus | baseInfo#5816 连带下线) | 无替代(转账状态跟踪能力下线) |
| transferDirection | baseInfo | 由 reporterNetAmount 正负判定:正=报账人应转回公司,负=公司应补报账人;金额取 transferAmount |
> 其余原顶层平铺字段id/orderId/reportStatus/reportVersion/primaryReporter*/各金额/generated*/confirmed***字段名与语义不变**,仅位置从顶层移入 baseInfo。
### 10.3 expenseLines 字段级对比
| 修改前(按类别稀疏字段) | 修改后(统一扁平字段) |
|--------------------------|------------------------|
| HOTEL: hotelName / roomTypeName / stayDate / roomCount / unitPrice | itemName=「酒店-房型」/ date / quantity / unitPrice |
| TICKET: scenicName / specName / dayDate / ticketCount / ticketUnitPrice | itemName=「景区-规格」/ date / quantity / unitPrice |
| MEAL: mealName / mealTypeName / mealDate / quantity / unitPrice | itemName=「餐食名(餐类型)」/ date / quantity / unitPrice |
| VEHICLE: vehiclePlate / driverName / serviceDate / dailyPrice | itemName=「车牌 车型/司机」/ date / unitPricequantity 恒 1 |
| GUIDE/PHOTOGRAPHER: staffName / settledDate / amount / reimburseAmount | itemName=姓名 / date / amount / reimburseAmount |
| 各类各自的付款方式/备注/凭证字段名 | 统一 paymentMethod/paymentMethodName/remark/voucherUrls |
### 10.4 行为级对比
| 场景 | 修改前 | 修改后 |
|------|--------|--------|
| 签单/公司直付车务费 | 出现在 vehicleLines | 不出现在本接口任何行(口径 A只列报账人垫付 |
| 支出行渲染 | 前端按 7 族类别各写一套列 | 单 table 统一 12 字段渲染 |
| 调旧字段(如 data.reportStatus、data.vehicleLines、data.baseInfo.transferDirection | 有值 | **undefined**(字段不存在,不报错静默丢失) |
## 11. 影响评估 / 回滚
### 11.1 影响评估
- **破坏兼容性**:⚠️ 是。所有读顶层平铺汇总字段、读 vehicleLines、按类别分叉渲染支出行、读 transferStatus/transferDirection 的前端代码**全部失效**(取到 undefined
- **前端必须同步上线**:是。前端需要:
1. 汇总字段读取路径从 data.xxx 改为 data.baseInfo.xxx
2. 支出行渲染改为单 table 统一字段category/categoryName/itemName/unitPrice/quantity/amount/reimburseAmount/paymentMethod/paymentMethodName/date/remark/voucherUrls
3. 删除 vehicleLines 相关渲染
4. 转账方向展示改由 reporterNetAmount 正负 + transferAmount 推导
5. 4 个镜像字段改读保留字段(见 §10.2 替代表)
- **后端兼容**:旧快照数据读回不报错(静默忽略旧键),无需数据迁移。
### 11.2 回滚方案
- 后端回滚 = revert PR #5839 + PR #5865 两个 merge commit,重启 hl-order-service-v3。出参即恢复旧结构。
- 前端回滚 = 切回旧版前端包。前后端必须同版本(新后端 + 旧前端 = 页面全空)。
- 无 DDL,无数据迁移,回滚无残留风险。
## 12. 注意事项
1. **所有 Long ID 字段id/orderId/primaryReporterId/receiptId/advanceId/各种 staffId/generatedBy/confirmedBy序列化为 JSON 字符串**,前端按 string 处理,不要 Number() 转换(防 JS 精度丢失)。
2. expenseLines 中 unitPrice / quantity / remark / voucherUrls 是**条件输出键**无值时整个键不出现NON_NULL,前端取值前判空。
3. reimburseAmount 大多数分类与 amount 相同;只有人员行GUIDE/PHOTOGRAPHER应报销与金额可能不同,展示报账口径时以 reimburseAmount 为准。
4. 转账方向不要再找 transferDirection 字段:用 reporterNetAmount > 0 判「报账人转回公司」、< 0 公司补报账人」,transferAmount 恒为绝对值
5. orderHeader.travelerComposition 全空档时为 nullteamNo 订金未支付时为 null展示需兜底
6. 本接口与单团核算表 reports/group 是两个口径本接口 = 主报账人视角只含报账人垫付,group = 整团视角含全部成本)。前端不要把两个接口的行混在一起渲染
7. 车辆支出行在 expenseLines 里按服务日**逐天一行**quantity 1),不是一车一行
## 13. 关联 / 联系人
- Issue
- https://git.1814.love:8443/wx/HL/issues/5820 主报账人报账表 RespVO 重构
- https://git.1814.love:8443/wx/HL/issues/5859 transferDirection + orderHeader returnDate/travelerCount
- PR
- https://git.1814.love:8443/wx/HL/pulls/5839 #5820 出参重构
- https://git.1814.love:8443/wx/HL/pulls/5865 #5859 orderHeader 补字段 + transferDirection
- 服务hl-order-service-v3端口 8086
- 后端负责人腰苏图