文件
hl-api-changelog/changelogs-v2/2026-09/23_frontend_查看需求Tab操作重排与逐户需求详情弹窗-前端优化-管理后台.md
T

11 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 frontend 查看需求 Tab:整团级操作收进顶部操作条 + 子订单行新增「需求详情」弹窗 admin wx(GIT) 前端优化 not_required not_required verified mmg f713b1c65c061a18754c5bc759d1c50c3dd5eb3e v2.1 2026-09-23 2026-09-23 wx 对「查看需求」Tab 提三点:①「新增正式行程用车需求」按钮应该在顶部操作条这里;②该按钮独立成一张卡片操作不方便;③要一个按钮点开弹窗看用房/用车需求详情;并总结「这个 Tab 操作整体不方便,整理优化下」。本条是给 mmg 的 UI 重排规格。后端零改动:四项改动用到的端点与字段全部已在 dev-v3 上线并被本 Tab 现有代码调用,无新增端点、无出入参变化、无网关路由变化、无 DDL。字段清单逐项对 origin/dev-v3 的 VO 源码核过(GroupHotelHouseholdsRespVO / GroupVehicleHouseholdsRespVO / GroupBatchRoomPlanDetailRespVO)。 | 2026-09-23 mmg 交付:五区块卡头全撤,顶部操作条(刷新一个顶六个/新增编辑正式需求平铺,整团级缺失时 primary ghost/撤回免车受控重开收更多下拉,判定经 ops-state 上抛);预检条目可点(户级滚动定位名单行+高亮,车侧整团级直开编辑弹窗);名单表加需求详情弹窗(两 tab 只读复用 households 快照零新请求,分房段按需拉 room-plans 过滤本户);五卡自绘折叠分区默认只展开两汇总(n-collapse 懒挂载不满足 eager fetch);scroll-x 钉死列宽合计 1568;顺带修 A 段遗留 doConfirm stale refs ReferenceError;7 spec 99 例全绿 2026-09-23 dev-v3

查看需求 Tab:操作重排 + 逐户需求详情弹窗

服务: hl-order-service-v3(后端零改动) 页面: 管理后台 → 团期订单 → 团期详情 → 「查看需求」Tab 文件: src/views/order-v2/batch/detail/components/RequirementTab.vue 及其子组件 日期: 2026-09-23 影响范围: 仅前台渲染与交互编排;无端点、无出入参、无网关路由、无 DDL 变化


一、现状与问题(对 origin/v2.1 = 61a549bd 实读)

这个 Tab 现在是「一条操作条 + 一张子订单表 + 五张平铺卡片」的结构:

位置 承载的整团级操作
RequirementTab.vue:29-51 .requirement-tab__ops 刷新预检 / 打回选中户(N) / 整团确认需求
GroupVehicleRequirementSection.vue 的 #header-extra 新增(编辑)正式行程用车需求 / 整份撤回·撤回免车 / 声明整团免车 / 受控重开配车窗口
五张卡片各自的卡头 各自一个「刷新」

三个具体问题:

  1. 整团级操作散在三处,其中一处还在第四屏。
  2. 阻断项和解除阻断的按钮离得最远。顶部预检提示条会打出「团期 xxx 尚未形成正式用车需求」,而消除它的那个按钮在下方「正式用车需求」卡片的卡头里——看见问题的地方和能动手的地方隔了四张卡片。
  3. 一户的需求被劈在两张卡片里。「用房 · 子订单订房记录」和「用车 · 子订单需求记录」各自按户列一遍,要看清某一户到底报了什么,得在两张卡片之间上下翻。子订单表里的那一行才是「这一户」,但那行点不开。

二、要做的四件事

1. 整团级操作全部收进顶部操作条

.requirement-tab__ops 改为(从左到右):

