17 KiB
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 | frontend | 团期看板展开行子订单列表恒空 | admin | wx(GIT) | 前端缺陷 | not_required | not_required | verified | mmg | 7d652bdc | 2026-09-06 | 后端 GB-ADM-003 已在测试服 dev-v3 网关实测返回 1 条活跃子订单;纯前端门控 bug:store.currentGroupBatchId 只在详情页 fetchDetail 赋值,看板展开走的 fetchBatchOrders 不赋值,PeriodRow 子订单列表恒空。首选按 groupBatchId 键缓存(PeriodRow 原注释的设计),并把 ordersError 显示出来。 | 2026-09-06 | 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)。
- 刷新页面(确保本会话没进过任何团期详情页)
- 产品页签选任一行头
orderCount>0的团期(2026-09-06 18:55 测试库可用:「测试小蒙马-多档-固定金额」的 12-20 出团「#7158验收班期」、12-27 出团「#7178验收班期」,各 1 个活跃子订单;wx 截图用的「冻干粉发短信给」10-01「没,那你」行当时也是 1 单,但那单已于 18:51 复原为已取消,现在该行是真的没有子订单) - 点击行左侧展开箭头
- 结果:展开区显示「本期暂无子订单。」,无加载态(而
GET /v3/admin/order/group-batch/{该行 groupBatchId}/orders返回 ≥1 条) - 对照:先点「进入团期」进详情页再返回看板展开同一行 → 显示子订单(这是 bug 的偶然绕过路径,不是修复)
调用链
PeriodRow.vue:240-245onToggle()→store.fetchBatchOrders(groupBatchId)src/stores/orderV2Batch.js:147-166fetchBatchOrders→src/api/orderV2GroupBatch.jsgetGroupBatchOrders(id, {includeTravelers: true, includeNeeds: true, includeCancelled: false})→GET /v3/admin/order/group-batch/{groupBatchId}/orders- hl-gateway 路由
/v3/admin/**→lb://hl-order-service-v3 - hl-order-service-v3
GroupBatchQueryController.listSubOrders(order/groupbatch/controller/admin/GroupBatchQueryController.java:96-)→GroupBatchQueryService.listSubOrders(:253-,缺省剔除CANCELLED)→ 返回 1 条 - store 把结果写进
batchOrders(:157),不写currentGroupBatchId PeriodRow.vue:233-235orders = currentGroupBatchId === groupBatchId ? batchOrders : []→[]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<List<GroupBatchOrderItemRespVO>>
使用场景
看板行展开(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<List<GroupBatchOrderItemRespVO>>
| 字段 | 类型 | 说明 |
|---|---|---|
| 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 | 定制师姓名(创单时固化) |
请求示例
GET /v3/admin/order/group-batch/2096412454643802114/orders?includeTravelers=true&includeNeeds=true HTTP/1.1
Host: api.test.1814.love:9443
Authorization: Bearer <token>
响应示例
实测响应(2026-09-06,travelers[] 略):
{
"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 时才应显示「本期暂无子订单」,请求失败或异常码一律显示错误态。
{
"code": 200,
"message": "成功",
"data": [],
"success": true
}
错误响应
{
"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 房)口径不同,不要互相校验
四、前端修复要点与自测清单
修复要点
- 首选(方案 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没有直接读它。 - 治标(方案 A):只在
fetchBatchOrders请求前写currentGroupBatchId.value = id。一行改动,但currentGroupBatchId是单值:keep-alive(index.vue:170-172)下先展开 X 行、进 Y 详情再返回,X 行会退回空态;多行同时展开互相覆盖。不推荐单独采用。 - 错误态:
PeriodRow.vue目前不渲染store.ordersError(orderV2Batch.js:159-162失败时置batchOrders=[]),接口失败会伪装成「暂无子订单」;展开区应区分「加载中 / 加载失败(可重试)/ 暂无子订单」,且行上orderCount>0(GB-ADM-001 有该字段)而列表为空时显示「加载失败」而非「暂无」。 - 让橙色芯片可自证:
SubOrderTable.vue:10-19表头只有联系人 / 人数 / 房型·间数 / 电话 / 应收 / 毛利 / 资料,GB-ADM-003 已返回的hotelRequirementStatus / vehicleRequirementStatus没有展示;建议加「房需求 / 车需求」状态列,或在芯片上加 tooltip 文案「进行中:N 户待审核」(数据来自 GB-ADM-090~095 逐户明细),否则运营看到橙色仍不知道它对应哪户的什么状态。芯片图例建议:灰=未开始、橙=进行中、绿=已完成、红=异常。 - 顺手核对:
ChipDetailModal.vue(index.vue:174引入)是否也依赖currentGroupBatchId;详情页离开时是否需要清空currentGroupBatchId。
自测清单
- 刷新看板页,直接展开任一
orderCount>0的行(如「测试小蒙马-多档-固定金额 · #7158验收班期」)→ 出现与 GB-ADM-003 返回条数一致的子订单 - 先展开 A 行再展开 B 行 → 各自显示各自的子订单,收起再展开不串行
- 展开瞬间出现加载态
- 断网或把接口改成 500 → 展开区显示「加载失败」而非「本期暂无子订单」
- 进详情页再返回看板展开 → 仍正确(keep-alive 场景)
- 真正没有活跃子订单的团期(如把该单取消后)→ 显示「本期暂无子订单」
五、验证证据
网关实测(测试服 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)