---
author: "yst(GIT)"
schema: "hl-changelog/v2"
ticket: "5655"
title: "核单导游/摄影族B嵌套接口下线，统一走族A扁平接口"
consumer: "admin"
change_type: "删除接口"
backend_status: "deployed"
gateway_status: "not_required"
frontend_status: "implemented"
frontend_owner: "mmg"
frontend_ref: "ee7a5d58"
target_release: ""
verified_at: "2026-08-07"
status_note: "后端已删除族B guides/photographers 嵌套 GET/PUT 共4个路由并部署测试服；已行为级验证族B 4端点返回404、族A guide-fees/photographer-fees 正常返回。等待前端将导游/摄影页签从族B路径切换到族A扁平接口，frontend_status=pending 表示等待前端真实领取。"
updated_at: "2026-08-08"
base: "dev-v3"
---


# ⚠️【删除接口·管理后台】核单导游/摄影族B嵌套接口下线，统一走族A扁平接口 (#5655)

> **PR**: #5658 | **服务**: order-v3 | **更新时间**: 2026-08-07

## 1. 接口背景

核单页面的导游、摄影师费用历史上存在两套接口：

- **族 A（保留）**：`/settlement/guide-fees`、`/settlement/photographer-fees`，按天扁平行结构，与住宿、餐食等页签形态一致。
- **族 B（本次删除）**：`/settlement/staff-fees/guides`、`/settlement/staff-fees/photographers`，按人嵌套 `persons[]` 结构。

一笔导游/摄影费用只对应一个人，族 B 的 `persons[]` 嵌套属于过度设计，且与其他核单页签的平铺形态不一致。本次将族 B 共 4 个路由整体删除，导游/摄影核单统一由族 A 扁平接口承载。

**旧路径已删，调用返回 HTTP 404「接口不存在」。** 前端必须把导游、摄影师页签的查询/保存调用从族 B 路径切换到族 A 路径。

## 2. 变更清单

| # | 接口名 | 方法 | 路径 | 变更类型 | 说明 |
|---|--------|------|------|----------|------|
| 1 | 查询导游人员费用（族B） | GET | `/v3/admin/order/:orderId/settlement/staff-fees/guides` | 删除 | 路由删除，调用返回 HTTP 404 |
| 2 | 全量替换导游人员费用（族B） | PUT | `/v3/admin/order/:orderId/settlement/staff-fees/guides` | 删除 | 路由删除，调用返回 HTTP 404 |
| 3 | 查询摄影师人员费用（族B） | GET | `/v3/admin/order/:orderId/settlement/staff-fees/photographers` | 删除 | 路由删除，调用返回 HTTP 404 |
| 4 | 全量替换摄影师人员费用（族B） | PUT | `/v3/admin/order/:orderId/settlement/staff-fees/photographers` | 删除 | 路由删除，调用返回 HTTP 404 |

替代接口（族 A，**本次未改动，已在线**，前端切换目标）：

| Tab | 查询 | 全量保存 | 确认 |
|-----|------|----------|------|
| 导游 | `GET /v3/admin/order/:orderId/settlement/guide-fees` | `PUT /v3/admin/order/:orderId/settlement/guide-fees` | `POST /v3/admin/order/:orderId/settlement/guide-fees/confirm` |
| 摄影师 | `GET /v3/admin/order/:orderId/settlement/photographer-fees` | `PUT /v3/admin/order/:orderId/settlement/photographer-fees` | `POST /v3/admin/order/:orderId/settlement/photographer-fees/confirm` |

## 3. 接口详情

### 3.1 已删除：族B 导游人员费用查询与保存

- **原方法与路径**：
  - `GET /v3/admin/order/:orderId/settlement/staff-fees/guides`
  - `PUT /v3/admin/order/:orderId/settlement/staff-fees/guides`
- **使用场景**：已删除。导游核单查询/保存改用 `/settlement/guide-fees`（见 §3.3）。
- **认证**：原接口要求管理后台登录态；接口删除后，即使登录态有效也返回 HTTP 404。
- **幂等性**：不适用。
- **限流**：无。

### 3.2 已删除：族B 摄影师人员费用查询与保存

- **原方法与路径**：
  - `GET /v3/admin/order/:orderId/settlement/staff-fees/photographers`
  - `PUT /v3/admin/order/:orderId/settlement/staff-fees/photographers`
