diff --git a/changelogs-v2/2026-09/06_7204_团期看板导摄芯片聚合零指派TODO-修改接口-管理后台.md b/changelogs-v2/2026-09/06_7204_团期看板导摄芯片聚合零指派TODO-修改接口-管理后台.md new file mode 100644 index 00000000..641f961d --- /dev/null +++ b/changelogs-v2/2026-09/06_7204_团期看板导摄芯片聚合零指派TODO-修改接口-管理后台.md @@ -0,0 +1,522 @@ +--- +schema: "hl-changelog/v2" +ticket: "7204" +title: "团期看板导/摄芯片聚合态:零指派灰、部分指派橙、全部指派绿" +consumer: "admin" +author: "wx(GIT)" +change_type: "修改接口" +backend_status: "deployed" +gateway_status: "verified" +frontend_status: "pending" +frontend_owner: "" +frontend_ref: "" +target_release: "" +verified_at: "2026-09-06" +updated_at: "2026-09-06" +base: "dev-v3" +status_note: "后端已合并(PR #7207,合并提交 7c705b80)并于 2026-09-06 19:54 部署测试服 dev-v3,网关复测通过(零指派改前 DOING → 改后 TODO);前端无需改代码,建议补芯片图例/tooltip。" +--- + +# 团期模块:看板导/摄芯片聚合态口径调整(零指派返未开始) + +## ⚠️ 关键变化 + +**只改一条聚合规则,不改任何字段名、枚举值集或户级明细。** 导游(guide)/ 摄影(photo)两枚芯片的整团聚合态 `aggregateStatus`(同一份值也就是 GB-ADM-001 `records[].chips.guide` / `chips.photo`): + +| 计入户(needsIt=true)情况 | 改前 | 改后 | +|---|---|---| +| 一户都没指派(doneCount = 0,totalCount > 0) | `DOING`(橙「进行中」) | **`TODO`(灰「未开始」)** | +| 部分已指派(0 < doneCount < totalCount) | `DOING` | `DOING`(不变) | +| 全部已指派(doneCount = totalCount > 0) | `DONE` | `DONE`(不变) | +| 没有计入户(totalCount = 0,全部免闸或无子订单) | `TODO` | `TODO`(不变) | + +**根因**:户级 `guide_status / photographer_status` 为 NULL(从未指派)时读侧归一为 `PENDING`「待指派」,而 `PENDING` 又在导/摄的「进行中」集合里,于是只要有户需要导游就恒 `DOING`。wx 2026-09-06 拍板改为与房/车「未提需求=灰、提了需求=橙、配完=绿」同一直觉。 + +**前端影响**:hl-ui `src/views/order-v2/batch/_shared/batchLifecycle.js` `chipAggState` 已把 `TODO` 映射为灰、`DOING` 橙、`DONE` 绿、`ERROR` 红,**无需改代码**;效果是「一户都没指派」的团期导/摄从橙变灰。建议:芯片区补图例或 tooltip(灰=未开始、橙=进行中、绿=已完成、红=异常)——运营把橙读成「配置完了」是本单起因。 + +房 / 车 / 约 / 保四芯片、GB-ADM-090~095 户级明细的 `items[].status`(`NONE / PENDING / DONE`)与 `statusText`(无需 / 待指派 / 已指派)**均不变**。 + +--- + +## 一、背景 + +### 现象 + +2026-09-06 测试服「团期订单」看板,产品「冻干粉发短信给」班期 2026-10-01 行,只有 1 个需要导游/摄影但从未指派的活跃子订单,「导 / 摄」芯片却是橙色(`DOING`),运营误读为「已配置完」。 + +### 调用链 + +1. hl-ui `src/stores/orderV2Batch.js:93-97` `getGroupBatchPage()` → `GET /v3/admin/order/group-batch`(GB-ADM-001)→ `records[].chips.guide / photo` +2. hl-ui 点击芯片 → `getGroupBatchChip(groupBatchId, 'guide'|'photo')` → `GET /v3/admin/order/group-batch/{groupBatchId}/chips/guide|photo`(GB-ADM-092/093)→ `aggregateStatus` +3. hl-order-service-v3:两处共用 `order/groupbatch/helper/GroupBatchChipResolver.resolveAggregateStatus`;本次在「失败→ERROR」「全完成→DONE」之后、扫描进行中值之前,对 GUIDE / PHOTOGRAPHER 增加 `doneCount == 0` 返 `TODO` 的分支 +4. 硬规则不变:流团(CANCELLED)六芯片恒 `TODO`;已返团(REVIEWING / SETTLED)房车导摄恒 `DONE`;约 / 保在房车导摄四项全 `DONE` 前恒 `TODO` + +### 地面真相(测试服 dev-v3,团期 groupBatchId=2096412454643802114) + +| 时点 | 子订单 | `chips/guide` 响应要点 | +|---|---|---| +| 改前 17:20(部署前) | 1 户,needs_guide=1,guide_status=NULL | `aggregateStatus="DOING"`,totalCount=1,doneCount=0,items[0].status=`PENDING`「待指派」 | +| 改后 19:58(部署 7c705b80 后,另造 1 户零指派测试单 2096568044598820866,测完已取消) | 同上 | `aggregateStatus="TODO"`,totalCount=1,doneCount=0,items[0].status=`PENDING`「待指派」(户级不变) | + +--- + +## 二、变更接口清单 + +| # | 接口 | 方法 | 路径 | 变更类型 | 说明 | +|---|------|------|------|----------|------| +| 1 | 团期看板分页(GB-ADM-001) | GET | `/v3/admin/order/group-batch` | 响应值语义变化 | `records[].chips.guide` / `chips.photo` 零指派由 `DOING` 改为 `TODO` | +| 2 | 导游芯片逐户明细(GB-ADM-092) | GET | `/v3/admin/order/group-batch/{groupBatchId}/chips/guide` | 响应值语义变化 | `aggregateStatus` 零指派由 `DOING` 改为 `TODO`;`items[]` 不变 | +| 3 | 摄影芯片逐户明细(GB-ADM-093) | GET | `/v3/admin/order/group-batch/{groupBatchId}/chips/photo` | 响应值语义变化 | 同上 | + +--- + +## 三、接口详情 + +### 1. 团期看板分页 `GET /v3/admin/order/group-batch` + +**VO**: `GroupBatchListReqVO → Result>` + +#### 使用场景 + +团期看板列表(hl-ui `getGroupBatchPage()`);本次只有 `records[].chips.guide` / `chips.photo` 的取值语义变化,其余字段与参数不变。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| productId | query | Long(字符串) | 否 | 雪花 ID | 按产品筛选 | +| opsStage | query | String | 否 | RECRUIT / FORMED / PENDING_TRIP / TRAVELLING / AUDITING / CHECKED / DISBANDED | 七桶筛选 | +| month | query | String | 否 | yyyy-MM | 出发月份 | +| keyword | query | String | 否 | 已转义 | 班期编号 / 名称模糊 | +| batchStatus | query | String | 否 | 团期状态码 | 可选 | +| deadlineFrom / deadlineTo | query | String | 否 | yyyy-MM-dd | 报名截止日区间 | +| pageNo | query | Integer | 否 | 默认 1 | 页码 | +| pageSize | query | Integer | 否 | 默认 20,最大 100 | 每页条数 | + +#### 出参 `Result>` + +| 字段 | 类型 | 说明 | +|------|------|------| +| data.records[] | Array | 团期行(分页容器字段为 `records / total / page / pageSize`) | +| data.records[].groupBatchId | String(Long) | 团期主订单 ID | +| data.records[].productBatchId | String(Long) | product 侧班期 ID | +| data.records[].batchStatus / batchStatusName | String | 团期状态码 / 中文名 | +| data.records[].orderCount | Integer | 活跃子订单数 | +| data.records[].chips | Object | 六键固定:`hotel / vehicle / guide / photo / contract / insurance`,值为 `TODO / DOING / DONE / ERROR` 字符串;无活跃子订单时整个 `chips` 为 `null` | +| data.records[].chips.guide | String | **本次变化**:零指派 `TODO`,部分指派 `DOING`,全部指派 `DONE`(导/摄没有失败值,不会出现 `ERROR`) | +| data.records[].chips.photo | String | 同 `chips.guide` | +| 其余字段 | — | 不变(enrolledRooms / remainRooms / receivableAmount / receivedAmount / departDate / endDate …) | + +#### 请求示例 + +```http +GET /v3/admin/order/group-batch?productId=2044306857534636034&pageNo=1&pageSize=20 HTTP/1.1 +Host: api.test.1814.love:9443 +Authorization: Bearer +``` + +#### 响应示例 + +改后(2026-09-06 19:58 实测,该行 1 户零指派、未提房车需求): + +```json +{ + "code": 200, + "message": "成功", + "data": { + "records": [ + { + "groupBatchId": "2096412454643802114", + "productBatchId": "2052935476557328386", + "productId": "2044306857534636034", + "batchName": " 没,那你", + "batchStatus": "RESOURCE_PREPARING", + "batchStatusName": "资源准备中", + "orderCount": 1, + "chips": { + "hotel": "TODO", + "vehicle": "TODO", + "guide": "TODO", + "photo": "TODO", + "contract": "TODO", + "insurance": "TODO" + } + } + ], + "total": 1, + "page": 1, + "pageSize": 20 + }, + "success": true +} +``` + +改前同一场景 `chips.guide` / `chips.photo` 为 `"DOING"`。 + +#### 空数据 / 降级响应 + +没有命中团期时 `records` 为空数组;团期无活跃子订单时该行 `chips` 为 `null`(前端六芯片全灰,不要当字符串解析)。 + +```json +{ + "code": 200, + "message": "成功", + "data": { "records": [], "total": 0, "page": 1, "pageSize": 20 }, + "success": true +} +``` + +#### 错误响应 + +```json +{ + "code": 589507, + "message": "无操作权限(非团期管理员 / 非本定制师名下)", + "data": null, + "success": false +} +``` + +HTTP 始终 200,按 `code` 判断。 + +#### 业务边界 + +- 权限 `group-batch:view` +- `chips.guide` / `chips.photo` 与 GB-ADM-092/093 的 `aggregateStatus` 同源同算法,两处必然一致 +- 硬规则优先:流团行六芯片恒 `TODO`;已返团行房车导摄恒 `DONE`;约/保在房车导摄四项全 `DONE` 前恒 `TODO` + +### 2. 导游芯片逐户明细 `GET /v3/admin/order/group-batch/{groupBatchId}/chips/guide` + +**VO**: `Result`(无请求 VO,仅路径参数) + +#### 使用场景 + +看板行点击「导」芯片时拉逐户明细(hl-ui `getGroupBatchChip(id, 'guide')`);头部 `aggregateStatus` 即看板 `chips.guide`。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| groupBatchId | path | Long(字符串) | 是 | 团期主订单 ID | 不是 product 侧 productBatchId | + +#### 出参 `Result` + +| 字段 | 类型 | 说明 | +|------|------|------| +| data.batchId | String(Long) | 团期主订单 ID | +| data.chipLabel | String | 「配导游」 | +| data.aggregateStatus | String | **本次变化**:`TODO`(零指派)/ `DOING`(部分指派)/ `DONE`(全部指派);导/摄不会出现 `ERROR` | +| data.totalCount | Integer | 计入户数(needsIt=true 的活跃子订单) | +| data.doneCount | Integer | 已指派户数 | +| data.items[] | Array | 逐户明细(**不变**) | +| data.items[].orderId / orderNo / contactName / peopleCount | String / String / String / Integer | 户标识与人数 | +| data.items[].status | String | `NONE`(免闸)/ `PENDING`(待指派)/ `DONE`(已指派) | +| data.items[].statusText | String | 无需 / 待指派 / 已指派 | +| data.items[].needsIt | Boolean | 是否需要导游 | +| data.items[].updateTime | String | 恒 null(无独立时间列) | + +#### 请求示例 + +```http +GET /v3/admin/order/group-batch/2096412454643802114/chips/guide HTTP/1.1 +Host: api.test.1814.love:9443 +Authorization: Bearer +``` + +#### 响应示例 + +改后(2026-09-06 19:58 实测): + +```json +{ + "code": 200, + "message": "成功", + "data": { + "batchId": "2096412454643802114", + "chipLabel": "配导游", + "aggregateStatus": "TODO", + "totalCount": 1, + "doneCount": 0, + "items": [ + { + "orderId": "2096568044598820866", + "orderNo": "HL20260906195548607", + "contactName": "7204复测", + "peopleCount": 1, + "status": "PENDING", + "statusText": "待指派", + "needsIt": true, + "updateTime": null + } + ] + }, + "success": true +} +``` + +改前(17:20 实测,同一团期另一户零指派)除 `aggregateStatus="DOING"` 外结构相同。 + +#### 空数据 / 降级响应 + +团期无活跃子订单或全部免闸:`totalCount=0`、`doneCount=0`、`aggregateStatus="TODO"`;`items[]` 为全部活跃户(免闸户 `status="NONE"`),无活跃户时为空数组。 + +```json +{ + "code": 200, + "message": "成功", + "data": { + "batchId": "2096412454643802114", + "chipLabel": "配导游", + "aggregateStatus": "TODO", + "totalCount": 0, + "doneCount": 0, + "items": [] + }, + "success": true +} +``` + +#### 错误响应 + +```json +{ + "code": 589500, + "message": "团期不存在", + "data": null, + "success": false +} +``` + +另:`589507` 无操作权限。 + +#### 业务边界 + +- 免闸户(needsIt=false)不计入 `totalCount / doneCount`,`status="NONE"` +- `aggregateStatus` 只读派生,不落库;在团期详情「配置导游」后扇出到全部子订单即 `DONE` + +### 3. 摄影芯片逐户明细 `GET /v3/admin/order/group-batch/{groupBatchId}/chips/photo` + +**VO**: `Result`(无请求 VO,仅路径参数) + +#### 使用场景 + +看板行点击「摄」芯片时拉逐户明细(hl-ui `getGroupBatchChip(id, 'photo')`);头部 `aggregateStatus` 即看板 `chips.photo`。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| groupBatchId | path | Long(字符串) | 是 | 团期主订单 ID | 同上 | + +#### 出参 `Result` + +| 字段 | 类型 | 说明 | +|------|------|------| +| data.chipLabel | String | 「配摄影」 | +| data.aggregateStatus | String | **本次变化**:规则同导游 | +| data.totalCount / doneCount | Integer | 同导游 | +| data.items[] | Array | 结构与导游接口完全相同,`items[].needsIt` 取需要摄影 | + +#### 请求示例 + +```http +GET /v3/admin/order/group-batch/2096412454643802114/chips/photo HTTP/1.1 +Host: api.test.1814.love:9443 +Authorization: Bearer +``` + +#### 响应示例 + +改后(19:58 实测): + +```json +{ + "code": 200, + "message": "成功", + "data": { + "batchId": "2096412454643802114", + "chipLabel": "配摄影", + "aggregateStatus": "TODO", + "totalCount": 1, + "doneCount": 0, + "items": [ + { + "orderId": "2096568044598820866", + "orderNo": "HL20260906195548607", + "contactName": "7204复测", + "peopleCount": 1, + "status": "PENDING", + "statusText": "待指派", + "needsIt": true, + "updateTime": null + } + ] + }, + "success": true +} +``` + +#### 空数据 / 降级响应 + +同导游接口:无计入户时 `totalCount=0`、`aggregateStatus="TODO"`。 + +```json +{ + "code": 200, + "message": "成功", + "data": { "batchId": "2096412454643802114", "chipLabel": "配摄影", "aggregateStatus": "TODO", "totalCount": 0, "doneCount": 0, "items": [] }, + "success": true +} +``` + +#### 错误响应 + +```json +{ + "code": 589500, + "message": "团期不存在", + "data": null, + "success": false +} +``` + +#### 业务边界 + +- 同导游接口 + +--- + +## 四、契约约束与正确调用方式 + +> 三个接口均为只读 GET,无请求体;本节写的是**前端消费聚合态的规则**。 + +### ✅ 正确 / ❌ 错误 payload 对照 + +| 场景 | payload / 处理 | +|------|---------| +| ✅ 按四值渲染 | `chips.guide` ∈ `TODO / DOING / DONE / ERROR` → 灰 / 橙 / 绿 / 红;未知值按灰 | +| ✅ `chips` 为 null | 六芯片全灰,不请求 090~095 明细 | +| ✅ 弹层头部与看板一致 | `chips/guide.aggregateStatus` 与 `records[].chips.guide` 同源,勿各算各的 | +| ❌ 用户级 `items[].status` 反推整团态 | 户级 `PENDING`「待指派」不等于整团进行中:零指派时整团是 `TODO` | +| ❌ 把 `DOING` 当「已配置」 | `DOING` 只表示部分户已指派 | + +### 切换状态时的必要动作 + +无写接口;指派动作走团期详情「配置导游 / 摄影」,完成后重新拉 GB-ADM-001 或 090~095 即可看到 `DONE`。 + +--- + +## 五、数据库行为 + +本次无写操作、无表变更。`aggregateStatus` / `chips.*` 为读时派生(`GroupBatchChipResolver` 内存计算),不落库;户级来源仍是 `order_main.guide_status / photographer_status`(取值只有 `DONE` 或 NULL)。 + +| 计入户情况 | 派生结果 | +|------|-----------------| +| doneCount = 0,totalCount > 0 | `TODO` | +| 0 < doneCount < totalCount | `DOING` | +| doneCount = totalCount > 0 | `DONE` | +| totalCount = 0 | `TODO` | + +--- + +## 六、边界行为 + +- 未登录 → 网关 401;无 `group-batch:view` → `589507` +- 团期不存在 → `589500` +- 流团团期 → 六芯片恒 `TODO`(硬规则 1);已返团团期 → 房车导摄恒 `DONE`(硬规则 2) +- 约 / 保在房车导摄四项未全 `DONE` 前恒 `TODO`(硬规则 3,本次导/摄零指派落 `TODO` 后约/保同样保持 `TODO`) +- HTTP 始终 200,按 `code` 判断 + +## 六.5、枚举 / 数据字典 + +### aggregateStatus / chips.*(`com.hulalv.order.groupbatch.helper.GroupBatchChipResolver` 常量 `AGGREGATE_TODO / AGGREGATE_DOING / AGGREGATE_DONE / AGGREGATE_ERROR`) + +| 值 | 含义 | 前端色 | +|---|---|---| +| `TODO` | 未开始(导/摄:零指派;房/车:未提需求) | 灰 | +| `DOING` | 进行中(导/摄:部分指派;房/车:需求已提交/处理中/待审核) | 橙 | +| `DONE` | 已完成 | 绿 | +| `ERROR` | 异常(房/车驳回、约作废、保失败;导/摄不会出现) | 红 | + +### items[].status(导/摄户级,`GroupBatchChipResolver.readGuideStatus`) + +| 值 | 含义 | statusText | +|---|---|---| +| `NONE` | 该户无需导游/摄影(免闸,不计入) | 无需 | +| `PENDING` | 需要且未指派 | 待指派 | +| `DONE` | 已指派 | 已指派 | + +## 六.6、修改前后对比 + +### 字段级对比 + +| 字段 | 修改前 | 修改后 | +|------|--------|--------| +| `records[].chips.guide` / `chips.photo`、`aggregateStatus` 取值集 | `TODO / DOING / DONE` | 不变 | +| 零指派场景取值 | `DOING` | `TODO` | + +### 行为级对比 + +| 场景 | 修改前 | 修改后 | +|------|--------|--------| +| 零指派(doneCount=0,totalCount=1) | `DOING`(橙) | `TODO`(灰) | +| 部分指派(doneCount=1,totalCount=2) | `DOING`(橙) | `DOING`(橙) | +| 全部指派(doneCount=2,totalCount=2) | `DONE`(绿) | `DONE`(绿) | +| 全部免闸(totalCount=0) | `TODO` | `TODO` | +| 已返团(REVIEWING / SETTLED) | `DONE`(硬规则) | `DONE` | +| 流团(CANCELLED) | `TODO`(硬规则) | `TODO` | + +## 六.7、影响评估 + +- 向后兼容:字段名、枚举值集不变,只是零指派场景的取值变化;老前端不改也能正确渲染 +- 前端是否必须同步上线:否 +- 数据:无表变更、无迁移;聚合态实时派生不落库 + +--- + +## 七、不影响范围 + +- **仅影响**: 管理后台团期看板行「导 / 摄」芯片颜色,以及 090~095 弹层头部聚合态 +- **零影响**: + - 房 / 车 / 约 / 保四芯片 + - 户级明细 `items[]`(值与文案不变) + - 团期详情 `hotelReady / guideReady / photographerReady` 标志 + - 指派流程、团期状态机、订单接口 + - 小程序 + +--- + +## 八、测试环境已验证 + +真实接口输出(测试服 api.test.1814.love,2026-09-06,登录后切 ADMIN 角色): + +``` +GET /v3/admin/order/group-batch/2096412454643802114/chips/guide → 200, aggregateStatus=TODO, total=1, done=0, items[0]=PENDING/待指派 ✓(改前 17:20 同场景 DOING) +GET /v3/admin/order/group-batch/2096412454643802114/chips/photo → 200, aggregateStatus=TODO, total=1, done=0 ✓ +GET /v3/admin/order/group-batch?productId=2044306857534636034 → 200, 该行 chips.guide=TODO, chips.photo=TODO, hotel=TODO, vehicle=TODO ✓ +``` + +验证团期: `groupBatchId=2096412454643802114`(产品 2044306857534636034「冻干粉发短信给」,班期 2026-10-01);造的零指派测试单 2096568044598820866 已取消。 + +单测:`GroupBatchChipResolverTest` 30/0/0(新增零指派 / 部分指派 / 全部指派 / 免闸 / 房车不受影响五例)、`GroupBatchChipServiceTest` 14/0、`GroupBatchQueryServiceTest` 23/0、ArchTest 门禁 41/0。部署:Deploy Panel 19:54 双实例滚动完成,分支 dev-v3。 + +--- + +## 十、相关文档 + +- 关联 Issue: [wx/HL#7204](https://git.1814.love:8443/wx/HL/issues/7204) +- 关联 PR: [wx/HL#7207](https://git.1814.love:8443/wx/HL/pulls/7207) +- 同现场: #7188(「第N期」序号)、#7189(看板以产品全班期为基底 + 班期范围筛选)、#7190(「出行完毕」状态与八桶) +- 前端缺陷 changelog: `06_frontend_团期看板展开行子订单列表恒空-前端缺陷-管理后台.md` + +## 关联 / 联系人 + +### 链接 + +- **Issue**: [#7204](https://git.1814.love:8443/wx/HL/issues/7204) +- **PR**: [#7207](https://git.1814.love:8443/wx/HL/pulls/7207) +- **Merge commit**: [7c705b80](https://git.1814.love:8443/wx/HL/commit/7c705b808723bc415b5dc99d0535d0521668f90f) + +### 联系人 + +- **后端负责人**: @wx