- 删除族B嵌套接口4个路由(staff-fees/guides、staff-fees/photographers 的 GET/PUT),调用返回404 - 删除族B专属错误码 584023/584024/584025/584028 - 前端切换目标:族A扁平接口 guide-fees / photographer-fees(已在线) - 关联 PR #5658,merge commit 7d29484da7
17 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 | pending | 2026-08-07 | 后端已删除族B guides/photographers 嵌套 GET/PUT 共4个路由并部署测试服;已行为级验证族B 4端点返回404、族A guide-fees/photographer-fees 正常返回。等待前端将导游/摄影页签从族B路径切换到族A扁平接口,frontend_status=pending 表示等待前端真实领取。 | 2026-08-07 | 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/guidesPUT /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/photographersPUT /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-feesPUT /v3/admin/order/:orderId/settlement/guide-feesPOST /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-feesPUT /v3/admin/order/:orderId/settlement/photographer-feesPOST /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 链接
- Issue: #5655
- PR: #5658
- Merge 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 正常返回业务数据。