diff --git a/changelogs-v2/2026-09/17_7853_团期配导游配摄影逐户明细带出已配置人员-修改接口-管理后台.md b/changelogs-v2/2026-09/17_7853_团期配导游配摄影逐户明细带出已配置人员-修改接口-管理后台.md new file mode 100644 index 00000000..502d0057 --- /dev/null +++ b/changelogs-v2/2026-09/17_7853_团期配导游配摄影逐户明细带出已配置人员-修改接口-管理后台.md @@ -0,0 +1,509 @@ +--- +schema: "hl-changelog/v2" +ticket: "7853" +title: "团期配导游/配摄影逐户明细带出已配置人员(角色、姓名、手机号)" +consumer: "admin" +author: "jw(GIT)" +change_type: "修改接口" +backend_status: "deployed" +gateway_status: "verified" +frontend_status: "pending" +frontend_owner: "" +frontend_ref: "" +target_release: "" +verified_at: "" +status_note: "chips/guide、chips/photo 新增 staffList(本团本配置位已配置名单)与 items[].staffs(每户实际分到的人,带来源),字段含角色 staffRoleName、姓名 staffName、脱敏手机号 staffPhone;只加不改,测试服两轮验收 21 项全部通过(见第八节与工单 #7853 验收评论)。前端待办:配导游 / 配摄影标签页顶部显示 staffList,进度表每户显示 staffs(见第四节);弹窗保存仍以 GET .../staff 为已选名单来源。" +updated_at: "2026-09-17" +base: "dev-v3" +--- + +# order-v3: 团期配导游/配摄影逐户明细带出已配置人员 + +> **存放目录**: `changelogs-v2/{YYYY-MM}/`(管理后台,二期 order-v3) +> +> **服务**: hl-order-service-v3 (端口 8086) +> **PR**: #7856 +> **Issue**: #7853 +> **日期**: 2026-09-17 +> **影响范围**: 团期详情页「配导游」「配摄影」两个标签页 + +--- + +## ⚠️ 关键变化 + +1. **两个接口新增了人员信息**:`GET .../chips/guide` 和 `GET .../chips/photo` 现在直接带出「配了谁」,包括**角色、人员姓名、手机号**(脱敏)。 + - 顶层 `staffList`:本团这个配置位的已配置名单; + - 每户 `items[].staffs`:这一户实际分到的人。 +2. **只加字段,不改原有字段**,老页面不受影响。 +3. **前端待办**:在这两个标签页显示人员信息,见第四节。以前要显示已配置人员,只能另调 `GET /v3/admin/group-batch/{productBatchId}/staff`,而且要换成产品侧 ID;现在直接用本接口的数据即可。 +4. 配房、配车、合同、保险四个芯片接口也是同一个响应结构,这两个新字段在那边**恒为 null**。 + +--- + +## 一、背景 + +「配导游」「配摄影」标签页此前只能看到每户的进度(待指派 / 已指派 / 无需),看不到具体配了哪些人。jw 2026-09-16 / 09-17 确认: +- 这两个接口要带出角色、人员姓名、手机号,**整团名单和每户人员都要**; +- 手机号保持脱敏; +- 按日期分段配置(哪天到哪天是哪个导游)本期不做,现有数据也没有日期字段。 + +--- + +## 二、变更接口清单 + +| # | 接口 | 方法 | 路径 | 变更类型 | 说明 | +|---|------|------|------|----------|------| +| 1 | 配导游逐户明细 | GET | `/v3/admin/order/group-batch/{groupBatchId}/chips/guide` | 修改 | 新增 `staffList`、`items[].staffs`(导游 + 领队) | +| 2 | 配摄影逐户明细 | GET | `/v3/admin/order/group-batch/{groupBatchId}/chips/photo` | 修改 | 新增 `staffList`、`items[].staffs`(摄影) | + +--- + +## 三、接口详情 + +### 1. 配导游逐户明细 `GET /v3/admin/order/group-batch/{groupBatchId}/chips/guide` + +**VO**: `Result`(新增 `staffList`、`items[].staffs`,元素为 `GroupBatchChipStaffVO`) + +#### 使用场景 + +团期详情页「配导游」标签页。原有的进度表照旧渲染;本次新增的两个字段用于显示「配了谁」: +- `staffList`:页面顶部的「已配置人员」区,显示本团的导游位人员(导游 + 领队)名单; +- `items[].staffs`:进度表每一行(每户)显示这一户实际分到的导游位人员(导游 + 领队)。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| groupBatchId | Path | Long | ✅ | 运营团期主键 | 与本接口原来的用法相同,不需要换成 productBatchId | + +#### 出参 + +以下只列**新增**字段,原有字段不变。 + +| 字段 | 类型 | 说明 | +|------|------|------| +| staffList | List | 本团导游位人员(导游 + 领队)的已配置名单,只含 `staffRole ∈ GUIDE / LEADER`,按配置时的排序。未配置时为 `[]`,不会是 null | +| staffList[].staffId | String | 人员 ID | +| staffList[].staffRole | String | 角色代码:GUIDE / LEADER | +| staffList[].staffRoleName | String | **角色名称**(导游 / 领队) | +| staffList[].staffName | String | **人员姓名** | +| staffList[].staffPhone | String | **手机号**,前 3 后 4 脱敏;没有手机号时为 null | +| staffList[].reporterRank | String | 报账人等级 `PRIMARY` / `SECONDARY` / `NONE` | +| staffList[].reporterRankName | String | 主报账人 / 次报账人 / 非报账人 | +| staffList[].source / sourceName | String | 在 `staffList` 中恒为 null | +| items[].staffs | List | 这一户实际分到的导游位人员(导游 + 领队),字段同 `staffList[]`;这一户没有时为 `[]` | +| items[].staffs[].source | String | `GROUP_BATCH`(由团期配置同步来的)/ `ORDER`(在订单上单独加的) | +| items[].staffs[].sourceName | String | 团期同步 / 订单专属 | + +#### 请求示例 + +```http +GET /v3/admin/order/group-batch/2100400970927157250/chips/guide +Authorization: Bearer +``` + +#### 响应示例 + +(测试服真实响应,2026-09-17,`items` 只截取第一户) + +```json +{ + "code": 200, + "message": "成功", + "data": { + "batchId": "2100400970927157250", + "groupBatchId": "2100400970927157250", + "chipLabel": "配导游", + "aggregateStatus": "DONE", + "aggregateStatusName": "已完成", + "totalCount": 2, + "doneCount": 2, + "staffList": [ + { + "staffId": "1002", + "staffRole": "GUIDE", + "staffRoleName": "导游", + "staffName": "李雪梅", + "staffPhone": "138****1002", + "reporterRank": "PRIMARY", + "reporterRankName": "主报账人", + "source": null, + "sourceName": null + }, + { + "staffId": "1005", + "staffRole": "LEADER", + "staffRoleName": "领队", + "staffName": "刘大山", + "staffPhone": "138****1005", + "reporterRank": "NONE", + "reporterRankName": "非报账人", + "source": null, + "sourceName": null + } + ], + "items": [ + { + "orderId": "2100400970570641410", + "orderNo": "HL20260917094629361", + "teamNo": null, + "contactName": "测试七八五三甲", + "customerName": "测试七八五三甲", + "peopleCount": 2, + "status": "DONE", + "statusText": "已指派", + "statusName": "已指派", + "needsIt": true, + "updateTime": null, + "claimerId": null, + "claimerName": null, + "claimerSource": null, + "staffs": [ + { + "staffId": "1002", + "staffRole": "GUIDE", + "staffRoleName": "导游", + "staffName": "李雪梅", + "staffPhone": "138****1002", + "reporterRank": "PRIMARY", + "reporterRankName": "主报账人", + "source": "GROUP_BATCH", + "sourceName": "团期同步" + }, + { + "staffId": "1005", + "staffRole": "LEADER", + "staffRoleName": "领队", + "staffName": "刘大山", + "staffPhone": "138****1005", + "reporterRank": "NONE", + "reporterRankName": "非报账人", + "source": "GROUP_BATCH", + "sourceName": "团期同步" + }, + { + "staffId": "1011", + "staffRole": "LEADER", + "staffRoleName": "领队", + "staffName": "巴特尔", + "staffPhone": "139****1011", + "reporterRank": "NONE", + "reporterRankName": "非报账人", + "source": "ORDER", + "sourceName": "订单专属" + } + ] + } + ] + }, + "success": true +} +``` + +#### 空数据 / 降级响应 + +团期没有配置导游位人员(导游 + 领队)、某户也没有分到人时,两个字段都是空数组: + +```json +{ + "code": 200, + "message": "成功", + "data": { + "chipLabel": "配导游", + "staffList": [], + "items": [ { "orderNo": "HL20260917094629361", "staffs": [] } ] + } +} +``` + +某一行手机号解密失败时,只有该项的 `staffPhone` 为 null,接口照常返回。 + +#### 错误响应 + +```json +{ "code": 589507, "message": "无操作权限(非团期管理员 / 非本定制师名下)", "data": null } +``` + +| code | 触发条件 | +|------|----------| +| 589507 | 没有团期查看权限 | +| 589500 | 团期不存在 | +| 401 | 未登录(网关拦截) | + +与本次改动前相同,没有新增错误码。 + +#### 业务边界 + +- 只读接口,判权、团期校验与原来一致;无权限时不会查询人员数据。 +- `staffList` 与 `GET /v3/admin/group-batch/{productBatchId}/staff` 是同一份数据,只是按配置位过滤了;前端在这个页面**不必再调**那个接口去显示已配置人员。 +- `items[].staffs` 来自每个订单的人员分配:团期配置保存后会同步到每一户,所以通常每户都和 `staffList` 相同;如果某户在订单上单独加了人,会多出 `source=ORDER` 的行。 +- 手机号一律脱敏,不提供明文。 +- 人员没有日期分段:一个人配上去就代表负责整个行程。 +- 查询次数固定(整团 1 次、所有户 1 次),与户数无关。 + +--- + +### 2. 配摄影逐户明细 `GET /v3/admin/order/group-batch/{groupBatchId}/chips/photo` + +**VO**: `Result`(新增 `staffList`、`items[].staffs`,元素为 `GroupBatchChipStaffVO`) + +#### 使用场景 + +团期详情页「配摄影」标签页。原有的进度表照旧渲染;本次新增的两个字段用于显示「配了谁」: +- `staffList`:页面顶部的「已配置人员」区,显示本团的摄影位人员名单; +- `items[].staffs`:进度表每一行(每户)显示这一户实际分到的摄影位人员。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| groupBatchId | Path | Long | ✅ | 运营团期主键 | 与本接口原来的用法相同,不需要换成 productBatchId | + +#### 出参 + +以下只列**新增**字段,原有字段不变。 + +| 字段 | 类型 | 说明 | +|------|------|------| +| staffList | List | 本团摄影位人员的已配置名单,只含 `staffRole ∈ PHOTOGRAPHER`,按配置时的排序。未配置时为 `[]`,不会是 null | +| staffList[].staffId | String | 人员 ID | +| staffList[].staffRole | String | 角色代码:PHOTOGRAPHER | +| staffList[].staffRoleName | String | **角色名称**(摄影) | +| staffList[].staffName | String | **人员姓名** | +| staffList[].staffPhone | String | **手机号**,前 3 后 4 脱敏;没有手机号时为 null | +| staffList[].reporterRank | String | 报账人等级 `PRIMARY` / `SECONDARY` / `NONE` | +| staffList[].reporterRankName | String | 主报账人 / 次报账人 / 非报账人 | +| staffList[].source / sourceName | String | 在 `staffList` 中恒为 null | +| items[].staffs | List | 这一户实际分到的摄影位人员,字段同 `staffList[]`;这一户没有时为 `[]` | +| items[].staffs[].source | String | `GROUP_BATCH`(由团期配置同步来的)/ `ORDER`(在订单上单独加的) | +| items[].staffs[].sourceName | String | 团期同步 / 订单专属 | + +#### 请求示例 + +```http +GET /v3/admin/order/group-batch/2100400970927157250/chips/photo +Authorization: Bearer +``` + +#### 响应示例 + +(测试服真实数据,2026-09-17,省略了未变的原有字段) + +```json +{ + "code": 200, + "message": "成功", + "data": { + "chipLabel": "配摄影", + "staffList": [ + { "staffId": "1003", "staffRole": "PHOTOGRAPHER", "staffRoleName": "摄影", "staffName": "王强", + "staffPhone": "138****1003", "reporterRank": "NONE", "reporterRankName": "非报账人", + "source": null, "sourceName": null } + ], + "items": [ + { "orderNo": "HL20260917094629361", "customerName": "测试七八五三甲", + "staffs": [ + { "staffId": "1003", "staffRole": "PHOTOGRAPHER", "staffRoleName": "摄影", "staffName": "王强", + "staffPhone": "138****1003", "reporterRank": "NONE", "reporterRankName": "非报账人", + "source": "GROUP_BATCH", "sourceName": "团期同步" } + ] } + ] + } +} +``` + +#### 空数据 / 降级响应 + +团期没有配置摄影位人员、某户也没有分到人时,两个字段都是空数组: + +```json +{ + "code": 200, + "message": "成功", + "data": { + "chipLabel": "配摄影", + "staffList": [], + "items": [ { "orderNo": "HL20260917094629361", "staffs": [] } ] + } +} +``` + +某一行手机号解密失败时,只有该项的 `staffPhone` 为 null,接口照常返回。 + +#### 错误响应 + +```json +{ "code": 589507, "message": "无操作权限(非团期管理员 / 非本定制师名下)", "data": null } +``` + +| code | 触发条件 | +|------|----------| +| 589507 | 没有团期查看权限 | +| 589500 | 团期不存在 | +| 401 | 未登录(网关拦截) | + +与本次改动前相同,没有新增错误码。 + +#### 业务边界 + +- 只读接口,判权、团期校验与原来一致;无权限时不会查询人员数据。 +- `staffList` 与 `GET /v3/admin/group-batch/{productBatchId}/staff` 是同一份数据,只是按配置位过滤了;前端在这个页面**不必再调**那个接口去显示已配置人员。 +- `items[].staffs` 来自每个订单的人员分配:团期配置保存后会同步到每一户,所以通常每户都和 `staffList` 相同;如果某户在订单上单独加了人,会多出 `source=ORDER` 的行。 +- 手机号一律脱敏,不提供明文。 +- 人员没有日期分段:一个人配上去就代表负责整个行程。 +- 查询次数固定(整团 1 次、所有户 1 次),与户数无关。 + +--- + +## 四、契约约束与正确调用方式 + +### 前端展示建议 + +| 位置 | 数据 | 每行显示 | +|------|------|----------| +| 标签页顶部「已配置人员」 | `data.staffList` | 角色名称 `staffRoleName` · 人员姓名 `staffName` · 手机号 `staffPhone`;可加报账人标记 `reporterRankName` | +| 进度表每户一行 | `data.items[].staffs` | 同上,多人时并列显示;`source=ORDER` 的可加「订单专属」标记 | +| 「配置导游 / 配置摄影」弹窗的已选名单 | 仍以 `GET /v3/admin/group-batch/{productBatchId}/staff` 为准 | 保存接口是全量覆盖,见 #7827 的说明 | + +### ✅ 正确 / ❌ 错误 用法 + +| 场景 | 做法 | +|------|------| +| ✅ 标签页显示已配置人员 | 直接读本接口的 `staffList`,不需要再调其他接口 | +| ✅ 判断某户有没有配人 | 看 `items[].staffs` 是否为空数组 | +| ❌ 把 `staffList` 当作保存弹窗的已选名单 | 它只包含当前配置位;保存接口需要全团所有配置位的完整名单,请用 `GET .../staff` | +| ❌ 在配房、配车、合同、保险芯片上读这两个字段 | 那边恒为 null | +| ❌ 期待拿到明文手机号 | 手机号一律脱敏,不提供明文 | + +--- + +## 六、边界行为 + +- 未配置人员 → `staffList: []`,每户 `staffs: []`。 +- 团期还没有活跃子订单 → `items: []`,`staffList` 照常返回。 +- 已取消的子订单不出现在 `items` 中,也不会查它的人员(原有口径)。 +- 已删除的人员分配不出现。 +- 某一行手机号解密失败 → 该项 `staffPhone=null`,接口照常返回。目前测试服的导游、领队、摄影数据都没有加密,这种情况实际不会出现。 +- 无权限 → 589507;团期不存在 → 589500;未登录 → 401(均与改动前相同)。 + +--- + +## 六.5、枚举 / 数据字典 + +### staffRole(角色) + +**所属字段**: `staffList[].staffRole`、`items[].staffs[].staffRole` | **类型**: `String` + +| 值 | 中文(`staffRoleName`) | 出现在 | +|----|------|------| +| `GUIDE` | 导游 | 配导游 | +| `LEADER` | 领队 | 配导游 | +| `PHOTOGRAPHER` | 摄影 | 配摄影 | + +### source(来源,仅每户人员) + +**所属字段**: `items[].staffs[].source` | **类型**: `String` + +| 值 | 中文(`sourceName`) | 含义 | +|----|------|------| +| `GROUP_BATCH` | 团期同步 | 由团期的人员配置同步到这一户 | +| `ORDER` | 订单专属 | 在这一户的订单上单独加的 | + +### reporterRank(报账人等级) + +**所属字段**: `staffList[].reporterRank`、`items[].staffs[].reporterRank` | **类型**: `String` + +| 值 | 中文(`reporterRankName`) | +|----|------| +| `PRIMARY` | 主报账人 | +| `SECONDARY` | 次报账人 | +| `NONE` | 非报账人 | + +--- + +## 六.6、修改前后对比 + +### 字段级对比 + +| 字段 | 改前 | 改后 | +|------|------|------| +| `data.staffList` | 无 | 配导游 / 配摄影:已配置名单(未配置为 `[]`);其他芯片:`null` | +| `data.items[].staffs` | 无 | 配导游 / 配摄影:这一户的人员(没有为 `[]`);其他芯片:`null` | +| 其余字段 | — | 不变 | + +### 行为级对比 + +| 行为 | 改前 | 改后 | +|------|------|------| +| 标签页显示已配置人员 | 需另调 `GET /v3/admin/group-batch/{productBatchId}/staff`,并换成产品侧 ID | 直接读本接口 | +| 看某户具体分到了谁 | 只能进订单详情看 | 本接口每户直接给出 | +| 查询次数 | — | 配导游 / 配摄影每次多 2 次查询(整团 1 次 + 所有户 1 次),与户数无关 | + +## 六.7、影响评估 + +- **是否破坏向后兼容**: 否,只新增字段。 +- **前端是否必须同步上线**: 否,不改也不会报错;但需要前端接入后,页面才会显示人员信息。 +- **前端 workaround 清理点**: 如果页面为了显示已配置人员另调了 `GET .../staff`,改用本接口的 `staffList` 后,该调用在这两个标签页可以去掉(弹窗保存仍需用它)。 + +--- + +## 七、不影响范围 + +- **仅影响**: `chips/guide`、`chips/photo` 两个接口的响应(新增字段)。 +- **零影响**: + - `chips/hotel`、`chips/vehicle`、`chips/contract`、`chips/insurance`(响应结构相同,新字段为 null) + - 团期看板与列表的进度统计 + - `GET / PUT /v3/admin/group-batch/{productBatchId}/staff`、候选接口 `.../staff/candidates`、`.../staff/candidates/page` + - 订单详情 `GET /v3/admin/order/{id}/staff` + - 数据库:无表结构变更,只读 + +--- + +## 八、测试环境已验证 + +被测版本:hl-order-service-v3 = dev-v3 `b4cff0427`(2026-09-17 10:06 部署)。此前已先用特性分支 `7c67fe063` 跑过同一套验收。验收脚本两轮均 **21/21** 通过。 + +``` +未配置时 chips/guide → staffList=[],每户 staffs=[] ✓ +配置后 chips/guide → staffList=[李雪梅 导游 138****1002 主报账人, 刘大山 领队 138****1005 非报账人] ✓ + 与 GET /v3/admin/group-batch/{productBatchId}/staff 逐字段一致 ✓ + 甲户 staffs = 李雪梅、刘大山(团期同步)+ 巴特尔(订单专属 source=ORDER)✓ + 乙户 staffs = 李雪梅、刘大山(团期同步),没有串户 ✓ + 导游页户级不含摄影 ✓ + chips/photo → staffList=[王强 摄影 138****1003],两户 staffs 都只有王强 ✓ +chips/hotel、vehicle、contract、insurance → staffList=null,items[].staffs=null ✓ +顶层字段 = 原字段 + staffList;totalCount / doneCount / aggregateStatus 照旧 ✓ +CUSTOMIZER 角色 → 589507 ✓ +团期不存在 → 589500 ✓ +``` + +验证数据:自建团期 `2100400970927157250`(两户),验完已取消订单、清空人员配置、取消成团并取消班期。 + +--- + +## 九、相关历史 PR + +| PR | Issue | 说明 | 是否仍有效 | +|----|-------|------|------------| +| #7831 | #7827 | 配置导游 / 摄影候选分页与模糊搜索 | ✅ 有效 | +| **本 PR #7856** | **#7853** | 逐户明细带出已配置人员 | ✅ 最新 | + +--- + +## 十、相关文档 + +- 关联 Issue: [wx/HL#7853](https://git.1814.love:8443/wx/HL/issues/7853) +- 关联 PR: [wx/HL#7856](https://git.1814.love:8443/wx/HL/pulls/7856) +- 前序: `changelogs-v2/2026-09/16_7827_团期配置导游摄影候选分页与模糊搜索-新增接口-管理后台.md` + +## 关联 / 联系人 + +### 链接 + +- **Issue**: [#7853](https://git.1814.love:8443/wx/HL/issues/7853) +- **PR**: [#7856](https://git.1814.love:8443/wx/HL/pulls/7856) +- **Merge commit**: [b4cff0427](https://git.1814.love:8443/wx/HL/commit/b4cff0427) + +### 联系人 + +- **后端负责人**: @jw