From c8106e3e6b4788a361c93c7910a7459ed978341e Mon Sep 17 00:00:00 2001 From: API Changelog Bot Date: Fri, 17 Apr 2026 15:16:55 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=9A=E7=9F=A5=E5=89=8D=E7=AB=AF:=20Step2?= =?UTF-8?q?=20=E4=BD=8F=E5=AE=BF=E6=A1=A3=E4=BD=8D=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E9=94=99=E4=B9=B1=20bug=20=E4=BF=AE=E5=A4=8D=E6=8C=87=E5=8D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...26-04-17_frontend-bug_step2-hotel-tiers.md | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 changelogs/2026-04/2026-04-17_frontend-bug_step2-hotel-tiers.md diff --git a/changelogs/2026-04/2026-04-17_frontend-bug_step2-hotel-tiers.md b/changelogs/2026-04/2026-04-17_frontend-bug_step2-hotel-tiers.md new file mode 100644 index 0000000..ed6b98c --- /dev/null +++ b/changelogs/2026-04/2026-04-17_frontend-bug_step2-hotel-tiers.md @@ -0,0 +1,155 @@ +# 前端 Bug 通知 — Step2 行程编排「住宿安排」档位显示错乱 + +- **日期**: 2026-04-17 +- **类型**: 前端 Bug 修复指南(**不涉及后端代码改动,后端无需重启**) +- **涉及端**: 管理后台 hl-ui(产品编辑页 Step2) +- **后端服务**: hl-product-service-v2(**仅作接口说明,代码不变**) + +--- + +## 一、问题描述 + +在产品编辑页 Step2「行程编排」→「住宿安排」tab 中: + +- **预期**:显示 5 个档位 tab,名称依次为 `经济 / 舒适 / 轻奢 / 高端 / 豪华`(与 Step1 基础信息配置的 5 档一致) +- **实际**:只显示 **2 个档位 tab**,且名称为 `经奢 / 高端` —— 其中 **"经奢" 这个词在后端任何地方都不存在** + +**复现路径**: +- 环境:测试服 `192.168.100.236` +- 产品 ID:`2045018534152478721` +- 页面:产品编辑 → Step2 行程编排 → 住宿安排 + +--- + +## 二、根因分析(后端已核实) + +### 1. 后端返回的数据是完整正确的 + +调用 `GET /admin/product/item/{id}` 返回 `data.tiers` **完整包含 5 档**,每档都有 `tierSeq` / `tierName` / `tierDescription` 字段,数据无问题。 + +### 2. "经奢" 不是后端字典 + +在整个后端项目(包括 schema.sql、字典表、常量、VO、代码注释)`grep "经奢"` **零匹配**。该字符串**必然是前端代码内写死的**。 + +### 3. itinerary 内 hotels 只有部分档位是业务正常 + +后端 `data.itinerary[*].hotels` 里 `tierSeq` 只出现 `1` 和 `2`,是**用户在 Step2 只给档位 1、2 录入了酒店**的真实业务状态(业务允许不录满全部档位,不是 bug)。 + +前端**不应该**从 `itinerary[*].hotels` 反推档位 tab 列表 —— 这会导致:未录入酒店的档位 tab 直接消失;而一旦索引/字段错位,还会出现 "经奢" 这种幻觉档位名。 + +--- + +## 三、后端接口数据结构(示例) + +接口:`GET /admin/product/item/{id}` + +```json +{ + "code": 0, + "data": { + "id": 2045018534152478721, + "name": "示例产品", + + "tiers": [ + {"tierSeq": 1, "tierName": "经济", "tierDescription": "快捷酒店/双床标间"}, + {"tierSeq": 2, "tierName": "舒适", "tierDescription": "四星酒店/河景房"}, + {"tierSeq": 3, "tierName": "轻奢", "tierDescription": "五星酒店/高级套房"}, + {"tierSeq": 4, "tierName": "高端", "tierDescription": "精品度假酒店/江景套房"}, + {"tierSeq": 5, "tierName": "豪华", "tierDescription": "奢华度假庄园/别墅"} + ], + + "itinerary": [ + { + "dayNumber": 1, + "hotels": [ + {"tierSeq": 1, "hotelId": 111, "hotelName": "某快捷酒店"}, + {"tierSeq": 2, "hotelId": 222, "hotelName": "某四星酒店"} + ] + }, + { + "dayNumber": 2, + "hotels": [] + } + ] + } +} +``` + +字段说明: + +| 字段 | 含义 | 说明 | +|------|------|------| +| `data.tiers` | **档位定义列表**(权威来源) | Step1 基础信息配置,**档位 tab 列表必须用它** | +| `data.tiers[*].tierSeq` | 档位序号 | 1/2/3/4/5 | +| `data.tiers[*].tierName` | 档位中文名 | 经济/舒适/轻奢/高端/豪华 | +| `data.tiers[*].tierDescription` | 档位描述 | 档位下方的说明文字 | +| `data.itinerary[*].hotels` | 某一天的酒店安排 | 按档位可能部分录入,**允许为空数组** | +| `data.itinerary[*].hotels[*].tierSeq` | 该酒店归属的档位 | 用于过滤到对应档位 tab 下展示 | + +--- + +## 四、前端正确渲染逻辑 + +### 1. 档位 tab 列表 + +**严格使用 `data.tiers`**: + +```js +// 正确 +const tierTabs = data.tiers; // 5 档齐全,顺序按 tierSeq + +// 错误 —— 会导致未录酒店的档位消失 +const tierTabs = uniqBy(flatMap(data.itinerary, d => d.hotels), 'tierSeq'); +``` + +### 2. 档位名称 + +**一律用 `tier.tierName` 字段**,禁止前端写死档位名数组: + +```js +// 正确 + + +// 错误 —— 极易出现 "经奢" 这种幻觉 +const TIER_NAMES = ['经济', '经奢', '轻奢', '高端', '豪华']; // 第 2 项就是错的 + +``` + +### 3. 每档下的酒店 + +按当前选中档位的 `tierSeq` 过滤: + +```js +const hotelsOfCurrentTier = day.hotels.filter(h => h.tierSeq === currentTierSeq); +``` + +### 4. 空档位保留 tab,内容区显示空状态 + +即使某档位下 `hotels` 全部为空,**tab 仍然要显示**,内容区渲染空状态提示(如"该档位暂未配置酒店,点击添加"),**禁止隐藏 tab**。 + +--- + +## 五、排查步骤建议 + +1. **全前端代码 grep `经奢`** → 应能定位到写死的字符串来源,删除或修正为从 `tiers` 取值 +2. **定位 Step2 住宿 tab 的数据源**:检查是否从 `itinerary[*].hotels` 聚合 `tierSeq` 推导档位 —— 如是,改为从 `data.tiers` 取 +3. **检查档位名枚举数组**:搜 `['经济'` / `['经济','` 等关键词,排查是否有写死的档位名数组写反 +4. **检查字典调用**:Step2 档位名是否误用了其他字典(如把酒店星级字典当档位用) + +--- + +## 六、验收标准(前端修完后自测) + +- [ ] 产品 `2045018534152478721` Step2「住宿安排」tab **严格显示 5 个档位**,名称依次等于 Step1:`经济 / 舒适 / 轻奢 / 高端 / 豪华` +- [ ] 档位 3(轻奢)、4(高端)、5(豪华)下未录酒店时,**tab 仍然显示**,内容区呈现空状态而非 tab 消失 +- [ ] 档位 1(经济)、2(舒适)下能正确看到已录入的酒店 +- [ ] **全前端代码 grep 不到「经奢」这个字符串** +- [ ] 其他已发布产品随机抽查 2 个,Step2 住宿 tab 档位数与 Step1 配置完全一致 + +--- + +## 七、影响范围 + +- **后端**:无变更,不需要重启服务 +- **前端**:仅 Step2「住宿安排」tab 的档位渲染逻辑修复 +- **数据**:无需订正,线上数据是正确的,仅前端展示错误