---
schema: "hl-changelog/v2"
ticket: "5729"
title: "核单报表（单团核算+报账表）出参明细数组 List<Map> 改为强类型 VO，并为所有枚举/字典 code 字段补充中文 xxxName 标签字段"
consumer: "admin"
change_type: "修改接口"
author: "yaosutu(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "4f5f4e47"
target_release: ""
verified_at: ""
status_note: "PR #5743 已合并 dev-v3；单团核算 incomeLines/costCategories 与报账表 incomeLines/expenseLines/advanceLines/vehicleLines 共 6 个列表字段从 List<Map<String,Object>> 改为强类型 VO；新增 13 个 xxxName/statusText 中文标签字段；新增 5 个数据字典。出参有新增字段、无删除字段，旧字段名保持不变——前端不传这些新字段不影响，但应尽快适配以展示中文名。"
updated_at: "2026-08-09"
base: "dev-v3"
generated: "2026-08-09T18:00:00+08:00"
---

# 核单报表（单团核算+报账表）出参强类型化并补充中文标签字段（#5729）

> **PR**: [#5743](https://git.1814.love:8443/wx/HL/pulls/5743) | **Commit**: [db8974cc9](https://git.1814.love:8443/wx/HL/commit/db8974cc9) | **Merge**: [7b4c69aa8](https://git.1814.love:8443/wx/HL/commit/7b4c69aa8) | **服务**: hl-order-service-v3 | **更新时间**: 2026-08-09

## 1. 接口背景

核单模块的「单团核算报表」和「报账表」两个查询接口，此前明细数组（收入行、成本分类、支出行、预支行、车辆逐日行）返回类型为 `List<Map<String,Object>>`，前端无法生成 TypeScript 类型定义，且枚举/字典 code 字段（如 `type`、`category`、`channel`、`payType`、`collectorRole`、`staffRole`、`expenseType`、`subsidyType`、`advanceType`、`sourceType` 等）只有 code 没有对应中文名，前端需自行硬编码 code→label 映射。本次将 6 个列表字段改为强类型 VO，并为所有枚举/字典 code 新增对应的中文 `xxxName` / `statusText` 字段（后端走数据字典/枚举 label 回填），前端可直接展示中文名，逐步移除硬编码。

> 本次为出参扩展类变更：仅新增字段，无删除字段，旧字段名、类型、语义完全不变。前端不传/不读新字段不影响现有功能，但建议尽快适配以展示中文标签。

## 2. 变更清单

| # | 接口 | 方法 | 路径 | 变更类型 | 前端动作 |
|---|---|---|---|---|---|
| 1 | 查询单团核算表 | GET | `/v3/admin/order/{orderId}/settlement/reports/group` | 出参 `incomeLines[]` 从 Map 改 VO，新增 `typeName` | 类型适配，展示中文名 |
| 2 | 查询单团核算表 | GET | `/v3/admin/order/{orderId}/settlement/reports/group` | 出参 `costCategories[]` 从 Map 改 VO，新增 `categoryName` | 类型适配，展示中文名 |
| 3 | 查询报账表 | GET | `/v3/admin/order/{orderId}/settlement/reports/reimbursement` | 出参 `incomeLines[]` 从 Map 改 VO，新增 `typeName`/`channelName`/`payTypeName`/`collectorRoleName` | 类型适配，展示中文名 |
| 4 | 查询报账表 | GET | `/v3/admin/order/{orderId}/settlement/reports/reimbursement` | 出参 `expenseLines[]` 从 Map 改 VO，新增 `categoryName`/`paymentMethodName`/`mealTypeName`/`expenseTypeName`/`subsidyTypeName`/`staffRoleName`/`sourceTypeName` | 类型适配，展示中文名 |
| 5 | 查询报账表 | GET | `/v3/admin/order/{orderId}/settlement/reports/reimbursement` | 出参 `advanceLines[]` 从 Map 改 VO，新增 `typeName`/`payeeRoleName`/`advanceTypeName`/`statusText` | 类型适配，展示中文名 |
| 6 | 查询报账表 | GET | `/v3/admin/order/{orderId}/settlement/reports/reimbursement` | 出参 `vehicleLines[]` 新增 `sourceTypeName` | 展示中文名 |

## 3. 接口详情

- **使用场景**：核单人员在订单核单页查看单团核算报表（收入与成本汇总）和报账表（收支明细与预支），用于财务复核与结算。
- **认证**：需要管理后台登录态（Bearer Token）。
- **幂等性**：GET 接口，天然幂等。
- **限流**：未声明接口专属限流。
- **方法/路径**：见 §2 变更清单。

## 4. 接口入参

两个接口均为纯 GET 查询，仅路径参数：

| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `orderId` | Long | 是 | 订单 ID，路径参数，两个接口一致 |

无 Query 参数、无请求体。本次入参无变化。

## 5. 出参字段

> 以下仅列出本次有变更的行级 VO 字段；RespVO 顶层字段（如 `baseOrderAmount`/`totalCost`/`grossProfit` 等汇总字段）**不变**，不重复列出。

### 5.1 单团核算收入行（SettlementGroupIncomeLineVO）

`incomeLines[]` 从 `List<Map>` 改为 `List<SettlementGroupIncomeLineVO>`，固定 4 行：

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `type` | String | 是 | 行类型枚举 code：`BASE_ORDER`（订单应收）/ `OTHER_INCOME`（其他收入）/ `DISCOUNT`（优惠，负数）/ `ACTUAL_REFUND`（实际退款，负数） |
| `typeName` ⭐新增 | String | 否 | 行类型中文名，走 `settlement_report_line_type` 字典；`BASE_ORDER`→订单应收、`OTHER_INCOME`→其他收入、`DISCOUNT`→优惠、`ACTUAL_REFUND`→实际退款 |
| `amount` | BigDecimal | 是 | 金额，保留两位小数；DISCOUNT/ACTUAL_REFUND 为负数 |

### 5.2 单团核算成本分类行（SettlementGroupCostCategoryVO）

`costCategories[]` 从 `List<Map>` 改为 `List<SettlementGroupCostCategoryVO>`，固定 8 行：

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `category` | String | 是 | 费用类别 code：`HOTEL` / `TICKET` / `MEAL` / `VEHICLE` / `GUIDE` / `PHOTOGRAPHER` / `OTHER_EXPENSE` / `INSURANCE` |
| `categoryName` ⭐新增 | String | 否 | 费用类别中文名，走 `settlement_category` 字典；`HOTEL`→住宿、`TICKET`→门票/游玩项目、`MEAL`→餐食、`VEHICLE`→车辆、`GUIDE`→导游、`PHOTOGRAPHER`→摄影、`OTHER_EXPENSE`→其他支出、`INSURANCE`→保险 |
| `amount` | BigDecimal | 是 | 金额，保留两位小数 |

### 5.3 报账表收入行（SettlementReimbursementIncomeLineVO）

`incomeLines[]` 从 `List<Map>` 改为 `List<SettlementReimbursementIncomeLineVO>`，目前仅 `DRIVER_CASH_RECEIPT`（司机现金收款）一类：

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `type` | String | 是 | 行类型 code：当前固定 `DRIVER_CASH_RECEIPT` |
| `typeName` ⭐新增 | String | 否 | 行类型中文名，走 `settlement_report_line_type` 字典；`DRIVER_CASH_RECEIPT`→司机现金收款 |
| `receiptId` | Long | 否 | 线下收款记录 ID（Long，JSON 序列化为字符串） |
| `amount` | BigDecimal | 是 | 收款金额，保留两位小数 |
| `channel` | String | 否 | 收款渠道 code：`DRIVER_CASH` / `BANK_TRANSFER` / `CONSULTANT_COLLECTION` |
| `channelName` ⭐新增 | String | 否 | 收款渠道中文名，走 `PaymentChannelEnum` 枚举 label；`DRIVER_CASH`→报账人收款、`BANK_TRANSFER`→银行转账、`CONSULTANT_COLLECTION`→顾问代收 |
| `payType` | String | 否 | 收款款项类型 code：`DEPOSIT` / `FULL` / `BALANCE` |
| `payTypeName` ⭐新增 | String | 否 | 收款款项类型中文名，走 `PayType` 枚举 label；`DEPOSIT`→定金、`FULL`→全款、`BALANCE`→尾款 |
| `collectorStaffId` | Long | 否 | 收款人人员安排 ID（Long，JSON 序列化为字符串） |
| `collectorName` | String | 否 | 收款人姓名 |
| `collectorRole` | String | 否 | 收款人角色 code：如 `DRIVER` |
| `collectorRoleName` ⭐新增 | String | 否 | 收款人角色中文名，走 `staff_role` 字典；`DRIVER`→司机等 |
| `receivedAt` | String | 否 | 收款时间，格式 `yyyy-MM-dd HH:mm:ss` |
| `remark` | String | 否 | 备注；无备注时为空 |

### 5.4 报账表支出行（SettlementReimbursementExpenseLineVO）

`expenseLines[]` 从 `List<Map>` 改为 `List<SettlementReimbursementExpenseLineVO>`，7 族稀疏联合（每行仅本族字段非 null）：

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `kind` | String | 是 | 行种类：`HOTEL` / `TICKET` / `MEAL` / `VEHICLE_FEE` / `STAFF:GUIDE` / `EXPENSE:FUEL` / `SUBSIDY:MEAL` 等 |
| `category` | String | 是 | 费用类别 code：`HOTEL` / `TICKET` / `MEAL` / `VEHICLE` / `GUIDE` / `PHOTOGRAPHER` / `OTHER_EXPENSE` / `INSURANCE` |
| `categoryName` ⭐新增 | String | 否 | 费用类别中文名，走 `settlement_category` 字典（同 §5.2） |
| `amount` | BigDecimal | 是 | 实际金额，保留两位小数 |
| `paymentMethod` | String | 是 | 付款方式：`CASH_PAID` / `COMPANY_PAID` / `SIGNED` |
| `paymentMethodName` ⭐新增 | String | 否 | 付款方式中文名，走 `settlement_payment_method` 字典；`CASH_PAID`→现金已付、`COMPANY_PAID`→公司支付、`SIGNED`→签单 |
| `voucherUrls` | Array of String | 否 | 凭证 URL 数组；无凭证时为空数组 |
| `remark` | String | 否 | 备注 |
| -- | -- | -- | **以下按族分组，仅本族字段非 null** |
| `hotelAssignmentId` | Long | 否 | [HOTEL] 配房安排 ID |
| `hotelId` | Long | 否 | [HOTEL] 酒店资源 ID |
| `roomTypeId` | Long | 否 | [HOTEL] 房型 ID |
| `dayNumber` | Integer | 否 | [HOTEL/TICKET] 行程第几天 |
| `stayDate` | String | 否 | [HOTEL] 入住日期 yyyy-MM-dd |
| `hotelName` | String | 否 | [HOTEL] 酒店名称 |
| `roomType` | String | 否 | [HOTEL] 房型编码 |
| `roomTypeName` | String | 否 | [HOTEL] 房型名称 |
| `roomCount` | Integer | 否 | [HOTEL] 房间数 |
| `unitPrice` | BigDecimal | 否 | [HOTEL/MEAL] 单价 |
| `plannedCost` | BigDecimal | 否 | [HOTEL/TICKET] 计划成本 |
| `sourceType` | String | 否 | [HOTEL/TICKET] 明细来源类型 code |
| `sourceTypeName` ⭐新增 | String | 否 | [HOTEL/TICKET] 明细来源类型中文名，走 `SettlementDetailSourceType` 枚举 label |
| `sourceId` | Long | 否 | [HOTEL] 来源记录 ID |
| `scenicAssignmentId` | Long | 否 | [TICKET] 景区安排 ID |
| `dayDate` | String | 否 | [TICKET] 游玩日期 yyyy-MM-dd |
| `scenicName` | String | 否 | [TICKET] 景区/项目名称 |
| `specName` | String | 否 | [TICKET] 规格名称 |
| `ticketCount` | Integer | 否 | [TICKET] 票数 |
| `ticketUnitPrice` | BigDecimal | 否 | [TICKET] 门票单价 |
| `sellPrice` | BigDecimal | 否 | [TICKET] 销售价 |
| `totalAmount` | BigDecimal | 否 | [TICKET] 票面总额 |
| `mealType` | String | 否 | [MEAL] 餐食类型：`BREAKFAST` / `LUNCH` / `DINNER` / `SELF` |
| `mealTypeName` ⭐新增 | String | 否 | [MEAL] 餐食类型中文名，走 `meal_type` 字典；`BREAKFAST`→早餐、`LUNCH`→午餐、`DINNER`→晚餐、`SELF`→自理 |
| `mealDate` | String | 否 | [MEAL] 用餐日期 yyyy-MM-dd |
| `mealName` | String | 否 | [MEAL] 餐食名称 |
| `quantity` | Integer | 否 | [MEAL] 份数 |
| `staffRole` | String | 否 | [STAFF] 人员角色 code：`GUIDE` / `GUIDE_ASSISTANT` / `LEADER` / `PHOTOGRAPHER` / `DRIVER` / `OTHER` |
| `staffRoleName` ⭐新增 | String | 否 | [STAFF] 人员角色中文名，走 `staff_role` 字典 |
| `staffId` | Long | 否 | [STAFF] 人员安排 ID |
| `staffName` | String | 否 | [STAFF] 人员姓名 |
| `totalPlannedCost` | BigDecimal | 否 | [STAFF] 计划费用合计 |
| `reimburse` | BigDecimal | 否 | [STAFF] 应报销金额 |
| `detail` | Object | 否 | [STAFF] 人员费用嵌套明细（JSON 对象） |
| `settleStatus` | String | 否 | [STAFF] 结算状态 |
| `settledDate` | String | 否 | [STAFF] 结算日期 yyyy-MM-dd |
| `transferRef` | String | 否 | [STAFF] 转账流水号 |
| `sourceRecordType` | String | 否 | [VEHICLE_FEE] 来源记录类型 |
| `sourceDetailId` | Long | 否 | [VEHICLE_FEE] 车辆费用明细 ID |
| `serviceDate` | String | 否 | [VEHICLE_FEE] 服务日期 yyyy-MM-dd |
| `vehicleId` | Long | 否 | [VEHICLE_FEE] 车辆 ID |
| `vehiclePlate` | String | 否 | [VEHICLE_FEE] 车牌号 |
| `vehicleModelId` | Long | 否 | [VEHICLE_FEE] 车型 ID |
| `vehicleModelName` | String | 否 | [VEHICLE_FEE] 车型名称 |
| `driverId` | Long | 否 | [VEHICLE_FEE] 司机 ID |
| `driverName` | String | 否 | [VEHICLE_FEE] 司机姓名 |
| `startDate` | String | 否 | [VEHICLE_FEE] 服务开始日期 yyyy-MM-dd |
| `endDate` | String | 否 | [VEHICLE_FEE] 服务结束日期 yyyy-MM-dd |
| `dailyPrice` | BigDecimal | 否 | [VEHICLE_FEE] 日单价 |
| `paymentTypeCode` | String | 否 | [VEHICLE_FEE] 车务付款类型编码 |
| `paymentTypeName` | String | 否 | [VEHICLE_FEE] 车务付款类型名称（原已有字段，不变） |
| `vehicleFeeWaiverReason` | String | 否 | [VEHICLE_FEE] 车辆费用减免原因 |
| `vehicleFeeSource` | String | 否 | [VEHICLE_FEE] 车辆费用来源说明 |
| `vehicleFeeAdjustmentReason` | String | 否 | [VEHICLE_FEE] 车辆费用调整原因 |
| `vehicleFeeAdjustedBy` | Long | 否 | [VEHICLE_FEE] 车辆费用调整操作人 ID |
| `vehicleFeeAdjustedAt` | String | 否 | [VEHICLE_FEE] 车辆费用调整时间 |
| `expenseType` | String | 否 | [EXPENSE] 其他费用类型：`FUEL` / `TOLL` / `PARKING` / `RENTAL` / `MAINTENANCE` / `OTHER` |
| `expenseTypeName` ⭐新增 | String | 否 | [EXPENSE] 其他费用类型中文名，走 `expense_type` 字典；`FUEL`→油费、`TOLL`→过路费、`PARKING`→停车费、`RENTAL`→租车费、`MAINTENANCE`→维修保养、`OTHER`→其他 |
| `projectName` | String | 否 | [EXPENSE/SUBSIDY] 项目名称 |
| `expenseDate` | String | 否 | [EXPENSE/SUBSIDY] 费用发生日期 yyyy-MM-dd |
| `subsidyType` | String | 否 | [SUBSIDY] 补贴类型：`MEAL` / `PHONE` / `OVERTIME` / `OTHER` |
| `subsidyTypeName` ⭐新增 | String | 否 | [SUBSIDY] 补贴类型中文名，走 `subsidy_type` 字典；`MEAL`→餐补、`PHONE`→话补、`OVERTIME`→加班补贴、`OTHER`→其他 |

### 5.5 报账表预支行（SettlementReimbursementAdvanceLineVO）

`advanceLines[]` 从 `List<Map>` 改为 `List<SettlementReimbursementAdvanceLineVO>`：

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `type` | String | 是 | 行类型 code：当前固定 `APPROVED_ADVANCE` |
| `typeName` ⭐新增 | String | 否 | 行类型中文名，走 `settlement_report_line_type` 字典；`APPROVED_ADVANCE`→已审批预支 |
| `advanceId` | Long | 否 | 预支单 ID（Long，JSON 序列化为字符串） |
| `payeeStaffId` | Long | 否 | 借款对象人员安排 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 | 否 | 预支状态：`SUBMITTED` / `APPROVED` / `REJECTED` |
| `statusText` ⭐新增 | String | 否 | 预支状态中文名，走 `AdvanceStatus` 枚举 label；`SUBMITTED`→已提交、`APPROVED`→已通过、`REJECTED`→已拒绝 |
| `submittedAt` | String | 否 | 提交时间 yyyy-MM-dd HH:mm:ss |
| `approvedAt` | String | 否 | 审批时间 yyyy-MM-dd HH:mm:ss |
| `approvedBy` | String | 否 | 审批人姓名 |

### 5.6 报账表车辆逐日行（SettlementReimbursementVehicleLineVO）

`vehicleLines[]` 原已是强类型 VO，本次仅新增 1 个字段：

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `sourceTypeName` ⭐新增 | String | 否 | 车辆费用来源中文名，走 `SettlementDetailSourceType` 枚举 label；`FLEET`→车务、`MANUAL`→外部 |

其余字段（`sourceDetailId`、`serviceDate`、`vehicleId`、`vehiclePlate`、`vehicleModelId`、`vehicleModelName`、`driverId`、`driverName`、`dailyPrice`、`amount`、`paymentMethod`、`paymentMethodName`、`sourceType`、`draftLineId`、`settlementConfirmStatus`、`remark`、`voucherUrls`、`vehicleFeeWaiverReason`、`vehicleFeeSource`、`vehicleFeeAdjustmentReason`、`vehicleFeeAdjustedById`、`vehicleFeeAdjustedAt`）**不变**。

## 6. 枚举 / 数据字典

### 6.1 新增数据字典

本次通过 Flyway 迁移（`hl-user-service`）新建 5 个字典，并为 `staff_role` 补回 `DRIVER` 值：

| 字典类型 | dict_type_id | 值数 | 用途 | 取值 |
|---|---|---|---|---|
| `settlement_category` | 10143 | 8 | 核单费用类别中文名 | `HOTEL`→住宿、`TICKET`→门票/游玩项目、`MEAL`→餐食、`VEHICLE`→车辆、`GUIDE`→导游、`PHOTOGRAPHER`→摄影、`OTHER_EXPENSE`→其他支出、`INSURANCE`→保险 |
| `settlement_payment_method` | 10144 | 3 | 核单付款方式中文名 | `CASH_PAID`→现金已付、`COMPANY_PAID`→公司支付、`SIGNED`→签单 |
| `settlement_report_line_type` | 10145 | 6 | 核单报表行类型中文名 | `BASE_ORDER`→订单应收、`OTHER_INCOME`→其他收入、`DISCOUNT`→优惠、`ACTUAL_REFUND`→实际退款、`DRIVER_CASH_RECEIPT`→司机现金收款、`APPROVED_ADVANCE`→已审批预支 |
| `expense_type` | 10147 | 6 | 其他费用类型中文名 | `FUEL`→油费、`TOLL`→过路费、`PARKING`→停车费、`RENTAL`→租车费、`MAINTENANCE`→维修保养、`OTHER`→其他 |
| `subsidy_type` | 10148 | 4 | 补贴类型中文名 | `MEAL`→餐补、`PHONE`→话补、`OVERTIME`→加班补贴、`OTHER`→其他 |
| `staff_role` | 8012 | +1 | 人员角色补回 `DRIVER`；现有 5 值不变 | 新增 `DRIVER`→司机；原 `GUIDE`→导游、`GUIDE_ASSISTANT`→助理导游、`LEADER`→领队、`PHOTOGRAPHER`→摄影师、`OTHER`→其他 不变 |

> 注：`dict_type_id=10146` 跳过（`meal_type` 字典为历史手工所建，已存在，直接复用，不新建）。

### 6.2 涉及的既有枚举/字典（不变，仅补充中文名映射来源）

| 来源 | 作用字段 | 说明 |
|---|---|---|
| `PaymentChannelEnum` | `channelName` | `DRIVER_CASH`→报账人收款、`BANK_TRANSFER`→银行转账、`CONSULTANT_COLLECTION`→顾问代收 |
| `PayType` 枚举 | `payTypeName` | `DEPOSIT`→定金、`FULL`→全款、`BALANCE`→尾款 |
| `SettlementDetailSourceType` 枚举 | `sourceTypeName`（支出行 + 车辆行） | `MANUAL`→手工、`HOUSE_ASSIGNMENT`→配房结果、`SCENIC_ASSIGNMENT`→配景区结果 等 |
| `AdvanceStatus` 枚举 | `statusText` | `SUBMITTED`→已提交、`APPROVED`→已通过、`REJECTED`→已拒绝 |
| `advance_type` 字典 | `advanceTypeName` | 预支类型中文（如 `ACCOMMODATION_DEPOSIT`→住宿押金） |
| `meal_type` 字典 | `mealTypeName` | `BREAKFAST`→早餐、`LUNCH`→午餐、`DINNER`→晚餐、`SELF`→自理 |

## 7. 错误码

本次不涉及错误码新增、删除或语义变化。`584118`（报表数据未就绪）、`584066`（暂无主报账人）等既有错误码不变。

## 8. 示例

### 8.1 典型成功（单团核算报表）

```http
GET /v3/admin/order/2084000000000002978/settlement/reports/group
Authorization: Bearer <token>
```

```json
{
  "code": 200,
  "message": "success",
  "data": {
    "id": "1001",
    "orderId": "2084000000000002978",
    "reportStatus": "CONFIRMED",
    "baseOrderAmount": "12800.00",
    "otherIncomeAmount": "500.00",
    "discountAmount": "-200.00",
    "adjustedReceivableAmount": "12600.00",
    "paidAmount": "10000.00",
    "actualRefundedAmount": "-300.00",
    "netRevenueAmount": "12300.00",
    "netReceivedAmount": "9700.00",
    "outstandingAmount": "2600.00",
    "hotelCost": "3600.00",
    "ticketCost": "2400.00",
    "mealCost": "1200.00",
    "vehicleCost": "880.00",
    "guideCost": "500.00",
    "photographerCost": "0.00",
    "otherExpenseCost": "200.00",
    "insurancePremium": "150.00",
    "totalCost": "8930.00",
    "paidCost": "7500.00",
    "unpaidCost": "1430.00",
    "grossProfit": "3370.00",
    "grossProfitRate": "0.2740",
    "travelerCount": 8,
    "perCapitaRevenue": "1537.50",
    "perCapitaCost": "1116.25",
    "perCapitaProfit": "421.25",
    "incomeLines": [
      {"type": "BASE_ORDER", "typeName": "订单应收", "amount": "12800.00"},
      {"type": "OTHER_INCOME", "typeName": "其他收入", "amount": "500.00"},
      {"type": "DISCOUNT", "typeName": "优惠", "amount": "-200.00"},
      {"type": "ACTUAL_REFUND", "typeName": "实际退款", "amount": "-300.00"}
    ],
    "costCategories": [
      {"category": "HOTEL", "categoryName": "住宿", "amount": "3600.00"},
      {"category": "TICKET", "categoryName": "门票/游玩项目", "amount": "2400.00"},
      {"category": "MEAL", "categoryName": "餐食", "amount": "1200.00"},
      {"category": "VEHICLE", "categoryName": "车辆", "amount": "880.00"},
      {"category": "GUIDE", "categoryName": "导游", "amount": "500.00"},
      {"category": "PHOTOGRAPHER", "categoryName": "摄影", "amount": "0.00"},
      {"category": "OTHER_EXPENSE", "categoryName": "其他支出", "amount": "200.00"},
      {"category": "INSURANCE", "categoryName": "保险", "amount": "150.00"}
    ],
    "generatedBy": "2037",
    "generatedByName": "腰苏图",
    "generatedAt": "2026-08-08T15:30:00",
    "confirmedBy": null,
    "confirmedByName": null,
    "confirmedAt": null
  },
  "success": true
}
```

### 8.2 典型成功（报账表，含多族支出行、预支行、车辆逐日行）

```http
GET /v3/admin/order/2084000000000002978/settlement/reports/reimbursement
Authorization: Bearer <token>
```

```json
{
  "code": 200,
  "message": "success",
  "data": {
    "id": "2001",
    "orderId": "2084000000000002978",
    "reportStatus": "CONFIRMED",
    "primaryReporterId": "7001",
    "primaryReporterName": "司机甲",
    "primaryReporterRole": "DRIVER",
    "driverCollectedTailAmount": "5000.00",
    "approvedAdvanceAmount": "3000.00",
    "reportablePaidCostAmount": "7500.00",
    "reporterNetAmount": "-2500.00",
    "incomeLines": [
      {
        "type": "DRIVER_CASH_RECEIPT",
        "typeName": "司机现金收款",
        "receiptId": "8001",
        "amount": "2000.00",
        "channel": "DRIVER_CASH",
        "channelName": "报账人收款",
        "payType": "BALANCE",
        "payTypeName": "尾款",
        "collectorStaffId": "7001",
        "collectorName": "司机甲",
        "collectorRole": "DRIVER",
        "collectorRoleName": "司机",
        "receivedAt": "2026-08-06 18:20:30",
        "remark": "尾款现金"
      }
    ],
    "expenseLines": [
      {
        "kind": "HOTEL",
        "category": "HOTEL",
        "categoryName": "住宿",
        "amount": "1200.00",
        "paymentMethod": "CASH_PAID",
        "paymentMethodName": "现金已付",
        "voucherUrls": ["https://oss.example.com/v1.jpg"],
        "remark": "含早",
        "hotelAssignmentId": "6001",
        "hotelName": "草原明珠大酒店",
        "roomType": "STANDARD",
        "roomTypeName": "标间",
        "roomCount": 3,
        "unitPrice": "400.00",
        "plannedCost": "1200.00",
        "sourceType": "HOUSE_ASSIGNMENT",
        "sourceTypeName": "配房结果",
        "dayNumber": 2,
        "stayDate": "2026-08-06"
      },
      {
        "kind": "TICKET",
        "category": "TICKET",
        "categoryName": "门票/游玩项目",
        "amount": "600.00",
        "paymentMethod": "CASH_PAID",
        "paymentMethodName": "现金已付",
        "voucherUrls": [],
        "scenicName": "希拉穆仁草原",
        "specName": "成人票",
        "ticketCount": 5,
        "ticketUnitPrice": "120.00",
        "sellPrice": "150.00",
        "totalAmount": "600.00",
        "sourceType": "SCENIC_ASSIGNMENT",
        "sourceTypeName": "配景区结果",
        "dayNumber": 3,
        "dayDate": "2026-08-07"
      },
      {
        "kind": "STAFF:GUIDE",
        "category": "GUIDE",
        "categoryName": "导游",
        "amount": "300.00",
        "paymentMethod": "CASH_PAID",
        "paymentMethodName": "现金已付",
        "voucherUrls": [],
        "staffRole": "GUIDE",
        "staffRoleName": "导游",
        "staffId": "7011",
        "staffName": "导游乙",
        "totalPlannedCost": "1500.00",
        "reimburse": "300.00",
        "detail": {},
        "settleStatus": "COMPLETED",
        "settledDate": "2026-08-08",
        "transferRef": "TX20260808001"
      },
      {
        "kind": "EXPENSE:FUEL",
        "category": "OTHER_EXPENSE",
        "categoryName": "其他支出",
        "amount": "200.00",
        "paymentMethod": "CASH_PAID",
        "paymentMethodName": "现金已付",
        "voucherUrls": [],
        "expenseType": "FUEL",
        "expenseTypeName": "油费",
        "projectName": "全程油费",
        "expenseDate": "2026-08-06"
      },
      {
        "kind": "SUBSIDY:MEAL",
        "category": "OTHER_EXPENSE",
        "categoryName": "其他支出",
        "amount": "150.00",
        "paymentMethod": "CASH_PAID",
        "paymentMethodName": "现金已付",
        "voucherUrls": [],
        "subsidyType": "MEAL",
        "subsidyTypeName": "餐补",
        "projectName": "每日餐补",
        "expenseDate": "2026-08-06"
      }
    ],
    "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-05 10:00:00",
        "approvedAt": "2026-08-05 12:00:00",
        "approvedBy": "财务丙"
      }
    ],
    "vehicleLines": [
      {
        "sourceDetailId": "9001",
        "serviceDate": "2026-08-06",
        "vehicleId": "9101",
        "vehiclePlate": "蒙A-5376",
        "vehicleModelId": "9201",
        "vehicleModelName": "坦克500",
        "driverId": "9301",
        "driverName": "司机甲",
        "dailyPrice": "880.00",
        "amount": "880.00",
        "paymentMethod": "CASH_PAID",
        "paymentMethodName": "现金已付",
        "sourceType": "FLEET",
        "sourceTypeName": "车务",
        "draftLineId": "9401",
        "settlementConfirmStatus": "CONFIRMED",
        "remark": null,
        "voucherUrls": []
      }
    ],
    "generatedBy": "2037",
    "generatedByName": "腰苏图",
    "generatedAt": "2026-08-08T15:30:00"
  },
  "success": true
}
```

### 8.3 边界情况（空数组：订单还未生成核单报表）

```http
GET /v3/admin/order/2084000000000002999/settlement/reports/group
Authorization: Bearer <token>
```

```json
{
  "code": 584118,
  "message": "核单报表数据未就绪，请先完成核单",
  "data": null,
  "success": false
}
```

当订单尚未完成核单（无终态快照）时，两个报表接口均返回 `584118`。完成核单后，两个接口正常返回数据，`incomeLines` / `costCategories` / `expenseLines` / `advanceLines` 等明细数组无数据时为空数组 `[]`（不会是 null）。

## 9. 业务边界

- **适用状态**：订单已完成核单（存在终态快照），`settlement_status` 为 `COMPLETED` 或已反确认重开前曾确认过。
- **不适用状态**：核单未完成（`settlement_status=PENDING` 或其他中间态）时返回 `584118`（报表数据未就绪）。
- **特殊边界**：
  - 单团核算 `incomeLines[]` 固定 4 行（BASE_ORDER / OTHER_INCOME / DISCOUNT / ACTUAL_REFUND），无数据行也不缺行（金额为 0）。
  - 单团核算 `costCategories[]` 固定 8 行（HOTEL~INSURANCE），同样不缺行。
  - 报账表 `incomeLines[]` 目前仅司机现金收款行，无司机收款时为空数组。
  - 报账表 `expenseLines[]` 每行仅本族字段非 null（`@JsonInclude(NON_NULL)`），前端按 `kind` 前缀（如 `HOTEL` / `TICKET` / `MEAL` / `STAFF:` / `VEHICLE_FEE` / `EXPENSE:` / `SUBSIDY:`）区分族渲染。
  - `xxxName` 字段在字典不可用或 code 未命中时可能为 null（不阻断主流程），前端展示时应降级回 code 或以空字符串处理。

## 10. 修改前后对比

### 10.1 字段级对比

| 数组字段 | 修改前类型 | 修改后类型 | 影响 |
|---|---|---|---|
| `SettlementGroupReportRespVO.incomeLines` | `List<Map<String,Object>>` | `List<SettlementGroupIncomeLineVO>` | TS 类型可生成；新增 `typeName` 字段 |
| `SettlementGroupReportRespVO.costCategories` | `List<Map<String,Object>>` | `List<SettlementGroupCostCategoryVO>` | TS 类型可生成；新增 `categoryName` 字段 |
| `SettlementReimbursementReportRespVO.incomeLines` | `List<Map<String,Object>>` | `List<SettlementReimbursementIncomeLineVO>` | TS 类型可生成；新增 `typeName`/`channelName`/`payTypeName`/`collectorRoleName` |
| `SettlementReimbursementReportRespVO.expenseLines` | `List<Map<String,Object>>` | `List<SettlementReimbursementExpenseLineVO>` | TS 类型可生成；新增 `categoryName`/`paymentMethodName`/`mealTypeName`/`expenseTypeName`/`subsidyTypeName`/`staffRoleName`/`sourceTypeName` |
| `SettlementReimbursementReportRespVO.advanceLines` | `List<Map<String,Object>>` | `List<SettlementReimbursementAdvanceLineVO>` | TS 类型可生成；新增 `typeName`/`payeeRoleName`/`advanceTypeName`/`statusText` |
| `SettlementReimbursementVehicleLineVO.sourceTypeName` | 不存在 | `String` | 新增字段 |

### 10.2 行为级对比

| 方面 | 修改前 | 修改后 |
|---|---|---|
| 前端获取 code 中文名 | 需前端自维护 code→label 硬编码映射表 | 后端直接在出参里提供 `xxxName` 字段，前端直接渲染 |
| 类型安全 | `Map<String,Object>`，IDE 无补全，字段拼写错误运行时才发现 | 强类型 VO，Knife4j 和前端代码生成均有完整类型定义 |
| JSON 输出 | 所有 Map key 全量输出（含 null 值 key） | `@JsonInclude(NON_NULL)`，仅非 null 字段输出，JSON 体积减小 |
| 字典降级 | 前端硬编码，字典增减需发版 | 后端走数据字典动态加载（5 分钟本地缓存），字典变化实时生效 |

## 11. 影响评估 / 回滚

- **破坏兼容**：否。本次为纯新增字段，旧字段名、类型、语义完全不变。前端不读新字段不影响现有功能。
- **前端同步上线**：不强制同步。前端可先上线新接口对接（读 `xxxName` 替换硬编码），再逐步移除旧硬编码。但建议尽快适配以统一展示效果——后端字典更新后前端硬编码可能不同步。
- **回滚方案**：若需回滚后端，前端需回退到读旧 Map 结构（字段名不变，只是少了 `xxxName`）。回滚到旧版后 `xxxName` 字段不再出现，前端如已移除硬编码则中文名会丢失。

## 12. 注意事项

1. **出参 JSON 的 key 集合可能有变化**：旧版 `List<Map>` 输出所有 key（含 null 值 key），新版 `@JsonInclude(NON_NULL)` 仅输出非 null key。前端按 key 遍历/检查存在性时注意——null 值的 key 不再出现，应使用 `!= null` 而非 `hasOwnProperty` 检查。
2. **`xxxName` 可能为 null**：字典加载失败或 code 未命中时 `xxxName` 为 null（不阻断主流程），前端展示时应 fallback 到 code 原值或空字符串。不要假设 `xxxName` 一定非空。
3. **`kind` 字段区分支出行族**：报账表支出行的 7 个族（HOTEL / TICKET / MEAL / STAFF:* / VEHICLE_FEE / EXPENSE:* / SUBSIDY:*）共享同一个 VO，`kind` 字段标识当前行属于哪个族，前端按 `kind` 前缀路由渲染组件。`kind` 字段本次不变。
4. **Long 类型 ID 字段**：`receiptId`、`collectorStaffId`、`advanceId`、`payeeStaffId`、`staffId`、`hotelAssignmentId`、`hotelId`、`roomTypeId`、`sourceId`、`scenicAssignmentId`、`sourceDetailId`、`vehicleId`、`vehicleModelId`、`driverId`、`vehicleFeeAdjustedBy`、`draftLineId` 等均为 Long 类型，JSON 序列化为**字符串**（`@JsonSerialize(using = ToStringSerializer.class)`），前端注意不要用 `typeof === 'number'` 判断。
5. **车辆逐日行 `vehicleFeeAdjustedAt` 时间格式**：该字段格式为 `yyyy-MM-dd'T'HH:mm:ss`（ISO-8601），不同于其他时间字段的 `yyyy-MM-dd HH:mm:ss`，前端解析时注意。
6. **`staff_role` 字典新增 `DRIVER`**：团期人员角色下拉会新增「司机」选项（用户已确认接受此副作用）。

## 13. 关联 / 联系人

### 链接

- **Issue**: [#5729](https://git.1814.love:8443/wx/HL/issues/5729)
- **PR**: [#5743](https://git.1814.love:8443/wx/HL/pulls/5743)
- **Commit**: [db8974cc9](https://git.1814.love:8443/wx/HL/commit/db8974cc9)
- **Merge commit**: [7b4c69aa8](https://git.1814.love:8443/wx/HL/commit/7b4c69aa8)

### 联系人

- **后端负责人**: @yst（yaosutu / 腰苏图）
