hl-api-changelog/changelogs-v2/2026-07/29_5325_核单人员费用分Tab-修改接口-管理后台.md
Mimingguang d65d0e22bb
所有检测均成功
changelog-filename-gate / validate (push) Successful in 3s
chore(changelog): 完成 5325 管理后台接入
修改原因:管理后台已完成五类人员费用独立 Tab 接入,需要回写消费终态。

修改内容:将 #5325 frontend_status 更新为 implemented,并记录可达业务提交 4cea39f7e87e74f42fb28ab260da12b585f034de。

实际验证:npm test 通过 46 项 changelog 质量门禁;git diff --check 通过。

Changelog:changelogs-v2/2026-07/29_5325_核单人员费用分Tab-修改接口-管理后台.md
2026-07-29 17:21:59 +08:00

1067 行
32 KiB
Markdown

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

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

---
schema: "hl-changelog/v2"
ticket: "5325"
title: "核单人员费用分 Tab"
consumer: "admin"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "hl-ui-pi"
frontend_ref: "mmg/hl-ui@4cea39f7e87e74f42fb28ab260da12b585f034de"
target_release: ""
verified_at: ""
status_note: ""
updated_at: "2026-07-29"
base: "dev-v3"
---
# ⚠️【修改接口·管理后台】核单人员费用分 Tab#5325
> **PR**#5332 **服务**hl-order-service-v3 **更新时间**2026-07-29
## 1. 接口背景
核单页面的领队、司机、导游、摄影师、其他人员是五个独立 Tab,需要分别加载、分别保存。原 `/settlement/step3` 把所有人员类型聚合在同一请求中,还要求调用方提交人员类型;车辆费用也曾通过 Order 管理端接口直接暴露。
本次将人员费用改为五组独立 GET/PUT。人员类型由接口路径唯一确定,保存请求不再接收人员类型;每次 PUT 只全量替换当前 Tab,成功响应只表达成功,不返回新增、修改或删除的数据 ID。旧 Step3 和两个 Order 管理端车辆费用接口直接删除,不保留兼容路由。
## 变更接口
本次对外契约由五组独立 GET/PUT 和四个删除路由组成,完整清单如下。
## 2. 变更清单
| # | 接口名 | 方法 | 路径 | 变更类型 | 说明 |
|---|--------|------|------|----------|------|
| 1 | 查询领队人员费用 | GET | `/v3/admin/order/:orderId/settlement/staff-fees/leaders` | 新增接口 | 仅返回领队 Tab |
| 2 | 保存领队人员费用 | PUT | `/v3/admin/order/:orderId/settlement/staff-fees/leaders` | 新增接口 | 路径固定为领队,全量替换领队 Tab |
| 3 | 查询司机人员费用 | GET | `/v3/admin/order/:orderId/settlement/staff-fees/drivers` | 新增接口 | 仅返回司机 Tab |
| 4 | 保存司机人员费用 | PUT | `/v3/admin/order/:orderId/settlement/staff-fees/drivers` | 新增接口 | 路径固定为司机,全量替换司机 Tab |
| 5 | 查询导游人员费用 | GET | `/v3/admin/order/:orderId/settlement/staff-fees/guides` | 新增接口 | 仅返回导游 Tab |
| 6 | 保存导游人员费用 | PUT | `/v3/admin/order/:orderId/settlement/staff-fees/guides` | 新增接口 | 路径固定为导游,全量替换导游 Tab |
| 7 | 查询摄影师人员费用 | GET | `/v3/admin/order/:orderId/settlement/staff-fees/photographers` | 新增接口 | 仅返回摄影师 Tab |
| 8 | 保存摄影师人员费用 | PUT | `/v3/admin/order/:orderId/settlement/staff-fees/photographers` | 新增接口 | 路径固定为摄影师,全量替换摄影师 Tab |
| 9 | 查询其他人员费用 | GET | `/v3/admin/order/:orderId/settlement/staff-fees/others` | 新增接口 | 仅返回其他人员 Tab |
| 10 | 保存其他人员费用 | PUT | `/v3/admin/order/:orderId/settlement/staff-fees/others` | 新增接口 | 路径固定为其他人员,全量替换其他人员 Tab |
| 11 | Step3 聚合查询 | GET | `/v3/admin/order/:orderId/settlement/step3` | 删除接口 | 不保留兼容 |
| 12 | Step3 聚合保存 | PUT | `/v3/admin/order/:orderId/settlement/step3` | 删除接口 | 不保留兼容 |
| 13 | 查询核单车辆总车费 | GET | `/v3/admin/order/:orderId/settlement/vehicle-fees` | 删除接口 | 管理后台不再直接调用 |
| 14 | 确认并冻结核单车辆总车费 | POST | `/v3/admin/order/:orderId/settlement/vehicle-fees/confirm` | 删除接口 | 管理后台不再直接调用 |
## 3. 接口详情
五组接口均使用管理后台登录态,`orderId` 必须大于 0。GET 只返回路径所代表的人员类型;PUT 只替换路径所代表的 Tab,不影响另外四个 Tab。
### 3.1 领队 Tab
- **查询**`GET /v3/admin/order/:orderId/settlement/staff-fees/leaders`
- **保存**`PUT /v3/admin/order/:orderId/settlement/staff-fees/leaders`
- **人员类型**路径固定为领队,PUT 不传 `staffRole`
- **保存语义**:全量替换领队 Tab;`items: []` 表示清空领队 Tab
- **人员引用**:每行 `staffId` 必填,必须属于当前订单的领队
- **费用明细**
| `detail` 字段 | 类型 | 必填 | 说明 | 校验 |
|---------------|------|------|------|------|
| `days` | Integer | 是 | 服务天数 | `>= 0` |
| `per_day` | Decimal | 是 | 每天费用 | `>= 0` |
- **费用口径**:计划成本为 `days × per_day`;实际成本为 `days × per_day + reimburse`
### 3.2 司机 Tab
- **查询**`GET /v3/admin/order/:orderId/settlement/staff-fees/drivers`
- **保存**`PUT /v3/admin/order/:orderId/settlement/staff-fees/drivers`
- **人员类型**路径固定为司机,PUT 不传 `staffRole`
- **保存语义**:全量替换司机 Tab;`items: []` 表示清空司机 Tab
- **人员引用**:每行 `staffId` 必填,必须属于当前订单的司机
- **费用明细**
| `detail` 字段 | 类型 | 必填 | 说明 | 校验 |
|---------------|------|------|------|------|
| `days` | Array | 是 | 服务日明细 | 可为空数组 |
| `days[].service_date` | String(date) | 是 | 服务日期 | `YYYY-MM-DD` |
| `days[].vehicle_brief` | String | 否 | 车辆摘要 | 可空 |
| `days[].daily_fee` | Decimal | 是 | 日费,仅回显,不计入人员费用 | `>= 0` |
| `days[].is_used` | Boolean | 否 | 是否使用 | 可空 |
| `days[].note` | String | 否 | 服务日备注 | 可空 |
| `extra_cost` | Decimal | 否 | 司机额外费用 | 空按 0,且 `>= 0` |
| `extra_breakdown` | Array | 否 | 额外费用说明 | 各项金额合计必须等于 `extra_cost` |
| `extra_breakdown[].name` | String | 是 | 费用名称 | 非空 |
| `extra_breakdown[].amount` | Decimal | 是 | 金额 | `>= 0` |
| `extra_breakdown[].note` | String | 否 | 备注 | 可空 |
- **费用口径**:司机基础服务费不在人员费用中重复计算;计划成本为 0,实际成本为 `extra_cost + reimburse`
### 3.3 导游 Tab
- **查询**`GET /v3/admin/order/:orderId/settlement/staff-fees/guides`
- **保存**`PUT /v3/admin/order/:orderId/settlement/staff-fees/guides`
- **人员类型**路径固定为导游,PUT 不传 `staffRole`
- **保存语义**:全量替换导游 Tab;`items: []` 表示清空导游 Tab
- **人员引用**`staffId` 可空;非空时必须属于当前订单的导游,空值表示按 `persons[]` 保存聚合行
- **费用明细**
| `detail` 字段 | 类型 | 必填 | 说明 | 校验 |
|---------------|------|------|------|------|
| `persons` | Array | 是 | 导游计费明细 | 可为空数组 |
| `persons[].name` | String | 是 | 姓名 | 非空 |
| `persons[].days` | Integer | 是 | 天数 | `>= 0` |
| `persons[].per_day` | Decimal | 是 | 每天费用 | `>= 0` |
| `persons[].note` | String | 否 | 备注 | 可空 |
- **费用口径**:计划成本为 `Σ(persons[].days × persons[].per_day)`;实际成本为计划成本加 `reimburse`
### 3.4 摄影师 Tab
- **查询**`GET /v3/admin/order/:orderId/settlement/staff-fees/photographers`
- **保存**`PUT /v3/admin/order/:orderId/settlement/staff-fees/photographers`
- **人员类型**路径固定为摄影师,PUT 不传 `staffRole`
- **保存语义**:全量替换摄影师 Tab;`items: []` 表示清空摄影师 Tab
- **人员引用**`staffId` 可空;非空时必须属于当前订单的摄影师,空值表示按 `persons[]` 保存聚合行
- **费用明细**
| `detail` 字段 | 类型 | 必填 | 说明 | 校验 |
|---------------|------|------|------|------|
| `persons` | Array | 是 | 摄影师计费明细 | 可为空数组 |
| `persons[].name` | String | 是 | 姓名 | 非空 |
| `persons[].days` | Integer | 是 | 天数 | `>= 0` |
| `persons[].per_day` | Decimal | 是 | 每天费用 | `>= 0` |
| `persons[].note` | String | 否 | 备注 | 可空 |
- **费用口径**:计划成本为 `Σ(persons[].days × persons[].per_day)`;实际成本为计划成本加 `reimburse`
### 3.5 其他人员 Tab
- **查询**`GET /v3/admin/order/:orderId/settlement/staff-fees/others`
- **保存**`PUT /v3/admin/order/:orderId/settlement/staff-fees/others`
- **人员类型**路径固定为其他人员,PUT 不传 `staffRole`
- **保存语义**:全量替换其他人员 Tab;`items: []` 表示清空其他人员 Tab
- **人员引用**`staffId` 可空;非空时必须属于当前订单的其他人员,空值表示按 `detail.items[]` 保存聚合行
- **费用明细**
| `detail` 字段 | 类型 | 必填 | 说明 | 校验 |
|---------------|------|------|------|------|
| `items` | Array | 是 | 其他人员费用项 | 可为空数组 |
| `items[].name` | String | 是 | 费用名称 | 非空 |
| `items[].amount` | Decimal | 是 | 金额 | `>= 0` |
| `items[].note` | String | 否 | 备注 | 可空 |
- **费用口径**:计划成本为 `Σ(detail.items[].amount)`;实际成本为计划成本加 `reimburse`
## 4. 接口入参
### 4.1 GET 路径参数
五个 GET 的路径参数相同。
| 字段 | 类型 | 必填 | 说明 | 校验 |
|------|------|------|------|------|
| `orderId` | String | 是 | 订单 ID | 正整数 |
GET 无 Query 参数、无请求体。
### 4.2 PUT 路径参数
五个 PUT 的路径参数相同。
| 字段 | 类型 | 必填 | 说明 | 校验 |
|------|------|------|------|------|
| `orderId` | String | 是 | 订单 ID | 正整数 |
### 4.3 PUT 请求体
| 字段 | 类型 | 必填 | 说明 | 校验 |
|------|------|------|------|------|
| `items` | Array | 是 | 当前 Tab 的完整人员费用行 | 空数组表示清空当前 Tab |
### 4.4 PUT `items[]` 通用字段
| 字段 | 类型 | 必填 | 说明 | 校验/默认值 |
|------|------|------|------|-------------|
| `staffId` | String | 条件必填 | 当前订单人员分配 ID | 领队、司机必填;其他三个 Tab 可空;非空时必须属于当前订单且角色与路径一致 |
| `detail` | Object | 是 | 当前 Tab 对应的角色明细 | 结构见 §3 |
| `reimburse` | Decimal | 否 | 小额报销 | 空按 0,且 `>= 0` |
| `paymentMethod` | String | 否 | 付款方式 | 空按 `COMPANY_PAID` |
| `voucherUrls` | String[] | 否 | 凭证 URL | 最多 9 个;每个非空、最长 1024 字符,仅支持 HTTP/HTTPS |
| `settleStatus` | String | 否 | 辅助人员结算状态 | 空按 `PENDING`;主报账人行不使用该字段 |
| `settledDate` | String(date) | 否 | 辅助人员结算日期 | `YYYY-MM-DD`;主报账人行不使用该字段 |
| `transferRef` | String | 条件必填 | 辅助人员结算转账流水号 | 最长 128 字符;辅助人员 `settleStatus=COMPLETED` 时必填;主报账人行不使用该字段 |
| `remark` | String | 否 | 备注 | 最长 500 字符 |
### 4.5 PUT 禁止提交的字段
请求体采用严格字段校验。以下字段属于路径确定项、服务端状态或查询回显,不得提交:
| 禁止字段 | 原因 |
|----------|------|
| `staffRole` | 人员类型由 `leaders/drivers/guides/photographers/others` 路径唯一确定 |
| `id` | 保存为全量替换,不按数据行 ID 执行新增或修改 |
| `staffName` | 查询回显字段 |
| `totalPlannedCost` | 查询回显字段 |
| `totalActualCost` | 查询回显字段 |
| `settlementConfirmStatus` | 核单确认状态不由 Tab 保存请求指定 |
| `isPrimaryReporter` | 查询回显字段 |
出现未知字段时请求失败,不会静默忽略。
## 5. 出参(响应)
### 5.1 统一响应外层
| 字段 | 类型 | 说明 |
|------|------|------|
| `code` | Integer | 业务码;成功为 200 |
| `message` | String | 结果说明 |
| `data` | Object/null | GET 为当前 Tab 数据;PUT 成功固定为 `null` |
| `traceId` | String/null | 链路追踪 ID |
| `success` | Boolean | `code=200` 时为 `true`,否则为 `false` |
### 5.2 五个 GET 的 `data`
| 字段 | 类型 | 说明 |
|------|------|------|
| `totalActualCost` | Decimal | 当前 Tab 实际费用合计 |
| `items` | Array | 当前 Tab 已保存行;没有已保存行时返回该角色候选草稿 |
### 5.3 GET `data.items[]`
| 字段 | 类型 | 可空 | 说明 |
|------|------|------|------|
| `id` | String | 是 | 已保存行 ID;候选草稿为 `null` |
| `staffId` | String | 是 | 人员分配 ID;聚合行可为 `null` |
| `staffName` | String | 是 | 人员姓名或聚合姓名摘要 |
| `detail` | Object | 否 | 当前 Tab 对应的角色明细,结构见 §3 |
| `totalPlannedCost` | Decimal | 否 | 计划成本 |
| `totalActualCost` | Decimal | 否 | 实际成本,已包含 `reimburse` |
| `reimburse` | Decimal | 否 | 小额报销 |
| `paymentMethod` | String | 否 | 付款方式 |
| `voucherUrls` | String[] | 否 | 凭证 URL;无凭证为 `[]` |
| `settlementConfirmStatus` | String | 否 | 人员费用核单确认状态 |
| `settleStatus` | String | 是 | 辅助人员结算状态;主报账人行返回 `null` |
| `settledDate` | String(date) | 是 | 辅助人员结算日期 |
| `transferRef` | String | 是 | 辅助人员结算转账流水号 |
| `isPrimaryReporter` | Boolean | 否 | 是否主报账人 |
| `remark` | String | 是 | 备注 |
ID 字段按字符串返回。
### 5.4 PUT 成功响应
五个 PUT 均为统一成功响应,不返回操作数据 ID
```json
{
"code": 200,
"message": "成功",
"data": null,
"traceId": null,
"success": true
}
```
## 6. 枚举 / 数据字典
### 6.1 `paymentMethod`
**所属字段**PUT `items[].paymentMethod`、GET `data.items[].paymentMethod` **类型**String **必填**:否
| 值 | 中文 | 说明 |
|----|------|------|
| `CASH_PAID` | 现金已付 | 现金支付 |
| `COMPANY_PAID` | 公司支付 | 请求不传时的默认值 |
| `SIGNED` | 签单 | 按签单方式结算 |
### 6.2 `settleStatus`
**所属字段**PUT `items[].settleStatus`、GET `data.items[].settleStatus` **类型**String **必填**:否
| 值 | 中文 | 说明 |
|----|------|------|
| `PENDING` | 待结算 | 辅助人员默认值 |
| `COMPLETED` | 已结算 | 辅助人员使用时必须同时填写 `transferRef` |
主报账人行的 `settleStatus``null`
### 6.3 `settlementConfirmStatus`
**所属字段**GET `data.items[].settlementConfirmStatus` **类型**String **入参**:禁止提交
| 值 | 中文 | 说明 |
|----|------|------|
| `UNCONFIRMED` | 未确认 | Tab 保存后为未确认 |
| `CONFIRMED` | 已确认 | 人员费用已完成核单确认 |
### 6.4 人员类型与路径映射
人员类型不是请求字段,仅用于说明路径含义。
| 路径尾段 | 人员类型 | 中文 |
|----------|----------|------|
| `leaders` | `LEADER` | 领队 |
| `drivers` | `DRIVER` | 司机 |
| `guides` | `GUIDE` | 导游 |
| `photographers` | `PHOTOGRAPHER` | 摄影师 |
| `others` | `OTHER` | 其他人员 |
## 7. 错误码
| code | 含义 | 触发场景 |
|------|------|----------|
| `400` | 请求参数错误 | 提交 `staffRole``id``settlementConfirmStatus` 等未知/禁止字段,或字段格式、长度、枚举校验失败 |
| `404` | 接口不存在 | 继续调用已删除的 Step3 或 Order 管理端车辆费用接口 |
| `584020` | 订单不存在 | `orderId` 对应订单不存在 |
| `584021` | 当前核单状态不允许录人员费用 | PUT 时订单不是待核单或核单中 |
| `584023` | 司机明细非法 | `days[]` 缺失、服务日期/日费非法,或额外费用明细合计不等于 `extra_cost` |
| `584024` | 导游/摄影师明细非法 | `persons[]` 缺失,或姓名、天数、每天费用非法 |
| `584025` | 领队明细非法 | 缺少 `days``per_day`,或值小于 0 |
| `584026` | 人员实际费用非法 | 报销或折算后的实际费用小于 0 |
| `584027` | 人员引用无效 | `staffId` 不属于当前订单、角色与路径不一致,或领队/司机未传 `staffId` |
| `584028` | 其他人员明细非法 | `detail.items[]` 缺失,或名称、金额非法 |
| `584038` | 已结算但缺转账流水号 | 辅助人员 `settleStatus=COMPLETED``transferRef` 为空 |
| `584039` | 结算状态非法 | `settleStatus` 不是 `PENDING``COMPLETED` |
| `584080` | 团期共享科目不可在子订单录入 | 团期子订单保存非空领队或摄影师费用 |
## 8. 示例
以下示例中的订单 ID、人员 ID、行 ID 均为格式示例。
### 8.1 领队 Tab典型 GET
**请求**
```http
GET /v3/admin/order/2080000000000000001/settlement/staff-fees/leaders
Authorization: Bearer <token>
```
无请求体。
**响应**
```json
{
"code": 200,
"message": "成功",
"data": {
"totalActualCost": 2450.00,
"items": [
{
"id": "2081000000000000001",
"staffId": "2082000000000000001",
"staffName": "领队甲",
"detail": {
"days": 3,
"per_day": 800.00
},
"totalPlannedCost": 2400.00,
"totalActualCost": 2450.00,
"reimburse": 50.00,
"paymentMethod": "COMPANY_PAID",
"voucherUrls": [],
"settlementConfirmStatus": "UNCONFIRMED",
"settleStatus": null,
"settledDate": null,
"transferRef": null,
"isPrimaryReporter": true,
"remark": "主报账人"
}
]
},
"traceId": null,
"success": true
}
```
### 8.2 领队 Tab典型 PUT
**请求**
```http
PUT /v3/admin/order/2080000000000000001/settlement/staff-fees/leaders
Authorization: Bearer <token>
Content-Type: application/json
```
```json
{
"items": [
{
"staffId": "2082000000000000001",
"detail": {
"days": 3,
"per_day": 800.00
},
"reimburse": 50.00,
"paymentMethod": "COMPANY_PAID",
"voucherUrls": [],
"remark": "主报账人"
}
]
}
```
**响应**
```json
{
"code": 200,
"message": "成功",
"data": null,
"traceId": null,
"success": true
}
```
### 8.3 司机 Tab典型 GET
**请求**
```http
GET /v3/admin/order/2080000000000000001/settlement/staff-fees/drivers
Authorization: Bearer <token>
```
无请求体。
**响应**
```json
{
"code": 200,
"message": "成功",
"data": {
"totalActualCost": 120.00,
"items": [
{
"id": "2081000000000000002",
"staffId": "2082000000000000002",
"staffName": "司机甲",
"detail": {
"days": [
{
"service_date": "2026-07-29",
"vehicle_brief": "示例车辆",
"daily_fee": 700.00,
"is_used": true,
"note": ""
}
],
"extra_cost": 100.00,
"extra_breakdown": [
{
"name": "临时停车",
"amount": 100.00,
"note": ""
}
]
},
"totalPlannedCost": 0,
"totalActualCost": 120.00,
"reimburse": 20.00,
"paymentMethod": "COMPANY_PAID",
"voucherUrls": [],
"settlementConfirmStatus": "UNCONFIRMED",
"settleStatus": "PENDING",
"settledDate": null,
"transferRef": null,
"isPrimaryReporter": false,
"remark": ""
}
]
},
"traceId": null,
"success": true
}
```
### 8.4 司机 Tab典型 PUT
**请求**
```http
PUT /v3/admin/order/2080000000000000001/settlement/staff-fees/drivers
Authorization: Bearer <token>
Content-Type: application/json
```
```json
{
"items": [
{
"staffId": "2082000000000000002",
"detail": {
"days": [
{
"service_date": "2026-07-29",
"vehicle_brief": "示例车辆",
"daily_fee": 700.00,
"is_used": true,
"note": ""
}
],
"extra_cost": 100.00,
"extra_breakdown": [
{
"name": "临时停车",
"amount": 100.00,
"note": ""
}
]
},
"reimburse": 20.00,
"paymentMethod": "COMPANY_PAID",
"voucherUrls": [],
"settleStatus": "PENDING",
"settledDate": null,
"transferRef": null,
"remark": ""
}
]
}
```
**响应**
```json
{
"code": 200,
"message": "成功",
"data": null,
"traceId": null,
"success": true
}
```
### 8.5 导游 Tab典型 GET
**请求**
```http
GET /v3/admin/order/2080000000000000001/settlement/staff-fees/guides
Authorization: Bearer <token>
```
无请求体。
**响应**
```json
{
"code": 200,
"message": "成功",
"data": {
"totalActualCost": 1800.00,
"items": [
{
"id": "2081000000000000003",
"staffId": null,
"staffName": "导游甲、导游乙",
"detail": {
"persons": [
{
"name": "导游甲",
"days": 2,
"per_day": 500.00,
"note": ""
},
{
"name": "导游乙",
"days": 2,
"per_day": 400.00,
"note": ""
}
]
},
"totalPlannedCost": 1800.00,
"totalActualCost": 1800.00,
"reimburse": 0,
"paymentMethod": "SIGNED",
"voucherUrls": [],
"settlementConfirmStatus": "UNCONFIRMED",
"settleStatus": "COMPLETED",
"settledDate": "2026-07-29",
"transferRef": "TRANSFER-20260729-001",
"isPrimaryReporter": false,
"remark": ""
}
]
},
"traceId": null,
"success": true
}
```
### 8.6 导游 Tab典型 PUT
**请求**
```http
PUT /v3/admin/order/2080000000000000001/settlement/staff-fees/guides
Authorization: Bearer <token>
Content-Type: application/json
```
```json
{
"items": [
{
"staffId": null,
"detail": {
"persons": [
{
"name": "导游甲",
"days": 2,
"per_day": 500.00,
"note": ""
},
{
"name": "导游乙",
"days": 2,
"per_day": 400.00,
"note": ""
}
]
},
"reimburse": 0,
"paymentMethod": "SIGNED",
"voucherUrls": [],
"settleStatus": "COMPLETED",
"settledDate": "2026-07-29",
"transferRef": "TRANSFER-20260729-001",
"remark": ""
}
]
}
```
**响应**
```json
{
"code": 200,
"message": "成功",
"data": null,
"traceId": null,
"success": true
}
```
### 8.7 摄影师 Tab典型 GET
**请求**
```http
GET /v3/admin/order/2080000000000000001/settlement/staff-fees/photographers
Authorization: Bearer <token>
```
无请求体。
**响应**
```json
{
"code": 200,
"message": "成功",
"data": {
"totalActualCost": 1500.00,
"items": [
{
"id": "2081000000000000004",
"staffId": "2082000000000000004",
"staffName": "摄影师甲",
"detail": {
"persons": [
{
"name": "摄影师甲",
"days": 3,
"per_day": 500.00,
"note": ""
}
]
},
"totalPlannedCost": 1500.00,
"totalActualCost": 1500.00,
"reimburse": 0,
"paymentMethod": "COMPANY_PAID",
"voucherUrls": [],
"settlementConfirmStatus": "UNCONFIRMED",
"settleStatus": "PENDING",
"settledDate": null,
"transferRef": null,
"isPrimaryReporter": false,
"remark": ""
}
]
},
"traceId": null,
"success": true
}
```
### 8.8 摄影师 Tab典型 PUT
**请求**
```http
PUT /v3/admin/order/2080000000000000001/settlement/staff-fees/photographers
Authorization: Bearer <token>
Content-Type: application/json
```
```json
{
"items": [
{
"staffId": "2082000000000000004",
"detail": {
"persons": [
{
"name": "摄影师甲",
"days": 3,
"per_day": 500.00,
"note": ""
}
]
},
"reimburse": 0,
"paymentMethod": "COMPANY_PAID",
"voucherUrls": [],
"settleStatus": "PENDING",
"settledDate": null,
"transferRef": null,
"remark": ""
}
]
}
```
**响应**
```json
{
"code": 200,
"message": "成功",
"data": null,
"traceId": null,
"success": true
}
```
### 8.9 其他人员 Tab典型 GET
**请求**
```http
GET /v3/admin/order/2080000000000000001/settlement/staff-fees/others
Authorization: Bearer <token>
```
无请求体。
**响应**
```json
{
"code": 200,
"message": "成功",
"data": {
"totalActualCost": 350.00,
"items": [
{
"id": "2081000000000000005",
"staffId": null,
"staffName": "临时协助",
"detail": {
"items": [
{
"name": "临时协助",
"amount": 300.00,
"note": ""
}
]
},
"totalPlannedCost": 300.00,
"totalActualCost": 350.00,
"reimburse": 50.00,
"paymentMethod": "CASH_PAID",
"voucherUrls": [
"https://example.com/vouchers/other-001.jpg"
],
"settlementConfirmStatus": "UNCONFIRMED",
"settleStatus": "COMPLETED",
"settledDate": "2026-07-29",
"transferRef": "TRANSFER-20260729-002",
"isPrimaryReporter": false,
"remark": ""
}
]
},
"traceId": null,
"success": true
}
```
### 8.10 其他人员 Tab典型 PUT
**请求**
```http
PUT /v3/admin/order/2080000000000000001/settlement/staff-fees/others
Authorization: Bearer <token>
Content-Type: application/json
```
```json
{
"items": [
{
"staffId": null,
"detail": {
"items": [
{
"name": "临时协助",
"amount": 300.00,
"note": ""
}
]
},
"reimburse": 50.00,
"paymentMethod": "CASH_PAID",
"voucherUrls": [
"https://example.com/vouchers/other-001.jpg"
],
"settleStatus": "COMPLETED",
"settledDate": "2026-07-29",
"transferRef": "TRANSFER-20260729-002",
"remark": ""
}
]
}
```
**响应**
```json
{
"code": 200,
"message": "成功",
"data": null,
"traceId": null,
"success": true
}
```
### 8.11 边界:清空单个 Tab
以下请求只清空导游 Tab,不影响领队、司机、摄影师和其他人员。
**请求**
```http
PUT /v3/admin/order/2080000000000000001/settlement/staff-fees/guides
Authorization: Bearer <token>
Content-Type: application/json
```
```json
{
"items": []
}
```
**响应**
```json
{
"code": 200,
"message": "成功",
"data": null,
"traceId": null,
"success": true
}
```
### 8.12 异常:提交人员类型或服务端字段
**请求**
```http
PUT /v3/admin/order/2080000000000000001/settlement/staff-fees/drivers
Authorization: Bearer <token>
Content-Type: application/json
```
```json
{
"staffRole": "GUIDE",
"items": []
}
```
**响应**
```json
{
"code": 400,
"message": "请求数据格式错误:人员费用 Tab 请求不支持字段: staffRole",
"data": null,
"traceId": null,
"success": false
}
```
`id``settlementConfirmStatus` 等禁止字段同样会被拒绝。
### 8.13 异常:辅助人员已结算但未填流水号
**请求**
```http
PUT /v3/admin/order/2080000000000000001/settlement/staff-fees/guides
Authorization: Bearer <token>
Content-Type: application/json
```
```json
{
"items": [
{
"staffId": null,
"detail": {
"persons": [
{
"name": "导游甲",
"days": 1,
"per_day": 500.00
}
]
},
"settleStatus": "COMPLETED",
"transferRef": null
}
]
}
```
**响应**
```json
{
"code": 584038,
"message": "结算状态为 COMPLETED 时转账流水号不能为空",
"data": null,
"traceId": null,
"success": false
}
```
### 8.14 异常:调用已删除接口
**请求**
```http
GET /v3/admin/order/2080000000000000001/settlement/step3
Authorization: Bearer <token>
```
无请求体。
**响应**
```json
{
"code": 404,
"message": "接口不存在",
"data": null,
"traceId": null,
"success": false
}
```
`PUT /settlement/step3``GET /settlement/vehicle-fees``POST /settlement/vehicle-fees/confirm` 同样不可用。
## 验证证据
- 五个 Tab 的 GET 均已通过管理后台网关返回 HTTP 200、业务码 200。
- `staffRole``id``settlementConfirmStatus` 禁止字段探针均返回业务码 400。
- 旧 Step3 GET/PUT、旧车辆费用 GET/confirm 路由均已返回业务码 404。
- Merge commit 已核对五组 GET/PUT 路由、严格请求字段和 `Result<Void>` 保存响应契约。
## 9. 业务边界
- 每个 GET 只返回路径对应的人员类型,调用方不需要也不应再按 `staffRole` 过滤。
- 每个 PUT 是当前 Tab 的全量替换;遗漏的当前 Tab 行会被删除,另外四个 Tab 不受影响。
- `items: []` 是合法请求,表示清空当前 Tab;`items: null` 或缺少 `items` 会失败。
- 领队、司机必须引用当前订单对应角色的 `staffId`
- 导游、摄影师、其他人员允许 `staffId=null` 的聚合行;如果传了 `staffId`,仍必须与订单和路径角色匹配。
- `settlementConfirmStatus` 是查询状态,PUT 不接收;Tab 保存后该 Tab 行为未确认状态。
- `settleStatus``settledDate``transferRef` 仅用于辅助人员的结算记录;主报账人行这三个字段不参与保存并在查询时为空。
- 辅助人员 `settleStatus=COMPLETED` 时必须填写 `transferRef`
- 司机 `daily_fee` 仅回显,不计入人员费用;司机实际人员费用只计算 `extra_cost + reimburse`
- 团期子订单不能录入非空的领队、摄影师共享费用。
- 旧 Step3 与两个 Order 管理端车辆费用接口没有兼容期,继续调用会失败。
## 10. 修改前后对比
### 10.1 路径与调用方式
| 项目 | 修改前 | 修改后 |
|------|--------|--------|
| 人员费用查询 | 一个 `GET /settlement/step3` 返回全部人员类型 | 五个 Tab 各自 GET,只返回路径对应类型 |
| 人员费用保存 | 一个 `PUT /settlement/step3` 保存全部人员类型 | 五个 Tab 各自 PUT,只替换当前 Tab |
| 人员类型 | 请求行提交 `staffRole` | 由 URL 路径唯一确定,禁止提交 `staffRole` |
| 保存数据行标识 | 响应可包含新增/更新/删除 ID | PUT 成功固定 `data=null` |
| 保存入参 ID | 可按旧聚合结构提交 `id` | 全量替换,不提交 `id` |
| 核单确认状态 | 可在旧聚合行中携带相关状态 | `settlementConfirmStatus` 只查询回显,PUT 禁止提交 |
| Order 管理端车辆费用 | 前端可调用查询/确认接口 | 两个接口删除,前端不再调用 |
### 10.2 旧路径到新路径
| 旧调用 | 新调用 |
|--------|--------|
| `GET /settlement/step3` 后按 `staffRole=LEADER` 过滤 | `GET /settlement/staff-fees/leaders` |
| `GET /settlement/step3` 后按 `staffRole=DRIVER` 过滤 | `GET /settlement/staff-fees/drivers` |
| `GET /settlement/step3` 后按 `staffRole=GUIDE` 过滤 | `GET /settlement/staff-fees/guides` |
| `GET /settlement/step3` 后按 `staffRole=PHOTOGRAPHER` 过滤 | `GET /settlement/staff-fees/photographers` |
| `GET /settlement/step3` 后按 `staffRole=OTHER` 过滤 | `GET /settlement/staff-fees/others` |
| `PUT /settlement/step3` 提交全部人员 | 按 Tab 调用对应 PUT |
| `GET /settlement/vehicle-fees` | 删除,无前端替代调用 |
| `POST /settlement/vehicle-fees/confirm` | 删除,无前端替代调用 |
## 11. 影响评估 / 回滚
### 11.1 影响评估
- **是否破坏向后兼容**:是。四个旧路由直接删除,旧 Step3 请求结构不再接受。
- **前端是否必须同步调整**:是。五个 Tab 必须切换到各自 GET/PUT,并删除 `staffRole``id``settlementConfirmStatus` 等保存字段。
- **保存响应处理**PUT 只判断统一成功/失败结果,不再读取操作数据 ID。
### 11.2 回滚边界
- 当前接口不提供旧 Step3 和 Order 管理端车辆费用兼容路由。
- 前端若回滚到仍调用旧路由的版本,将无法完成查询或保存;回滚版本必须仍使用本文五组接口。
## 12. 注意事项
- 不要在五个 PUT 的根对象或行对象中发送 `staffRole`
- 不要把 GET 返回的完整行对象原样回传;至少移除 `id``staffName``totalPlannedCost``totalActualCost``settlementConfirmStatus``isPrimaryReporter`
- 五个 Tab 应分别维护请求状态和保存动作;保存某个 Tab 时不要拼入其他类型的行。
- PUT 成功后的 `data``null`,不再解析新增、修改、删除 ID。
- 删除前端对 `/settlement/step3``/settlement/vehicle-fees``/settlement/vehicle-fees/confirm` 的调用。
- 金额字段按 Decimal 处理;ID 字段按 String 处理。
## 13. 关联 / 联系人
### 13.1 链接
- **Issue**[#5325](https://git.1814.love:8443/wx/HL/issues/5325)
- **PR**[#5332](https://git.1814.love:8443/wx/HL/pulls/5332)
- **Merge commit**[10996166df493ee4237fdfdbaece611cb6c0cb52](https://git.1814.love:8443/wx/HL/commit/10996166df493ee4237fdfdbaece611cb6c0cb52)
### 13.2 联系人
- **后端负责人**@yst