文件
hl-api-changelog/changelogs-v2/2026-08/07_5655_核单导游摄影族B接口下线-删除接口-管理后台.md
Mimingguang 20255492d0
changelog-filename-gate / validate (push) Failing after 1s
chore(v2): 标记 #5655 admin 前端已实现 (hl-admin@ee7a5d58)
族B→族A 切换已上线:直连 guide-fees/photographer-fees + 类别级指纹乐观锁
+ 并入 CategoryTable + 人员下拉仅预填姓名 + 不接 confirm + 候选最小实现。
如实标注待确认项:人员指纹冲突错误码按车辆域 584108 复用,待后端确认。
2026-08-08 09:42:52 +08:00

18 KiB

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

请求:

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

无请求体。

响应(测试单真实打样):

{
  "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(清空导游费用)

请求:

PUT /v3/admin/order/2085641684778958848/settlement/guide-fees
Authorization: Bearer JWT_TOKEN
Content-Type: application/json
{
  "expectedSourceFingerprint": "a02c66c6...",
  "items": [],
  "excludedCandidateKeys": []
}

响应:

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

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

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

请求:

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

无请求体。

响应:

{
  "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 链接

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 复用做冲突刷新分支;若人员域实际返回别的码,请告之以对齐(不阻塞,缺省时错误照常透传提示,仅无自动刷新)。