文件
hl-api-changelog/changelogs-v2/2026-10/02_8717_团期读端点定制师归属校验-修改接口-管理后台.md
T
API Changelog Bot和Claude Opus 5.5 b54834b3f5
changelog-filename-gate / validate (push) Failing after 1s
docs(changelog): #8717 团期 21 个读端点补定制师归属校验,非本人团期返回 589507
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 17:36:28 +08:00

36 KiB
原始文件 Blame 文件历史

schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
schema ticket title consumer author change_type backend_status gateway_status frontend_status frontend_owner frontend_ref target_release verified_at status_note updated_at base
hl-changelog/v2 8717 团期读端点定制师归属校验:21 个端点新增定制师非本人团期返回 589507 admin wx(GIT) 修改接口 deployed not_required not_required 2026-10-02 dev-v3

团期读端点定制师归属校验:21 个端点新增 589507 拒绝码

存放目录: 二期 → changelogs-v2/2026-10/

服务: hl-order-service-v3 Issue: #8717 日期: 2026-10-02 影响范围: 管理后台团期详情页及相关弹窗的 21 个数据读端点


⚠️ 关键变化

CUSTOMIZER(定制师)角色对非本人团期的 21 个读端点,新增返回业务码 589507 的场景。 该团期属于定制师本人(存在一笔在团且非 CANCELLED 的子订单其顾问 ID 等于本人)时,返回 200 与完整数据。不属于本人时返回 HTTP 200 + code: 589507 + data: null。其他角色(管理员、超管、团期主管等)对这些端点无变化。


一、背景

#7949 授予 CUSTOMIZER 权限码 group-batch:view 用于打开自己团期的订单调整弹窗,但当时仅在 GET /{id} 与 GET /{id}/orders 两个端点补了数据级归属校验。同一团期的其余 21 个读视图端点(逐户名单、配房、行程、签单凭证等)仍缺少该校验,导致任一定制师可读全公司所有团期的客户名、联系人、已付金额等敏感信息。本次补齐这 21 个端点的归属校验,与既有两个端点采用同一口径:团期「属于」定制师当且仅当该团期存在在团(非 CANCELLED)子订单其顾问 ID 等于当前登录用户。


二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 需求汇总 GET /v3/admin/order/group-batch/{groupBatchId}/requirement-summary 修改 新增 589507(定制师非本人团期)
2 逐户订房记录 GET /v3/admin/order/group-batch/{groupBatchId}/requirement/hotel-households 修改 新增 589507(定制师非本人团期)
3 逐户用车记录 GET /v3/admin/order/group-batch/{groupBatchId}/requirement/vehicle-households 修改 新增 589507(定制师非本人团期)
4 配房方案 GET /v3/admin/order/group-batch/{groupBatchId}/room-plans 修改 新增 589507(定制师非本人团期)
5 酒店芯片详情 GET /v3/admin/order/group-batch/{groupBatchId}/chips/hotel 修改 新增 589507(定制师非本人团期)
6 用车芯片详情 GET /v3/admin/order/group-batch/{groupBatchId}/chips/vehicle 修改 新增 589507(定制师非本人团期)
7 导游芯片详情 GET /v3/admin/order/group-batch/{groupBatchId}/chips/guide 修改 新增 589507(定制师非本人团期)
8 摄影芯片详情 GET /v3/admin/order/group-batch/{groupBatchId}/chips/photo 修改 新增 589507(定制师非本人团期)
9 合同芯片详情 GET /v3/admin/order/group-batch/{groupBatchId}/chips/contract 修改 新增 589507(定制师非本人团期)
10 保险芯片详情 GET /v3/admin/order/group-batch/{groupBatchId}/chips/insurance 修改 新增 589507(定制师非本人团期)
11 合同看板 GET /v3/admin/order/group-batch/{groupBatchId}/contracts 修改 新增 589507(定制师非本人团期)
12 团级行程单打印 GET /v3/admin/order/group-batch/{groupBatchId}/print-itinerary 修改 新增 589507(定制师非本人团期)
13 签单凭证 GET /v3/admin/order/group-batch/{groupBatchId}/sign-voucher 修改 新增 589507(定制师非本人团期)
14 行程汇总 GET /v3/admin/order/group-batch/{groupBatchId}/itinerary 修改 新增 589507(定制师非本人团期)
15 行程节点明细 GET /v3/admin/order/group-batch/{groupBatchId}/itinerary/nodes/{nodeKey} 修改 新增 589507(定制师非本人团期)
16 状态流水 GET /v3/admin/order/group-batch/{groupBatchId}/status-logs 修改 新增 589507(定制师非本人团期)
17 物资清单 GET /v3/admin/order/group-batch/{groupBatchId}/supplies 修改 新增 589507(定制师非本人团期)
18 物资候选 GET /v3/admin/order/group-batch/{groupBatchId}/supplies/candidates 修改 新增 589507(定制师非本人团期)
19 撤团候选 GET /v3/admin/order/group-batch/{groupBatchId}/withdraw-candidates 修改 新增 589507(定制师非本人团期)
20 撤团预览 GET /v3/admin/order/group-batch/{groupBatchId}/sub-order/{orderId}/withdraw-preview 修改 新增 589507(定制师非本人团期)
21 转团候选 GET /v3/admin/order/group-batch/{groupBatchId}/transfer-candidates 修改 新增 589507(定制师非本人团期)