[刷新] [打回选中户(N)] [新增正式行程用车需求] [更多 ▾] ………… [整团确认需求]
  • 新增正式行程用车需求 平铺(wx 明确指定放这里)。文案沿用现有逻辑:有需求时显示「编辑正式需求」,无需求时显示「新增正式行程用车需求」。
  • 更多 ▾ 收三个低频且互斥的:整份撤回 / 撤回免车(二者 v-if / v-else-if 互斥)、声明整团免车、受控重开配车窗口。收进下拉的理由是这四个按钮的出现与否随状态变化,平铺会让操作条宽度随状态跳动;下拉让操作条形状恒定。
  • 按钮层级:整团确认需求 保持 type="primary",是这个页面的终点。新增正式行程用车需求 用默认样式,但当预检提示条里出现「尚未形成正式用车需求」这一条时,把它切成 type="primary" ghost —— 此刻它才是「现在该点的那个」。
  • 卡片保留,只清空卡头。GroupVehicleRequirementSection 这张卡片继续展示正式用车需求的内容(车队、座位、状态),只把 #header-extra 里那四个按钮搬走。

实现上父子已经通着:RequirementTab.vue:155-168 已持有 ref="vehicleReqRef",把 canEdit / isWaived / canWithdraw / canReopen 四个 computed 与四个动作的入口方法 defineExpose 出来即可,不需要新增 props 或提升状态。

2. 预检提示条的每一条做成可点

这是「操作不方便」最直接的来源,优先级最高。

提示条里的条目 点击后
HL2026xxxx 定制师张三 — 未提交房需求 滚动到子订单表对应行并高亮(orderId 已在 missing 项里)
团期 21008xxxx 尚未形成正式用车需求 直接打开 GroupVehicleRequirementEditModal,即操作条上那个「新增正式行程用车需求」

把「看见问题」和「动手解决」接在一起,用户就不必自己在页面里找对应入口。

3. 子订单表操作列新增「需求详情」→ 弹窗

在现有「进入」旁边加一个「需求详情」。点开一个 n-modal(或右侧 n-drawer),两个 Tab:用房 / 用车,只读。

关键点:这个弹窗的价值是「按户聚合」,不是「多给字段」。 两张列表卡片其实已经把下面这些字段渲染出来了(RoomHouseholdsSection.vue / VehicleHouseholdsSection.vue 实读确认),弹窗做的是把同一户散在两处的内容收到一屏。

用房 Tab

数据来自本 Tab 已加载的 GET /v3/admin/order/group-batch/{groupBatchId}/requirement/hotel-households,按 orderId 过滤,不发新请求。

  • 头部:customerName / teamNo / orderNo / participantCount / consultantName
  • 状态:statusName,外加 countedInSummary 的显式标识(计入汇总 / 未计入汇总)
  • 配房需求:remark
  • 特殊标签:specialTags[]
  • 打回留痕:returnRemark +returnedAt(有值才显示)
  • 逐晚表,来自 days[]:
列 取值 既有约定(沿用,勿改)
第 N 天 dayNumber
入住日 stayDate
自行预订 customerSelfBooked 为 true 时该晚不该被当成缺口
酒店 hotels[].hotelName 为 null 显「未知酒店」,行不隐藏(间数仍有效)
地点 hotels[].district 用 district 不用 city,契约实测 city 几乎恒为同一地级市,区分不出地点
房型 rooms[].roomTypeName 回落链:roomTypeName → roomCategoryName → roomCategory → 「未知房型」
间数 rooms[].roomCount

用车 Tab

数据来自 GET .../requirement/vehicle-households,同样按 orderId 过滤复用已加载数据。逐条渲染 requirements[]:

  • kindName(行程用车 / 接送机)+ statusName
  • serviceDates[]
  • headcount / totalSeatCount(含驾驶位)/ remainingPassengerSeats(负数标「缺口」,沿用现有红色样式)
  • fleet[] 车队明细
  • pickupRequired / dropoffRequired —— 仅 TRANSFER 有意义,TRAVEL 恒为 null,TRAVEL 下整行不渲染
  • specialTags[] / remark
  • returnRemark + returnedAt(有值才显示)