- **使用场景**：已删除。摄影师核单查询/保存改用 `/settlement/photographer-fees`（见 §3.4）。
- **认证**：原接口要求管理后台登录态；接口删除后，即使登录态有效也返回 HTTP 404。
- **幂等性**：不适用。
- **限流**：无。

### 3.3 替代：导游费用（族A）

- **接口名**：查询导游费用 / 全量保存导游费用 / 确认导游费用
- **方法与路径**：
  - `GET /v3/admin/order/:orderId/settlement/guide-fees`
  - `PUT /v3/admin/order/:orderId/settlement/guide-fees`
  - `POST /v3/admin/order/:orderId/settlement/guide-fees/confirm`
- **使用场景**：核单页面导游页签的查询、全量保存、确认。
- **认证**：管理后台登录态 + 订单访问权限。
- **幂等性**：GET 只读；PUT 为全量替换语义，需携带 `expectedSourceFingerprint` 乐观锁指纹（取值为最近一次 GET 返回的 `sourceFingerprint`），指纹不匹配拒绝写入；POST confirm 重复确认不产生副作用。
- **限流**：无接口级特殊限流。

### 3.4 替代：摄影师费用（族A）

- **接口名**：查询摄影师费用 / 全量保存摄影师费用 / 确认摄影师费用
- **方法与路径**：
  - `GET /v3/admin/order/:orderId/settlement/photographer-fees`
  - `PUT /v3/admin/order/:orderId/settlement/photographer-fees`
  - `POST /v3/admin/order/:orderId/settlement/photographer-fees/confirm`
- **使用场景**：核单页面摄影师页签的查询、全量保存、确认。
- **认证 / 幂等性 / 限流**：与 §3.3 导游一致。

## 4. 接口入参

### 4.1 路径参数（族A GET / PUT / POST 通用）

| 字段 | 类型 | 必填 | 说明 | 校验 |
|------|------|------|------|------|
| `orderId` | String(Long) | 是 | 订单 ID | 正整数 |

GET 无 Query 参数、无请求体。POST confirm 无请求体。

### 4.2 PUT 请求体（全量保存）

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `expectedSourceFingerprint` | String | 是 | 乐观锁指纹，取最近一次 GET 返回的 `sourceFingerprint`；不匹配则拒绝写入 |
| `items` | Array | 是 | 全量费用行（扁平按天，无嵌套）；传 `[]` 表示清空 |
| `excludedCandidateKeys` | String[] | 否 | 被排除的候选 `candidateKey` 列表；无排除传 `[]` |

`items[]` 行字段与 GET 出参行字段一致（见 §5.2），其中 `id` 已有行需回传、新增行不传。

## 5. 出参字段

### 5.1 顶层字段（GET `data`）

| 字段 | 类型 | 可空 | 说明 |
|------|------|------|------|
| `category` | String | 否 | 类别；导游固定 `GUIDE`，摄影师固定 `PHOTOGRAPHER` |
| `sourceFingerprint` | String | 否 | 乐观锁指纹；PUT 必须通过 `expectedSourceFingerprint` 回传 |
| `totalAmount` | String(Decimal) | 否 | 费用合计金额，字符串格式如 `"590.00"` |
| `cashPaidAmount` | String(Decimal) | 否 | 现付金额合计 |
| `unconfirmedCount` | Integer | 否 | 未确认行数 |
| `pendingCandidateCount` | Integer | 否 | 待处理候选数 |
| `settlementReady` | Boolean | 否 | 是否已具备核单条件 |
| `blockReasonCode` | String | 是 | 不具备核单条件时的机器可读原因；可核单时为 `null`，如 `ITEMS_UNCONFIRMED` |
| `editable` | Boolean | 否 | 当前是否可编辑 |
| `readOnlyReasonCode` | String | 是 | 只读原因；可编辑时为 `null` |
| `items` | Array | 否 | 费用行，扁平按天，无嵌套；无明细为 `[]` |

### 5.2 `items[]` 行字段

导游（guide-fees）：