三、接口详情

公共说明:所有 21 个接口的行为变化相同。改前 CUSTOMIZER 对任意团期 ID 均返回 200。改后仅本人团期返回 200,其余返回 HTTP 200 + code: 589507 + data: null。非 CUSTOMIZER 角色(ADMIN / SUPER_ADMIN / GROUP_BATCH_MANAGER / FINANCE 等)无变化。

1. 需求汇总 GET /v3/admin/order/group-batch/{groupBatchId}/requirement-summary

VO: GroupRequirementSummaryRespVO

使用场景

团期详情页"需求"Tab 的汇总数据(酒店间数、用车数量等)。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID

出参字段表

字段 类型 说明
出参结构不变 - 详见改前契约;定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/requirement-summary
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": { "hotelCount": 8, "vehicleCount": 3, "totalGuests": 24 },
  "success": true
}

空数据 / 降级响应

  • 团期不存在:返回 589500「团期不存在」(顺序:角色码 → 归属 → 存在性)。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:CUSTOMIZER 对非本人团期(无在团子订单或顾问 ID 不匹配)请求时返回。
  • 定制师本人团期:该团期下存在一笔在团(非 CANCELLED 状态)的子订单其 consultantId 等于当前登录用户。
  • 系统上下文:以 system 用户(无登录态)请求时放行,不返回 589507。

2. 逐户订房记录 GET /v3/admin/order/group-batch/{groupBatchId}/requirement/hotel-households

VO: GroupHotelHouseholdsRespVO

使用场景

团期详情页"需求"Tab 的逐户订房明细(客户名、订房房型、金额等)。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID

出参字段表

字段 类型 说明
出参结构不变 - 含 customerName / consultantName / remark 等;定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/requirement/hotel-households
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": { "households": [ { "customerName": "张三", "roomType": "大床房", "nights": 3 } ] },
  "success": true
}

空数据 / 降级响应

  • 团期无订房需求:返回空数组。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:同上(#1)。
  • 列表可能为空:即使 CUSTOMIZER 本人团期,若无订房需求也返回空数组而非 589507。

3. 逐户用车记录 GET /v3/admin/order/group-batch/{groupBatchId}/requirement/vehicle-households

VO: GroupVehicleHouseholdsRespVO

使用场景

团期详情页"需求"Tab 的逐户用车明细(客户名、车型、备注等)。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID

出参字段表

字段 类型 说明
出参结构不变 - 含 customerName / specialTags / remark 等;定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/requirement/vehicle-households
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": { "households": [ { "customerName": "李四", "vehicleType": "中巴", "remark": "轮椅可达" } ] },
  "success": true
}

