From 077845c8aaab8e449d54c31ffe9b72153db6a9b0 Mon Sep 17 00:00:00 2001 From: API Changelog Bot Date: Sun, 6 Sep 2026 18:56:15 +0800 Subject: [PATCH] =?UTF-8?q?changelog(frontend):=20=E5=9B=A2=E6=9C=9F?= =?UTF-8?q?=E7=9C=8B=E6=9D=BF=E5=B1=95=E5=BC=80=E8=A1=8C=E5=AD=90=E8=AE=A2?= =?UTF-8?q?=E5=8D=95=E5=88=97=E8=A1=A8=E6=81=92=E7=A9=BA=E2=80=94=E2=80=94?= =?UTF-8?q?store.currentGroupBatchId=20=E5=8F=AA=E5=9C=A8=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E9=A1=B5=E8=B5=8B=E5=80=BC=E8=87=B4=20PeriodRow=20?= =?UTF-8?q?=E9=97=A8=E6=8E=A7=E6=81=92=E7=A9=BA=EF=BC=9BGB-ADM-003=20?= =?UTF-8?q?=E5=AE=9E=E6=B5=8B=E6=AD=A3=E7=A1=AE=EF=BC=88=E5=85=B3=E8=81=94?= =?UTF-8?q?=20#7204/#7188/#7189/#7190=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01N7Xpgcv9nncadAXQtWhg4P --- ...œ‹板展开行子订单列表恒空-前端缺陷-管理后台.md | 260 ++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 changelogs-v2/2026-09/06_frontend_团期看板展开行子订单列表恒空-前端缺陷-管理后台.md diff --git a/changelogs-v2/2026-09/06_frontend_团期看板展开行子订单列表恒空-前端缺陷-管理后台.md b/changelogs-v2/2026-09/06_frontend_团期看板展开行子订单列表恒空-前端缺陷-管理后台.md new file mode 100644 index 00000000..37382bc4 --- /dev/null +++ b/changelogs-v2/2026-09/06_frontend_团期看板展开行子订单列表恒空-前端缺陷-管理后台.md @@ -0,0 +1,260 @@ +--- +schema: "hl-changelog/v2" +ticket: "frontend" +title: "团期看板展开行子订单列表恒空" +consumer: "admin" +author: "wx(GIT)" +change_type: "前端缺陷" +backend_status: "not_required" +gateway_status: "not_required" +frontend_status: "pending" +frontend_owner: "" +frontend_ref: "" +target_release: "" +verified_at: "" +status_note: "后端 GB-ADM-003 已在测试服 dev-v3 网关实测返回 1 条活跃子订单;纯前端门控 bug:store.currentGroupBatchId 只在详情页 fetchDetail 赋值,看板展开走的 fetchBatchOrders 不赋值,PeriodRow 子订单列表恒空。首选按 groupBatchId 键缓存(PeriodRow 原注释的设计),并把 ordersError 显示出来。" +updated_at: "2026-09-06" +base: "dev-v3" +--- + +# 团期订单:看板展开行子订单列表恒空(前端缺陷) + +## ⚠️ 关键变化 + +**现象**:管理后台「团期订单」看板,产品「冻干粉发短信给」班期 2026-10-01「没,那你」这一行显示「已订房 1/8 · 剩 7 · 应收 5850.00 · 已收 5850.00」,点击展开却显示「本期暂无子订单。」,也没有加载态。 + +**根因(hl-ui `gitea/v2.1` 提交 e78ba5be)**:`src/stores/orderV2Batch.js:147-166` `fetchBatchOrders(groupBatchId)` 请求成功后只写 `batchOrders`,**不写 `currentGroupBatchId`**;该字段全文件唯一赋值点是 `:129-131` `fetchDetail()`(团期详情页才调)。而 `src/views/order-v2/batch/components/PeriodRow.vue:233-235` 的子订单列表和 `:236-238` 的加载态都门控于 `String(store.currentGroupBatchId) === groupBatchId.value`。看板页展开只走 `onToggle → store.fetchBatchOrders`(`:240-245`),`currentGroupBatchId` 保持初始 `''`,门控永远不等 → `orders` 恒 `[]` → `SubOrderTable.vue:4-7` `v-if="!subs.length"` 渲染「本期暂无子订单。」。只有在同一 SPA 会话里先进过**该团期**的详情页(`fetchDetail` 把 `currentGroupBatchId` 设成它)再回看板展开同一行,才碰巧显示正确;刷新页面后直接展开必现。 + +**结论**:后端零改动(GB-ADM-001 / GB-ADM-003 实测正确)。前端修法首选**按 `groupBatchId` 键缓存子订单**(`PeriodRow.vue:232` 原注释「按 groupBatchId 缓存」就是这个设计,现实现漂移成了借用详情页的 `currentGroupBatchId` 单值门控);同时把 `store.ordersError` 显示出来,否则接口 4xx/5xx 时也会伪装成「暂无子订单」。 + +行上的「1/8」「5850」和「房/导/摄」橙色芯片**都是当时那条被挡住的活跃子订单 HL20260906093733163 的真实状态**,不是看板算错:已订房按「1 单 = 1 房」持久计数器算(`order_group_batch.enrolled_rooms`),产品侧「线下占位房数」不参与已订房/剩余;橙 = 进行中(`batchLifecycle.js:64-70` DOING → doing),不是「配置完了」。导/摄「零指派却橙」的后端口径已另立 #7204 修正。补充说明:这条子订单本是 2026-09-06 01:37 已取消的测试单,14 时许被团期房务会话为 #7149 实测用 SQL 临时改成「定制中 / 已付订金」,18:51 已复原为已取消——因此该班期现在已订房回到 0/8、展开区显示「本期暂无子订单」是**正确**的;复现本缺陷请换任一有活跃子订单的团期(见复现步骤)。 + +--- + +## 一、背景 + +### 复现步骤 + +页面:管理后台 `192.168.100.219:9527/order-v2/batch`(hl-ui 团期看板,`src/views/order-v2/batch/index.vue`)。 + +1. 刷新页面(确保本会话没进过任何团期详情页) +2. 产品页签选任一**行头 `orderCount>0`** 的团期(2026-09-06 18:55 测试库可用:「测试小蒙马-多档-固定金额」的 12-20 出团「#7158验收班期」、12-27 出团「#7178验收班期」,各 1 个活跃子订单;wx 截图用的「冻干粉发短信给」10-01「没,那你」行当时也是 1 单,但那单已于 18:51 复原为已取消,现在该行是真的没有子订单) +3. 点击行左侧展开箭头 +4. **结果**:展开区显示「本期暂无子订单。」,无加载态(而 `GET /v3/admin/order/group-batch/{该行 groupBatchId}/orders` 返回 ≥1 条) +5. 对照:先点「进入团期」进详情页再返回看板展开同一行 → 显示子订单(这是 bug 的偶然绕过路径,不是修复) + +### 调用链 + +1. `PeriodRow.vue:240-245` `onToggle()` → `store.fetchBatchOrders(groupBatchId)` +2. `src/stores/orderV2Batch.js:147-166` `fetchBatchOrders` → `src/api/orderV2GroupBatch.js` `getGroupBatchOrders(id, {includeTravelers: true, includeNeeds: true, includeCancelled: false})` → `GET /v3/admin/order/group-batch/{groupBatchId}/orders` +3. hl-gateway 路由 `/v3/admin/**` → `lb://hl-order-service-v3` +4. hl-order-service-v3 `GroupBatchQueryController.listSubOrders`(`order/groupbatch/controller/admin/GroupBatchQueryController.java:96-`)→ `GroupBatchQueryService.listSubOrders`(`:253-`,缺省剔除 `CANCELLED`)→ 返回 1 条 +5. store 把结果写进 `batchOrders`(`:157`),**不写 `currentGroupBatchId`** +6. `PeriodRow.vue:233-235` `orders = currentGroupBatchId === groupBatchId ? batchOrders : []` → `[]` +7. `SubOrderTable.vue:4-7` 空态 + +### 地面真相(测试服 dev-v3 e9a8dd27,2026-09-06 网关实测) + +| 属性 | 值 | +|------|-----| +| 产品 | 冻干粉发短信给 `productId=2044306857534636034`(GROUP) | +| 班期 | product 侧 `productBatchId=2052935476557328386`(2026-10-01 出团、10-03 返团) | +| 团期主订单 | `groupBatchId=2096412454643802114`,`batchStatus=RESOURCE_PREPARING`,`maxRooms=8`,`enrolledRooms=1`,`enrolledPeople=2`,`orderCount=1` | +| 活跃子订单 | `orderId=2096412454488612866` `orderNo=HL20260906093733163`:`orderStatus=CUSTOMIZING`,`payStatus=DEPOSIT_PAID`,`paidAmount=5850.00`,1 成人 1 儿童,`order_main.room_count=1` | +| 同班期其余 13 单 | 全部 `CANCELLED`(`includeCancelled=true` 时返回 14 条) | +| 备注 | 以上是 wx 截图时段(2026-09-06 17:20 前后网关实测)的状态。该单 09:37 建、01:37(UTC 09-05 17:37)已取消,14 时许被团期房务会话为 #7149 实测用 SQL 临时改成 CUSTOMIZING / DEPOSIT_PAID / 5850 并改写房务需求(`roomCount=2` KING,`specialNeeds` 含「#7149 网关实测」),**18:51 已复原为 CANCELLED / UNPAID / 0.00**;复原后该班期 `enrolledRooms=0`、无活跃子订单。它与产品侧「线下占位房数=0」无关 | + +--- + +## 二、变更接口清单 + +| # | 接口 | 方法 | 网关路径 | 前端函数 | 变更 | 说明 | +|---|------|------|---------|---------|------|------| +| 1 | 团期子订单列表 GB-ADM-003 | GET | `/v3/admin/order/group-batch/{groupBatchId}/orders` | `getGroupBatchOrders()` | 复用不改 | 后端已实测返回 1 条,前端未渲染 | + +--- + +## 三、接口详情 + +### 1. 团期子订单列表 `GET /v3/admin/order/group-batch/{groupBatchId}/orders` + +**VO**: 无请求 VO(路径参数 + 三个可选 query)→ `Result>` + +#### 使用场景 + +看板行展开(`PeriodRow.onToggle`)与团期详情名单页拉该团期的子订单摘要;缺省只返活跃集(`orderStatus != CANCELLED`)。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| groupBatchId | path | Long(JSON 字符串) | 是 | 团期主订单 ID | 不是 product 侧 `productBatchId` | +| includeTravelers | query | Boolean | 否 | 缺省 false | true 时附 `travelers[]`(证件号一律不返回) | +| includeNeeds | query | Boolean | 否 | 缺省 false | true 时附 `roomCount / roomType / specialNeeds` | +| includeCancelled | query | Boolean | 否 | 缺省 false | true 时含已取消子订单 | + +#### 出参 `Result>` + +| 字段 | 类型 | 说明 | +|------|------|------| +| data[].orderId | String(Long) | 子订单 ID | +| data[].orderNo | String | 订单编号 | +| data[].customerName | String | 客户姓名 | +| data[].contactPhone | String | 联系人手机号(脱敏,前 3 后 4) | +| data[].adultCount / childCount / youngChildCount / babyCount | Integer | 成人 / 儿童 / 幼童 / 婴儿数 | +| data[].participantCount | Integer | 出行人总数(四项之和) | +| data[].orderStatus | String | 订单状态码:`PENDING_PAY / CUSTOMIZING / PENDING_DEPARTURE / TRAVELLING / COMPLETED / CANCELLED` | +| data[].orderStatusName | String | 订单状态中文名 | +| data[].payStatus | String | `UNPAID / DEPOSIT_PAID / FULLY_PAID` | +| data[].paidAmount | String(BigDecimal) | 已支付金额(订金 + 尾款) | +| data[].totalPrice | String(BigDecimal) | 本户应收 = orderAmount + 增项 − 优惠(下限 0);取消单返 0 | +| data[].balanceAmount | String(BigDecimal) | 待支付尾款 = 应收 − 已退 − 已付(≥0) | +| data[].estimatedCost | String(BigDecimal) | 下单时点预估成本快照,可为 null | +| data[].contractStatus | String | `GENERATING / SIGNED / VOIDED / RESIGNING / FAILED`;无合同 null | +| data[].insuranceStatus | String | `INSURING / INSURED / CANCELLED / FAILED`;无保险 null | +| data[].hotelRequirementStatus | String | 房需求提报状态 `PENDING / SUBMITTED / REJECTED`(实测也会透出需求状态机原值如 `PENDING_REVIEW`) | +| data[].vehicleRequirementStatus | String | 车需求提报状态 `PENDING / SUBMITTED / REJECTED` | +| data[].roomCount | Integer | 房数(includeNeeds=true;来源 `order_hotel_requirement.days`,缺省 ceil(人数/2))——**与 `order_main.room_count` 是两个字段**,看板「已订房」用的是后者 | +| data[].roomType | String | 房型文本(includeNeeds=true) | +| data[].specialNeeds | String | 特殊需求(includeNeeds=true;缺需求行回落 customer_remark) | +| data[].tierCode | String | 档位码,如 `1A1C` | +| data[].tierName | String | 档位名,如 `1成人1儿童` | +| data[].travelerInfoComplete | Boolean | 出行人资料是否齐全 | +| data[].travelers[] | Array | includeTravelers=true 时返回:`name / type(ADULT/CHILD/YOUNG_CHILD/BABY) / age / birthdayInTrip` | +| data[].consultantName | String | 定制师姓名(创单时固化) | + +#### 请求示例 + +```http +GET /v3/admin/order/group-batch/2096412454643802114/orders?includeTravelers=true&includeNeeds=true HTTP/1.1 +Host: api.test.1814.love:9443 +Authorization: Bearer +``` + +#### 响应示例 + +实测响应(2026-09-06,`travelers[]` 略): + +```json +{ + "code": 200, + "message": "成功", + "data": [ + { + "orderId": "2096412454488612866", + "orderNo": "HL20260906093733163", + "customerName": "测试团期指引", + "adultCount": 1, + "childCount": 1, + "youngChildCount": 0, + "babyCount": 0, + "participantCount": 2, + "orderStatus": "CUSTOMIZING", + "orderStatusName": "定制中", + "payStatus": "DEPOSIT_PAID", + "paidAmount": "5850.00", + "totalPrice": "5850.00", + "balanceAmount": "0.00", + "estimatedCost": null, + "contractStatus": null, + "insuranceStatus": null, + "hotelRequirementStatus": "PENDING_REVIEW", + "vehicleRequirementStatus": "PENDING", + "roomCount": 2, + "roomType": "KING", + "specialNeeds": "#7149 网关实测 AC-1 招募中", + "tierCode": "1A1C", + "tierName": "1成人1儿童", + "travelerInfoComplete": false, + "consultantName": "admin" + } + ], + "success": true +} +``` + +#### 空数据 / 降级响应 + +该团期没有活跃子订单时 `data` 为空数组(不是 null);前端只有在 `code=200 && data.length===0` 时才应显示「本期暂无子订单」,请求失败或异常码一律显示错误态。 + +```json +{ + "code": 200, + "message": "成功", + "data": [], + "success": true +} +``` + +#### 错误响应 + +```json +{ + "code": 589500, + "message": "团期不存在", + "data": null, + "success": false +} +``` + +其他:`589507` 无操作权限(非团期管理员 / 非本定制师名下)。HTTP 始终 200,按 `code` 判断。 + +#### 业务边界 + +- 缺省剔除 `CANCELLED`;`includeCancelled=true` 才含已取消单 +- 路径参数是 order 侧 `groupBatchId`,看板行 VO 里的 `groupBatchId` 字段直接可用;不要传 `productBatchId` +- `roomCount`(房务需求)与看板「已订房」(`order_main.room_count` 计数器,1 单 = 1 房)口径不同,不要互相校验 + +--- + +## 四、前端修复要点与自测清单 + +### 修复要点 + +1. **首选(方案 B)按 `groupBatchId` 键缓存**:`orderV2Batch.js` 把 `batchOrders`(单值数组)改成按 ID 的 map(如 `ordersByBatch = ref({})`),`fetchBatchOrders` 写 `ordersByBatch.value[id] = list`;`PeriodRow.vue:233-238` 的 `orders / ordersLoading` 直接读 `store.ordersByBatch[groupBatchId.value]`,去掉对 `currentGroupBatchId` 的依赖(该字段语义上只服务详情页)。多行同时展开互不覆盖;`PeriodRow.vue:232` 原注释「按 groupBatchId 缓存」即此设计。保留旧的 `batchOrders` 导出(`:202` 一带)直到 grep 确认详情页 / `ChipDetailModal.vue` 没有直接读它。 +2. **治标(方案 A)**:只在 `fetchBatchOrders` 请求前写 `currentGroupBatchId.value = id`。一行改动,但 `currentGroupBatchId` 是单值:keep-alive(`index.vue:170-172`)下先展开 X 行、进 Y 详情再返回,X 行会退回空态;多行同时展开互相覆盖。不推荐单独采用。 +3. **错误态**:`PeriodRow.vue` 目前不渲染 `store.ordersError`(`orderV2Batch.js:159-162` 失败时置 `batchOrders=[]`),接口失败会伪装成「暂无子订单」;展开区应区分「加载中 / 加载失败(可重试)/ 暂无子订单」,且行上 `orderCount>0`(GB-ADM-001 有该字段)而列表为空时显示「加载失败」而非「暂无」。 +4. **让橙色芯片可自证**:`SubOrderTable.vue:10-19` 表头只有联系人 / 人数 / 房型·间数 / 电话 / 应收 / 毛利 / 资料,GB-ADM-003 已返回的 `hotelRequirementStatus / vehicleRequirementStatus` 没有展示;建议加「房需求 / 车需求」状态列,或在芯片上加 tooltip 文案「进行中:N 户待审核」(数据来自 GB-ADM-090~095 逐户明细),否则运营看到橙色仍不知道它对应哪户的什么状态。芯片图例建议:灰=未开始、橙=进行中、绿=已完成、红=异常。 +5. **顺手核对**:`ChipDetailModal.vue`(`index.vue:174` 引入)是否也依赖 `currentGroupBatchId`;详情页离开时是否需要清空 `currentGroupBatchId`。 + +### 自测清单 + +1. 刷新看板页,直接展开任一 `orderCount>0` 的行(如「测试小蒙马-多档-固定金额 · #7158验收班期」)→ 出现与 GB-ADM-003 返回条数一致的子订单 +2. 先展开 A 行再展开 B 行 → 各自显示各自的子订单,收起再展开不串行 +3. 展开瞬间出现加载态 +4. 断网或把接口改成 500 → 展开区显示「加载失败」而非「本期暂无子订单」 +5. 进详情页再返回看板展开 → 仍正确(keep-alive 场景) +6. 真正没有活跃子订单的团期(如把该单取消后)→ 显示「本期暂无子订单」 + +--- + +## 五、验证证据 + +### 网关实测(测试服 2026-09-06 17:20 前后,登录后切 ADMIN 角色;该单 18:51 已复原为已取消,下表是截图时段的证据) + +| 请求 | 结果 | +|------|------| +| `GET /v3/admin/order/group-batch/2096412454643802114/orders` | 200 / code 200,1 条(HL20260906093733163) | +| `GET .../orders?includeTravelers=true&includeNeeds=true`(前端缺省参数) | 200 / code 200,1 条,含 roomCount=2 / roomType=KING | +| `GET .../orders?includeCancelled=true` | 200 / code 200,14 条(1 活跃 + 13 CANCELLED) | +| `GET /v3/admin/order/group-batch/2096412454643802114` | enrolledRooms=1、enrolledPeople=2、remainRooms=7、maxRooms=8 | +| `GET /v3/admin/order/group-batch/board?productId=2044306857534636034` 该行 | enrolledRooms=1、orderCount=1、groupBatchId=2096412454643802114 | + +### DB 落库(只读) + +`hl_order_service_v3.order_main` 中 `product_batch_id=2052935476557328386` 共 14 行:13 行 `order_status=CANCELLED`,1 行 `CUSTOMIZING`(`pay_status=DEPOSIT_PAID`、`paid_amount=5850.00`、`room_count=1`、`group_batch_id=2096412454643802114`);`order_group_batch` 该团期 `enrolled_rooms=1`、`enrolled_people=2`。 + +--- + +## 六、影响与不影响范围 + +- **影响**:hl-ui `src/stores/orderV2Batch.js`、`src/views/order-v2/batch/components/PeriodRow.vue`、`SubOrderTable.vue`(可选加列);团期详情页若直接读 `store.batchOrders` 需同步改用新缓存 +- **不影响**:后端 GB-ADM-001 / GB-ADM-003 契约与实现;网关;小程序;订单列表页 + +--- + +## 七、关联 + +- 后端工单 #7204:导/摄芯片零指派却 DOING(橙)的聚合口径修正(wx 2026-09-06 拍板:零指派灰 / 部分指派橙 / 全部指派绿)——与本缺陷无依赖,但同一现场 +- 后端团期看板三单:#7188(「第N期」序号透出)、#7189(看板以产品全班期为基底 + 班期范围筛选)、#7190(「出行完毕」状态)——均不改 GB-ADM-003 +- 同日前端缺陷:`06_frontend_团期产品新建订单向导创单漏传productBatchId-前端缺陷-管理后台.md`(已由 mmg 修复 03a985b6)