| 字段 | 类型 | 可空 | 说明 |
|------|------|------|------|
| `id` | String(Long) | 是 | 费用行 ID（雪花，字符串）；候选未落库行为 `null` |
| `candidateKey` | String | 是 | 候选键；手工补录行为 `null` |
| `staffAssignmentId` | String(Long) | 是 | 人员派单 ID；无关联为 `null` |
| `serviceDate` | String(date) | 否 | 服务日期（单天），格式 `YYYY-MM-DD` |
| `name` | String | 否 | 导游姓名 |
| `serviceType` | String | 否 | 服务类型编码，见 §6.1 |
| `serviceTypeName` | String | 否 | 服务类型名称，如 `全陪导游` |
| `paymentMethod` | String | 否 | 付款方式编码，见 §6.3 |
| `paymentMethodName` | String | 否 | 付款方式名称 |
| `amount` | String(Decimal) | 否 | 金额，字符串格式如 `"295.00"` |
| `settlementConfirmStatus` | String | 否 | 核单确认状态编码，见 §6.4 |
| `settlementConfirmStatusName` | String | 否 | 核单确认状态名称 |
| `remark` | String | 是 | 备注 |
| `sourceType` | String | 否 | 来源编码，见 §6.5 |
| `sourceTypeName` | String | 否 | 来源名称，如 `手工补录` |
| `sourceActive` | Boolean | 否 | 来源是否有效 |
| `voucherUrls` | String[] | 否 | 凭证 URL；无凭证为 `[]` |
| `completionState` | String | 否 | 行完备状态，如 `COMPLETE` |
| `candidateResolution` | String | 否 | 候选处理结果，如 `INCLUDED` |

摄影师（photographer-fees）与导游**同构**，仅两个字段名不同：

| 语义 | 导游字段名 | 摄影师字段名 |
|------|-----------|--------------|
| 姓名 | `name` | `photographerName` |
| 类型编码/名称 | `serviceType` / `serviceTypeName` | `feeType` / `feeTypeName` |

摄影师类型枚举见 §6.2。

## 6. 枚举 / 数据字典

### 6.1 导游 `serviceType`

**所属字段**：guide-fees `items[].serviceType` ｜ **类型**：String

| 值 | 中文 |
|----|------|
| `FULL_COURSE_GUIDE` | 全陪导游 |
| `LOCAL_GUIDE` | 地接导游 |
| `COMMENTARY_SERVICE` | 讲解服务 |
| `TEMPORARY_SUPPLEMENT` | 临时补录 |

### 6.2 摄影师 `feeType`

**所属字段**：photographer-fees `items[].feeType` ｜ **类型**：String

| 值 | 中文 |
|----|------|
| `FOLLOW_SHOOT` | 跟拍 |
| `PORTRAIT` | 写真 |
| `AERIAL_SHOOT` | 航拍 |
| `EDITING_DELIVERY` | 剪辑出片 |
| `CAMERA_DRONE` | 相机/无人机 |
| `OTHER` | 其他 |

### 6.3 `paymentMethod`

**所属字段**：`items[].paymentMethod` ｜ **类型**：String

| 值 | 中文 |
|----|------|
| `COMPANY_PAID` | 公司付款 |
| `CASH_PAID` | 现付 |

### 6.4 `settlementConfirmStatus`

**所属字段**：`items[].settlementConfirmStatus` ｜ **类型**：String

| 值 | 中文 |
|----|------|
| `UNCONFIRMED` | 未确认 |
| `CONFIRMED` | 已确认 |

### 6.5 `sourceType`

**所属字段**：`items[].sourceType` ｜ **类型**：String

| 值 | 中文 | 说明 |
|----|------|------|
| `MANUAL` | 手工补录 | 核单页手工新增的费用行 |
| 其他来源编码 | — | 由派单/候选自动带入，以实际返回为准 |

## 7. 错误码

### 7.1 已删除的族B专属错误码（不再返回）

| code | 原含义 | 变更 |
|------|--------|------|
| `584023` | DRIVER detail 缺 days[] 数组 / 元素缺 service_date 或 daily_fee 字段 | 删除，不再返回 |
| `584024` | GUIDE / PHOTOGRAPHER detail 缺 persons[] / 元素缺 name / days / per_day | 删除，不再返回 |
| `584025` | LEADER detail 缺 days 或 per_day 字段 | 删除，不再返回 |
| `584028` | OTHER detail 缺 items[] / 元素缺 name / amount | 删除，不再返回 |

前端若存在针对这 4 个错误码的分支处理，可一并清理。