空数据 / 降级响应

  • 团期无用车需求:返回空数组。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:同上(#1)。

4. 配房方案 GET /v3/admin/order/group-batch/{groupBatchId}/room-plans

VO: GroupBatchRoomPlanDetailRespVO

使用场景

团期详情页"配房"Tab 的配房方案(酒店、房型、间数、价格等)。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID

出参字段表

字段 类型 说明
出参结构不变 - 含 hotelName / roomTypeName / travelerCount 等;定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/room-plans
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": { "hotelName": "如家酒店", "roomType": "标准间", "travelerCount": 8 },
  "success": true
}

空数据 / 降级响应

  • 团期无配房数据:返回空数据或空数组。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:同上(#1)。

5. 酒店芯片详情 GET /v3/admin/order/group-batch/{groupBatchId}/chips/hotel

VO: GroupBatchChipDetailVO

使用场景

团期详情页"芯片"弹窗中酒店芯片的详细信息(人数、供应商列表、备注等)。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID

出参字段表

字段 类型 说明
出参结构不变 - 芯片聚合数据;定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/chips/hotel
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": { "count": 3, "staffList": [], "items": [] },
  "success": true
}

空数据 / 降级响应

  • 团期无酒店芯片:返回空数据。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:同上(#1)。

6. 用车芯片详情 GET /v3/admin/order/group-batch/{groupBatchId}/chips/vehicle

VO: GroupBatchChipDetailVO

使用场景

团期详情页"芯片"弹窗中用车芯片的详细信息。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID

出参字段表

字段 类型 说明
出参结构不变 - 芯片聚合数据;定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/chips/vehicle
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": { "count": 1, "staffList": [], "items": [] },
  "success": true
}

空数据 / 降级响应

  • 团期无用车芯片:返回空数据。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:同上(#1)。

7. 导游芯片详情 GET /v3/admin/order/group-batch/{groupBatchId}/chips/guide

VO: GroupBatchChipDetailVO

使用场景

团期详情页"芯片"弹窗中导游芯片的详细信息。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID

出参字段表

字段 类型 说明
出参结构不变 - 芯片聚合数据;定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/chips/guide
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": { "count": 2, "staffList": [], "items": [] },
  "success": true
}

空数据 / 降级响应

  • 团期无导游芯片:返回空数据。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:同上(#1)。

8. 摄影芯片详情 GET /v3/admin/order/group-batch/{groupBatchId}/chips/photo

VO: GroupBatchChipDetailVO

使用场景

团期详情页"芯片"弹窗中摄影芯片的详细信息。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID

出参字段表

字段 类型 说明
出参结构不变 - 芯片聚合数据;定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/chips/photo
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": { "count": 1, "staffList": [], "items": [] },
  "success": true
}

空数据 / 降级响应

  • 团期无摄影芯片:返回空数据。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:同上(#1)。

9. 合同芯片详情 GET /v3/admin/order/group-batch/{groupBatchId}/chips/contract

VO: GroupBatchChipDetailVO

使用场景

团期详情页"芯片"弹窗中合同芯片的详细信息。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID

出参字段表

字段 类型 说明
出参结构不变 - 芯片聚合数据;定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/chips/contract
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": { "count": 1, "staffList": [], "items": [] },
  "success": true
}

空数据 / 降级响应

  • 团期无合同芯片:返回空数据。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:同上(#1)。

10. 保险芯片详情 GET /v3/admin/order/group-batch/{groupBatchId}/chips/insurance

VO: GroupBatchChipDetailVO

使用场景

团期详情页"芯片"弹窗中保险芯片的详细信息。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID

出参字段表

字段 类型 说明
出参结构不变 - 芯片聚合数据;定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/chips/insurance
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": { "count": 1, "staffList": [], "items": [] },
  "success": true
}

空数据 / 降级响应

  • 团期无保险芯片:返回空数据。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:同上(#1)。

11. 合同看板 GET /v3/admin/order/group-batch/{groupBatchId}/contracts

VO: GroupBatchContractBoardVO

使用场景

团期详情页"合同"Tab 的合同签署看板(签署状态、进度等)。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID

出参字段表

字段 类型 说明
出参结构不变 - 合同看板数据;定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/contracts
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": { "items": [] },
  "success": true
}

