diff --git a/changelogs-v2/2026-09/23_frontend_查看需求Tab操作重排与逐户需求详情弹窗-前端优化-管理后台.md b/changelogs-v2/2026-09/23_frontend_查看需求Tab操作重排与逐户需求详情弹窗-前端优化-管理后台.md new file mode 100644 index 00000000..2434ba05 --- /dev/null +++ b/changelogs-v2/2026-09/23_frontend_查看需求Tab操作重排与逐户需求详情弹窗-前端优化-管理后台.md @@ -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`)要保留在操作条附近,免车时车侧校验整体跳过,别让它看起来像出错了。