### 7.2 本次相关错误码

| code | 含义 | 触发场景 |
|------|------|----------|
| `404` | 请求地址不存在 | 调用任一已删除的族B路由（staff-fees/guides、staff-fees/photographers） |
| `400` | 请求参数错误 | `orderId` 不是正整数；PUT 请求体字段缺失或非法 |
| `403` | 无访问权限 | 登录态或角色无权访问 |
| `581007` | 订单不存在 | `orderId` 对应订单不存在 |

## 8. 示例

### 8.1 典型成功：GET 导游费用（族A）

请求：

```http
GET /v3/admin/order/2085641684778958848/settlement/guide-fees
Authorization: Bearer JWT_TOKEN
```

无请求体。

响应（测试单真实打样）：

```json
{
  "code": 200,
  "message": "成功",
  "data": {
    "category": "GUIDE",
    "sourceFingerprint": "a02c66c6...",
    "totalAmount": "590.00",
    "cashPaidAmount": "0.00",
    "unconfirmedCount": 2,
    "pendingCandidateCount": 0,
    "settlementReady": false,
    "blockReasonCode": "ITEMS_UNCONFIRMED",
    "editable": true,
    "readOnlyReasonCode": null,
    "items": [
      {
        "id": "2085641684778958849",
        "candidateKey": null,
        "staffAssignmentId": null,
        "serviceDate": "2026-08-10",
        "name": "王强",
        "serviceType": "FULL_COURSE_GUIDE",
        "serviceTypeName": "全陪导游",
        "paymentMethod": "COMPANY_PAID",
        "paymentMethodName": "公司付款",
        "amount": "295.00",
        "settlementConfirmStatus": "UNCONFIRMED",
        "settlementConfirmStatusName": "未确认",
        "remark": "打样导游",
        "sourceType": "MANUAL",
        "sourceTypeName": "手工补录",
        "sourceActive": true,
        "voucherUrls": [],
        "completionState": "COMPLETE",
        "candidateResolution": "INCLUDED"
      }
    ]
  },
  "success": true
}
```

### 8.2 边界：PUT 全量保存空 items（清空导游费用）

请求：

```http
PUT /v3/admin/order/2085641684778958848/settlement/guide-fees
Authorization: Bearer JWT_TOKEN
Content-Type: application/json
```

```json
{
  "expectedSourceFingerprint": "a02c66c6...",
  "items": [],
  "excludedCandidateKeys": []
}
```

响应：

```json
{
  "code": 200,
  "message": "成功",
  "data": null,
  "success": true
}
```

保存后重新 GET 拉取最新 `sourceFingerprint` 再渲染。

### 8.3 业务失败：调用已删除的族B旧路径返回 404

请求：

```http
GET /v3/admin/order/2085641684778958848/settlement/staff-fees/guides
Authorization: Bearer JWT_TOKEN
```

无请求体。

响应：

```json
{
  "code": 404,
  "message": "请求地址不存在",
  "data": null,
  "success": false
}
```

PUT `/settlement/staff-fees/guides`、GET/PUT `/settlement/staff-fees/photographers` 行为一致，均为 HTTP 404。

## 9. 业务边界

**适用**：
- 核单页面导游、摄影师页签的查询、保存、确认全部走族 A 扁平接口。
- 一笔费用一行（按人×天扁平铺开），不存在一人多行嵌套。

**不适用**：
- 族 B 的 `persons[]` 嵌套请求体不再有任何承载路径，不得把嵌套 body 改发到族 A（族 A 只接受扁平 `items[]`）。
- 领队、司机、其他人员费用早在 #5380 已删除，本次不涉及。

**特殊边界**：
- PUT 必须携带最新 `expectedSourceFingerprint`；并发编辑或保存后未刷新指纹再保存会被拒绝，需重新 GET。
- `items=[]` 是合法输入，表示清空该类别费用。

## 10. 修改前后对比

### 10.1 接口级对比