空数据 / 降级响应

  • 团期无合同数据:返回空数据。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:同上(#1)。

12. 团级行程单打印 GET /v3/admin/order/group-batch/{groupBatchId}/print-itinerary

VO: GroupPrintItineraryRespVO

使用场景

团期详情页"文档"弹窗中团级行程单的打印数据(日期、酒店、金额等)。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID

出参字段表

字段 类型 说明
出参结构不变 - 含 contactName / dayTotalAmount / totalAmount 等;定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/print-itinerary
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": { "contactName": "王五", "totalAmount": "15000.00" },
  "success": true
}

空数据 / 降级响应

  • 团期无行程数据:返回空数据。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:同上(#1)。

13. 签单凭证 GET /v3/admin/order/group-batch/{groupBatchId}/sign-voucher

VO: GroupSignVoucherRespVO

使用场景

团期详情页"文档"弹窗中签单凭证的打印数据(联系人、电话、金额等)。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID
showAmount Query Boolean ❌ - 是否显示金额
scope Query String ❌ - 凭证范围

出参字段表

字段 类型 说明
出参结构不变 - 含 contactPerson / contactPhone / totalAmount 等;定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/sign-voucher?showAmount=true
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": { "contactPerson": "张三", "contactPhone": "13800138000", "totalAmount": "15000.00" },
  "success": true
}

空数据 / 降级响应

  • 团期无凭证数据:返回空数据。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:同上(#1)。
  • 查询参数不变:showAmount 与 scope 的默认值、约束保持不变。

14. 行程汇总 GET /v3/admin/order/group-batch/{groupBatchId}/itinerary

VO: GroupBatchItineraryRespVO

使用场景

团期详情页"行程"Tab 的逐日汇总(日期、酒店、景点、金额等)。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID

出参字段表

字段 类型 说明
出参结构不变 - 含 contactName / dayTotalAmount / totalAmount 等;定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/itinerary
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": { "days": [ { "dayNumber": 1, "hotel": "如家酒店", "dayTotalAmount": "2000.00" } ] },
  "success": true
}

空数据 / 降级响应

  • 团期无行程数据:返回空数据或空数组。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:同上(#1)。

15. 行程节点明细 GET /v3/admin/order/group-batch/{groupBatchId}/itinerary/nodes/{nodeKey}

VO: GroupBatchItineraryNodeDetailVO

使用场景

团期详情页"行程"Tab 中行程节点(某天的具体景点、酒店、出发地点等)的明细信息。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID
nodeKey Path String ✅ - 行程节点键
dayNumber Query Integer ❌ - 第几天(可选)

出参字段表

字段 类型 说明
出参结构不变 - 节点级行程数据;定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/itinerary/nodes/node_001?dayNumber=1
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": { "nodeKey": "node_001", "location": "颐和园", "dayNumber": 1 },
  "success": true
}

空数据 / 降级响应

  • 节点不存在:返回空数据。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:同上(#1)。
  • 路径参数:nodeKey 必填,dayNumber 为可选查询参数。

16. 状态流水 GET /v3/admin/order/group-batch/{groupBatchId}/status-logs

VO: 无请求体 → List<GroupBatchStatusLogVO>

使用场景

团期详情页"概览"等区域的操作历史(谁在什么时间做了什么操作)。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID

出参字段表

字段 类型 说明
出参结构不变 - 状态流水数组;定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/status-logs
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": [ { "operator": "李四", "operationTime": "2026-10-02 14:30", "action": "确认配房" } ],
  "success": true
}

空数据 / 降级响应

  • 团期无操作历史:返回空数组。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:同上(#1)。

17. 物资清单 GET /v3/admin/order/group-batch/{groupBatchId}/supplies

VO: GroupBatchSuppliesRespVO

使用场景

团期详情页"物资"区域的清单数据(物资名称、单价、数量等)。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID

出参字段表

字段 类型 说明
出参结构不变 - 含单价等信息;定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/supplies
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": { "supplies": [ { "name": "导游讲解", "unitPrice": "100.00" } ] },
  "success": true
}