可选第二段:这一户「已经配成什么样」

如果要让弹窗从「他报了什么」延伸到「我们给他配了什么」,GET /v3/admin/order/group-batch/{groupBatchId}/room-plans(H12 整团配房明细,只读、不含金额)已经有分房层,按 orderId 过滤即可:

days[].plans[].allocations[]  →  orderId / orderNo / roomCount / roomGroupNo(家庭分组 F{N}) / 入住人数 / allocSource(AUTO|MANUAL)

外层还带 hotelName / roomTypeName / planStatus(PENDING|CONFIRMED)/ replaceReason。这是弹窗里唯一需要多发一个请求的部分,按需加载即可。

4. 刷新收敛成一个,明细卡片默认折叠

  • 顶部操作条那个 刷新预检 改名 刷新,一次刷预检 + 五个区块;撤掉五张卡片各自的刷新按钮。用户心智里这个页面只有一个「刷新」。
  • 五张卡片(用房·汇总 / 用房·子订单订房记录 / 用车·汇总 / 正式用车需求 / 用车·子订单需求记录)改 n-collapse,默认只展开两张「汇总」。明细按需展开,首屏留给操作条、预检提示条和子订单表。

三、数据来源汇总(零新接口)

用途 端点 本 Tab 现状
子订单表 GET /v3/admin/order/group-batch/{id}/orders 已调
预检 GET .../requirement/confirm-check 已调
用房逐户(弹窗用房 Tab) GET .../requirement/hotel-households 已调,字段够
用车逐户(弹窗用车 Tab) GET .../requirement/vehicle-households 已调,字段够
整团确认 / 打回 POST .../requirement/confirm、.../requirement/reject 已调
正式用车需求 读/存/撤回/免车/重开 GET·PUT .../vehicle-requirement、.../withdraw、.../waive、.../reopen 已调
弹窗「已配成什么样」(可选段) GET .../room-plans 本 Tab 未调,端点已上线(H12)

四、业务边界

  • 本条只覆盖「查看需求」Tab。「配房明细」Tab(RoomPlansTab.vue)的结构不在本次重排范围内。
  • 需求侧的房间粒度只到「房型 × 间数」。GroupHotelHouseholdsRespVO 的最细一层是 HouseholdRoomItem{roomTypeId, roomTypeName, roomCategory, roomCategoryName, roomCount},弹窗的用房 Tab 给不出「哪一间」。
  • 「谁住哪一间」这层数据全系统没有。配房侧能到「哪一户的哪个家庭分组 F{N}、几个人、住哪家酒店哪个房型的几间」(上面第二段那个可选来源),但出行人姓名与房间的绑定不存在——GET .../room-plans 的接口说明里明写了不返回出行人姓名与联系方式。要做到姓名级,是一次真正的新增能力,不是取数问题。
  • 用车侧被打回的户可能在弹窗里无行可渲染。VehicleHouseholdsSection.vue:210 的注释写着「打回行失活不在列表(与用房侧『列出打回户灰显』刻意不同)」。【需确认】这一条我只读到注释、没有实测接口返回,实现时以 vehicle-households 的实际返回为准;若确实不返,弹窗用车 Tab 对被打回的户要给一个明确空态文案,不要显示成「这户没报用车需求」。
  • 受控重开配车窗口 进下拉后仍受既有约束:DISPATCHED 定稿后要重配须先开窗拿令牌,PENDING_RECONFIRM 下续开/取当前令牌同走这个入口(后端幂等返回既有令牌,809203 兜他人窗口)。挪位置不改变这套行为。
  • 整团免车 是合法逃生口不是异常态。顶部那个 本团整团免车 的 n-tag(checkResult?.vehicleWaived === true)要保留在操作条附近,免车时车侧校验整体跳过,别让它看起来像出错了。