From 1d88fab99dc84e3e2e84b65fa9b1a8e7a9a768bf Mon Sep 17 00:00:00 2001 From: yaosutu <770858045@qq.com> Date: Sun, 9 Aug 2026 14:17:09 +0800 Subject: [PATCH] =?UTF-8?q?feat(order-v3):=20=E6=A0=B8=E5=8D=95=E6=8A=A5?= =?UTF-8?q?=E8=A1=A8=E5=87=BA=E5=8F=82=E5=BC=BA=E7=B1=BB=E5=9E=8B=E5=8C=96?= =?UTF-8?q?=E8=A1=A5=E4=B8=AD=E6=96=87=E5=90=8D(#5729)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...表出参强类型化补中文名-修改接口-管理后台.md | 574 ++++++++++++++++++ 1 file changed, 574 insertions(+) create mode 100644 changelogs-v2/2026-08/09_5729_核单报表出参强类型化补中文名-修改接口-管理后台.md diff --git a/changelogs-v2/2026-08/09_5729_核单报表出参强类型化补中文名-修改接口-管理后台.md b/changelogs-v2/2026-08/09_5729_核单报表出参强类型化补中文名-修改接口-管理后台.md new file mode 100644 index 0000000..7818690 --- /dev/null +++ b/changelogs-v2/2026-08/09_5729_核单报表出参强类型化补中文名-修改接口-管理后台.md @@ -0,0 +1,574 @@ +--- +schema: "hl-changelog/v2" +ticket: "5729" +title: "核单报表(单团核算+报账表)出参明细数组 List 改为强类型 VO,并为所有枚举/字典 code 字段补充中文 xxxName 标签字段" +consumer: "admin" +change_type: "修改接口" +author: "yaosutu(GIT)" +backend_status: "deployed" +gateway_status: "verified" +frontend_status: "not_implemented" +frontend_owner: "" +frontend_ref: "" +target_release: "" +verified_at: "" +status_note: "PR #5743 已合并 dev-v3;单团核算 incomeLines/costCategories 与报账表 incomeLines/expenseLines/advanceLines/vehicleLines 共 6 个列表字段从 List> 改为强类型 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>`,前端无法生成 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` 改为 `List`,固定 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` 改为 `List`,固定 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` 改为 `List`,目前仅 `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` 改为 `List`,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` 改为 `List`: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `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 +``` + +```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 +``` + +```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 +``` + +```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>` | `List` | TS 类型可生成;新增 `typeName` 字段 | +| `SettlementGroupReportRespVO.costCategories` | `List>` | `List` | TS 类型可生成;新增 `categoryName` 字段 | +| `SettlementReimbursementReportRespVO.incomeLines` | `List>` | `List` | TS 类型可生成;新增 `typeName`/`channelName`/`payTypeName`/`collectorRoleName` | +| `SettlementReimbursementReportRespVO.expenseLines` | `List>` | `List` | TS 类型可生成;新增 `categoryName`/`paymentMethodName`/`mealTypeName`/`expenseTypeName`/`subsidyTypeName`/`staffRoleName`/`sourceTypeName` | +| `SettlementReimbursementReportRespVO.advanceLines` | `List>` | `List` | TS 类型可生成;新增 `typeName`/`payeeRoleName`/`advanceTypeName`/`statusText` | +| `SettlementReimbursementVehicleLineVO.sourceTypeName` | 不存在 | `String` | 新增字段 | + +### 10.2 行为级对比 + +| 方面 | 修改前 | 修改后 | +|---|---|---| +| 前端获取 code 中文名 | 需前端自维护 code→label 硬编码映射表 | 后端直接在出参里提供 `xxxName` 字段,前端直接渲染 | +| 类型安全 | `Map`,IDE 无补全,字段拼写错误运行时才发现 | 强类型 VO,Knife4j 和前端代码生成均有完整类型定义 | +| JSON 输出 | 所有 Map key 全量输出(含 null 值 key) | `@JsonInclude(NON_NULL)`,仅非 null 字段输出,JSON 体积减小 | +| 字典降级 | 前端硬编码,字典增减需发版 | 后端走数据字典动态加载(5 分钟本地缓存),字典变化实时生效 | + +## 11. 影响评估 / 回滚 + +- **破坏兼容**:否。本次为纯新增字段,旧字段名、类型、语义完全不变。前端不读新字段不影响现有功能。 +- **前端同步上线**:不强制同步。前端可先上线新接口对接(读 `xxxName` 替换硬编码),再逐步移除旧硬编码。但建议尽快适配以统一展示效果——后端字典更新后前端硬编码可能不同步。 +- **回滚方案**:若需回滚后端,前端需回退到读旧 Map 结构(字段名不变,只是少了 `xxxName`)。回滚到旧版后 `xxxName` 字段不再出现,前端如已移除硬编码则中文名会丢失。 + +## 12. 注意事项 + +1. **出参 JSON 的 key 集合可能有变化**:旧版 `List` 输出所有 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 / 腰苏图)