空数据 / 降级响应

  • 团期无物资数据:返回空数组。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:同上(#1)。

18. 物资候选 GET /v3/admin/order/group-batch/{groupBatchId}/supplies/candidates

VO: 无请求体 → List<SupplyCandidateVO>

使用场景

团期详情页"物资"区域添加物资时的候选物资下拉/搜索数据。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID

出参字段表

字段 类型 说明
出参结构不变 - 物资候选数据;定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/supplies/candidates
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": [ { "id": "2105...", "name": "导游讲解", "unitPrice": "100.00" } ],
  "success": true
}

空数据 / 降级响应

  • 无可选物资:返回空数组。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:同上(#1)。

19. 撤团候选 GET /v3/admin/order/group-batch/{groupBatchId}/withdraw-candidates

VO: WithdrawCandidateVO 列表

使用场景

团期详情页"撤团"弹窗中可撤团的子订单候选列表(客户名、已付金额等)。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID

出参字段表

字段 类型 说明
出参结构不变 - 含 customerName / paidAmount 等;定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/withdraw-candidates
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": [ { "orderId": "2105...", "customerName": "张三", "paidAmount": "5000.00" } ],
  "success": true
}

空数据 / 降级响应

  • 团期无可撤订单:返回空数组。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:同上(#1)。

20. 撤团预览 GET /v3/admin/order/group-batch/{groupBatchId}/sub-order/{orderId}/withdraw-preview

VO: 无请求体 → WithdrawPreviewVO

使用场景

团期详情页"撤团"弹窗中选中某个子订单后,展示该订单的撤团预览数据(退款金额、涉及的应收应付等)。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID
orderId Path Long ✅ - 子订单 ID

出参字段表

字段 类型 说明
出参结构不变 - 撤团预览数据(金额等);定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/sub-order/2105709698592440322/withdraw-preview
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": { "refundAmount": "5000.00", "hasPaymentRecord": true },
  "success": true
}

空数据 / 降级响应

  • 订单不存在或不属于该团期:返回空数据或错误。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:同上(#1)。

21. 转团候选 GET /v3/admin/order/group-batch/{groupBatchId}/transfer-candidates

VO: TransferCandidateVO 列表

使用场景

团期详情页"转团"弹窗中可转入的候选团期/订单列表,支持按手机号跨团期搜索(客户名、已付金额等)。

入参字段表

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期 ID
keyword Query String ❌ - 搜索关键字(手机号/姓名)

出参字段表

字段 类型 说明
出参结构不变 - 含 customerName / paidAmount 等;定制师本人团期返回完整数据

请求示例

GET /v3/admin/order/group-batch/2105709698592440321/transfer-candidates?keyword=13800138000
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": [ { "orderId": "2105...", "customerName": "李四", "paidAmount": "3000.00" } ],
  "success": true
}

空数据 / 降级响应

  • 搜索无结果或无可转订单:返回空数组。

错误响应

{
  "code": 589507,
  "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
  "data": null,
  "success": false
}

