docs(changelog): 查看需求 Tab 操作重排 + 子订单行需求详情弹窗规格(前端优化,后端零改动)
changelog-filename-gate / validate (push) Failing after 2s
changelog-filename-gate / validate (push) Failing after 2s
wx 2026-09-23 对团期详情「查看需求」Tab 提三点:新增正式行程用车需求按钮 应在顶部操作条、该按钮独立成卡片操作不方便、要一个按钮点开看用房/用车 需求详情;并总结「这个 Tab 操作整体不方便,整理优化下」。 本条给 mmg 四项重排规格:整团级操作收进 .requirement-tab__ops、预检提示条 每条可点直达解除入口、子订单表操作列加「需求详情」弹窗(按户聚合房+车)、 刷新收敛成一个且明细卡片默认折叠。 字段清单逐项对 origin/dev-v3 源码核过(GroupHotelHouseholdsRespVO / GroupVehicleHouseholdsRespVO / GroupBatchRoomPlanDetailRespVO),无新增端点、 无出入参变化、无网关路由变化、无 DDL。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
这个提交包含在:
@@ -0,0 +1,154 @@
|
||||
---
|
||||
schema: hl-changelog/v2
|
||||
ticket: "frontend"
|
||||
title: "查看需求 Tab:整团级操作收进顶部操作条 + 子订单行新增「需求详情」弹窗"
|
||||
consumer: admin
|
||||
author: "wx(GIT)"
|
||||
change_type: "前端优化"
|
||||
backend_status: "not_required"
|
||||
gateway_status: "not_required"
|
||||
frontend_status: "pending"
|
||||
frontend_owner: "mmg"
|
||||
frontend_ref: ""
|
||||
target_release: "v2.1"
|
||||
verified_at: ""
|
||||
status_note: "2026-09-23 wx 对「查看需求」Tab 提三点:①「新增正式行程用车需求」按钮应该在顶部操作条这里;②该按钮独立成一张卡片操作不方便;③要一个按钮点开弹窗看用房/用车需求详情;并总结「这个 Tab 操作整体不方便,整理优化下」。本条是给 mmg 的 UI 重排规格。后端零改动:四项改动用到的端点与字段全部已在 dev-v3 上线并被本 Tab 现有代码调用,无新增端点、无出入参变化、无网关路由变化、无 DDL。字段清单逐项对 origin/dev-v3 的 VO 源码核过(GroupHotelHouseholdsRespVO / GroupVehicleHouseholdsRespVO / GroupBatchRoomPlanDetailRespVO)。"
|
||||
updated_at: "2026-09-23"
|
||||
base: 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`)要保留在操作条附近,免车时车侧校验整体跳过,别让它看起来像出错了。
|
||||
在新工单中引用
屏蔽一个用户