修正 frontmatter frontend_status 非法值 not_implemented -> pending 后走状态机:pending -> claimed -> implemented,frontend_ref 4f5f4e47。ReportModal 明细 code 列改由后端 xxxName/statusText 承载,缺 name 回退 code。
32 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, generated
| 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 | generated |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hl-changelog/v2 | 5729 | 核单报表(单团核算+报账表)出参明细数组 List<Map> 改为强类型 VO,并为所有枚举/字典 code 字段补充中文 xxxName 标签字段 | admin | 修改接口 | yaosutu(GIT) | deployed | verified | implemented | mmg | 4f5f4e47 | PR #5743 已合并 dev-v3;单团核算 incomeLines/costCategories 与报账表 incomeLines/expenseLines/advanceLines/vehicleLines 共 6 个列表字段从 List<Map<String,Object>> 改为强类型 VO;新增 13 个 xxxName/statusText 中文标签字段;新增 5 个数据字典。出参有新增字段、无删除字段,旧字段名保持不变——前端不传这些新字段不影响,但应尽快适配以展示中文名。 | 2026-08-09 | dev-v3 | 2026-08-09T18:00:00+08:00 |
核单报表(单团核算+报账表)出参强类型化并补充中文标签字段(#5729)
PR: #5743 | Commit: db8974cc9 | Merge: 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 典型成功(单团核算报表)
GET /v3/admin/order/2084000000000002978/settlement/reports/group
Authorization: Bearer <token>
{
"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 典型成功(报账表,含多族支出行、预支行、车辆逐日行)
GET /v3/admin/order/2084000000000002978/settlement/reports/reimbursement
Authorization: Bearer <token>
{
"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 边界情况(空数组:订单还未生成核单报表)
GET /v3/admin/order/2084000000000002999/settlement/reports/group
Authorization: Bearer <token>
{
"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. 注意事项
- 出参 JSON 的 key 集合可能有变化:旧版
List<Map>输出所有 key(含 null 值 key),新版@JsonInclude(NON_NULL)仅输出非 null key。前端按 key 遍历/检查存在性时注意——null 值的 key 不再出现,应使用!= null而非hasOwnProperty检查。 xxxName可能为 null:字典加载失败或 code 未命中时xxxName为 null(不阻断主流程),前端展示时应 fallback 到 code 原值或空字符串。不要假设xxxName一定非空。kind字段区分支出行族:报账表支出行的 7 个族(HOTEL / TICKET / MEAL / STAFF:* / VEHICLE_FEE / EXPENSE:* / SUBSIDY:*)共享同一个 VO,kind字段标识当前行属于哪个族,前端按kind前缀路由渲染组件。kind字段本次不变。- 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'判断。 - 车辆逐日行
vehicleFeeAdjustedAt时间格式:该字段格式为yyyy-MM-dd'T'HH:mm:ss(ISO-8601),不同于其他时间字段的yyyy-MM-dd HH:mm:ss,前端解析时注意。 staff_role字典新增DRIVER:团期人员角色下拉会新增「司机」选项(用户已确认接受此副作用)。
13. 关联 / 联系人
链接
联系人
- 后端负责人: @yst(yaosutu / 腰苏图)