业务边界

  • 触发 589507:同上(#1)。本端点搜索支持跨团期,但归属校验作用在 {groupBatchId} 参数上,仅限定制师本人团期可查该团期的候选。

四、契约约束与正确调用方式

  • 共同变化:所有 21 个接口的请求参数、响应结构无变化,仅新增 589507 错误场景。
  • CUSTOMIZER 对非本人团期:返回 HTTP 200 + code: 589507 + data: null,与其他业务错误码(如 589500)走同一套错误处理流程。
  • hl-ui 现有处理:v2.1 通用请求拦截器(src/utils/request.js 的业务错误分支)对非成功业务码一律弹出后端 message,没有 589507 专属分支。团期详情页头部 GET /{id} 对非本人团期早已返回 589507(#7949),本次补的是同页兄弟端点。
  • 前端无需新增代码:现有拦截器即可覆盖。如果希望定制师打开非本人团期时只提示一次、不按区块各弹一次,可以在页头 GET /{id} 返回 589507 后不再拉取各区块,这属于体验优化,不影响正确性。

五、数据库行为

  • 无表结构变更、无 Flyway 迁移。
  • 归属校验基于已有子订单投影(OrderService.listInGroupOrdersByGroupBatchId),仅在读路径内存查询,不涉及写入。

六、边界行为

  • 系统上下文:无登录态(system user)时放行,不返回 589507。
  • 其他角色:ADMIN / SUPER_ADMIN / GROUP_BATCH_MANAGER / FINANCE 等对这些端点无变化,仍返回 200。
  • 团期不存在:顺序 — 角色码 → 归属 → 存在性;CUSTOMIZER 查不存在的团期返回 589507(因无在团子订单),不区分「不存在」与「不是你的」。
  • 子订单全部取消 / 团期已无在团子订单:定制师名下在该团期的子订单全部变为 CANCELLED(或已移出团期)后,同一定制师再调这 21 个端点同样返回 589507;取消前是 200。测试服已实测这一翻转。
  • 判据只看子订单顾问:「本人团期」= 该团期存在一笔在团、非 CANCELLED 的子订单,其 consultantId 等于当前登录用户;团期本身的创建人不参与判定。
  • 转团候选 transfer-candidates:校验接在该端点的判权分支内,测试服当前对定制师非本人团期返回 589507。本人团期没有可转团候选时返回 200 + [],这是业务空结果,不是权限拒绝。
  • 灰度与开关:除上一条外,没有灰度开关,所有环境均生效。

六.5 枚举

不新增枚举值。


六.6、修改前后对比

项 改前 改后
CUSTOMIZER 对任意团期 ID 返回 200 + 完整数据 仅本人团期 200,其余 589507 + null
非 CUSTOMIZER 角色 返回 200 + 完整数据 返回 200 + 完整数据(无变化)
系统上下文 返回 200 + 完整数据 返回 200 + 完整数据(无变化)
定制师本人团期判据 仅 2 个端点检查 21 个端点统一检查

六.7、影响评估

  • 是否破坏向后兼容:否。仅对 CUSTOMIZER 非本人团期新增拒绝,正常调用链路无影响。
  • 前端是否必须同步上线:否。hl-ui v2.1 现有的通用业务错误拦截器会把后端返回的 message 原样呈现,无需新增前端代码。
  • 前端 workaround 清理点:无。定制师在团期详情页的所有操作链路已依赖 GET /{id} 的 589507 拒绝(该接口已在 #7949 加过校验),本次只是补全兄弟端点的一致性。

七、不影响范围

  • 仅影响:CUSTOMIZER 角色对非本人团期的这 21 个读端点。
  • 零影响:其他角色、写操作端点、一期 HL(无 order-v3 标签)、其他权限码(如 LIST / FINANCE_VIEW / AUDIT_VIEW)。
  • 按审批单 ID({approvalId})或产品批次 ID({productBatchId})取数的团期相关端点(如流团审批详情):本次没有加这道校验,对定制师不会返回 589507;行为与改前相同。
  • staff/meal-info:跨前缀且数据类别不同(员工档案 vs 客户信息),本次未动。

八、测试环境已验证

测试服 order-v3 1f8b1dacd(2026-10-02)经网关实测:21 个端点,加上 GET /{id} 与 GET /{id}/orders 两个既有对照端点,共 23 个端点 × 3 种身份 = 69 组调用,全部符合预期。

  • 定制师 → 非本人团期:均为 HTTP 200 + code 589507 + data null,message 为「无操作权限(当前角色未授予团期权限,或该团期不在您名下)」。
  • 定制师 → 本人团期:均为 code 200。
  • 管理员 → 同一非本人团期:均为 code 200。
  • 定制师本人团期的子订单全部取消后复测:由 200 转为 589507。

十、相关文档

  • 工单 #7949(授权 CUSTOMIZER 查看本人团期)。
  • 源码 GroupBatchOwnershipGuard(新公共守卫)。

关联 / 联系人

联系人

  • 后端负责人: @wx