| 能力 | 改前 | 改后 |
|------|------|------|
| 导游费用查询 | `GET /settlement/staff-fees/guides`（族B，persons[] 嵌套） | `GET /settlement/guide-fees`（族A，扁平 items[]） |
| 导游费用保存 | `PUT /settlement/staff-fees/guides`（族B） | `PUT /settlement/guide-fees`（族A，带 expectedSourceFingerprint） |
| 摄影师费用查询 | `GET /settlement/staff-fees/photographers`（族B） | `GET /settlement/photographer-fees`（族A） |
| 摄影师费用保存 | `PUT /settlement/staff-fees/photographers`（族B） | `PUT /settlement/photographer-fees`（族A） |
| 族B 4 个路由 | 可用 | **已删除，调用返回 HTTP 404** |

### 10.2 错误码对比

| 错误码 | 改前 | 改后 |
|--------|------|------|
| `584023` / `584024` / `584025` / `584028` | 族B 请求体校验失败时返回 | 不再返回（族B 路由整体删除） |

## 11. 影响评估 / 回滚

### 11.1 影响评估

- **是否破坏向后兼容**：是。族B 共 4 个路由已删除，未切换的前端版本调用固定 404。
- **前端是否必须同步上线**：是。管理后台必须把导游、摄影师页签的查询/保存切换到族 A 路径，并改为扁平 `items[]` 请求体（携带 `expectedSourceFingerprint`）。
- **后端数据**：导游/摄影费用底层存储不变，仅接口承载形态收口；历史数据在族 A 下正常可见。

### 11.2 回滚边界

- 前端版本不得回滚到仍调用 `staff-fees/guides`、`staff-fees/photographers` 的版本，否则对应页签固定 404。
- 后端如需回滚需恢复 4 个路由与 4 个错误码，涉及 PR #5658 整体 revert，由后端评估。

## 12. 注意事项

- 切换目标路径是 `guide-fees` / `photographer-fees`（短横线、无 staff 前缀），不要拼成 `staff-fees/guide-fees` 等混合路径。
- 族A PUT 是全量替换语义：保存时提交整页 `items[]`；只传改动行会丢失未传行。
- 保存成功后必须重新 GET 获取最新 `sourceFingerprint`，否则下次 PUT 指纹不匹配被拒。
- 摄影师行字段是 `photographerName` / `feeType` / `feeTypeName`，与导游的 `name` / `serviceType` / `serviceTypeName` 不同，不要复用同一套字段映射常量。
- `orderId`、行 `id`、`staffAssignmentId` 均按字符串处理；金额字段（`amount` / `totalAmount` / `cashPaidAmount`）为字符串格式 Decimal。
- 清理前端对 `584023` / `584024` / `584025` / `584028` 的错误码分支。

## 13. 关联 / 联系人

### 13.1 链接

- **Issue**: [#5655](https://git.1814.love:8443/wx/HL/issues/5655)
- **PR**: [#5658](https://git.1814.love:8443/wx/HL/pulls/5658)
- **Merge commit**: [7d29484da77e20a706ec611893545c419f6821b2](https://git.1814.love:8443/wx/HL/commit/7d29484da77e20a706ec611893545c419f6821b2)

### 13.2 联系人

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

## 验证证据

- PR #5658 已合并至 `dev-v3`，合并提交 `7d29484da77e20a706ec611893545c419f6821b2`。
- 测试服已部署并行为级验证：族B 4 端点（GET/PUT staff-fees/guides、GET/PUT staff-fees/photographers）均返回 HTTP 404；族A guide-fees / photographer-fees 正常返回业务数据。

## 前端交付（2026-08-08 mmg，hl-admin@ee7a5d58）

族B→族A 切换已上线 v2.1。导游/摄影师页签查询/保存直连族A `guide-fees`/`photographer-fees`，废弃按人嵌套 StaffFeeTable、并入通用 CategoryTable（与住宿/餐食/车辆页签同形态）；PUT 携带 `expectedSourceFingerprint` 类别级指纹乐观锁（照车辆 version 模式 GET attach / 保存后 re-GET 写回 / 冲突刷新）。导游 `name`/`serviceType` 与摄影 `photographerName`/`feeType` 分别映射未复用；人员下拉保留仅预填姓名（族A 无 staffId 落点）；未接 confirm 端点（确认语义行级随 PUT）；候选最小实现 excludedCandidateKeys 恒 []。

**待后端确认**：人员费用指纹冲突的错误码 changelog 未给出，前端按车辆域既有 `584108` 复用做冲突刷新分支；若人员域实际返回别的码，请告之以对齐（不阻塞，缺省时错误照常透传提示，仅无自动刷新）。
