From 1f1c15cedf0baa8176ff45fcdede8898a5db0231 Mon Sep 17 00:00:00 2001 From: API Changelog Bot Date: Mon, 11 May 2026 14:07:16 +0800 Subject: [PATCH] =?UTF-8?q?feat(admin/product-v2):=20=E8=A1=8C=E7=A8=8B?= =?UTF-8?q?=E8=AF=A6=E6=83=85=E6=96=B0=E5=A2=9E=20mileageWarnings=20?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=20+=20POI=20=E9=80=89=E9=94=99=E4=BA=8B?= =?UTF-8?q?=E6=95=85=E5=A4=8D=E7=9B=98=20(PR=20#1938,=20Issue=20#1937)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...dmin_itinerary-mileage-anomaly-warnings.md | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 changelogs/2026-05/11_feat_admin_itinerary-mileage-anomaly-warnings.md diff --git a/changelogs/2026-05/11_feat_admin_itinerary-mileage-anomaly-warnings.md b/changelogs/2026-05/11_feat_admin_itinerary-mileage-anomaly-warnings.md new file mode 100644 index 0000000..9d6a505 --- /dev/null +++ b/changelogs/2026-05/11_feat_admin_itinerary-mileage-anomaly-warnings.md @@ -0,0 +1,149 @@ +# admin/product-v2: 行程编辑详情新增里程异常 warnings 字段 + 建议前端 POI 搜索控件改进 + +> **服务**: hl-product-service-v2 (端口 8083) +> **PR**: #1938 +> **Issue**: #1937 +> **日期**: 2026-05-11 +> **影响范围**: 管理端产品编辑(step2 行程编排)详情响应; POI 搜索控件(可选改进) + +--- + +## ⚠️ 关键变化 + +后端在产品编辑详情响应里**新增了一个 `mileageWarnings: List` 字段**(按天), 用于在运营选错 POI 时弹红旗提示。前端可在编辑页该天显示警告徽章。 + +**同时强烈建议(可选)**:POI 搜索控件 UX 优化, 防止运营选错同名异地 POI。已发生事故见下文背景。 + +--- + +## 一、背景 + +2026-05-11 发现产品《一次走透呼伦贝尔的旷野心脏》DAY 3 `daily_mileage = 475.2 km`, 客户用高德地图手测同样 5 点路线 = **275.0 公里**, 差 **+200 km(+73%)**。 + +### 根因(实证) + +运营在产品 step2 编辑器搜"恩和", 选了高德返回的 POI `poiId=B0LALCK6P1`, 该 POI 名字叫"恩和"但**实际坐标在陈巴尔虎旗宝日希勒镇** `(lat=49.279092, lng=119.616988)`, 跟真正"额尔古纳市恩和俄罗斯民族乡" `(lat≈50.83)` 偏南 **167 km**。后端调高德 API 算驾车里程, 从骑马场(50.83°) → 错位"恩和"(49.28°)单段就多算 200 km。 + +### 平台 F 维度扫描 + +正式服全平台扫描坐标落在 `(lat 49.27-49.30, lng 119.60-119.65)` 范围 → 共 **6 条记录, 涉及 4 个产品**: + +| 产品 | 状态 | 命中 | +|------|------|------| +| 2053003990289129474 一次走透呼伦贝尔的旷野心脏 | PUBLISHED | DAY3 dismissal + DAY4 gather | +| 2052985893312008193 呼伦贝尔5天4晚自由行 | COMPLETED | DAY2 dismissal + DAY3 gather | +| 2052926308213891073 燕6天5晚私人订制 | COMPLETED | DAY3 gather | +| 2052984406884225025 草原慢旅行 | DRAFT | DAY3 dismissal + DAY4 gather | + +已通过 SQL `JSON_SET` 修正全部 6 条 location 到 `(50.828414, 119.912452)`, 修复后 F 扫描 = 0 行。 + +### 数据库 schema 差异 + +- **正式服旧 schema**: `product_itinerary_day.gather_place / dismissal_place` 是 JSON, 含 `location.lat/lng` +- **测试服新 schema**: 同字段已升级为**行政区粒度**(`name / level / adcode / fullPath / levelName`), 不嵌套坐标; 途经点搬到新表 `product_route_point` +- 测试服 F 维度扫描 0 命中, 新 schema 已天然阻断此 bug 模式 + +--- + +## 二、变更接口清单 + +| # | 接口 | 方法 | 路径 | 变更类型 | 说明 | +|---|------|------|------|----------|------| +| 1 | 管理端获取产品详情(含 step2 行程) | GET | `/admin/product/item/{id}` | 响应新增字段 | 每个 `days[]` 元素新增 `mileageWarnings: List`, 默认空数组 | + +--- + +## 三、接口详情 + +### 1. 管理端获取产品详情 `GET /admin/product/item/{id}` + +**VO**: `ProductDetailRespVO.days[] -> ItineraryDayRespVO` + +#### 出参新增字段 + +| 字段 | 类型 | 说明 | 默认 | +|------|------|------|------| +| `days[i].mileageWarnings` | `List` | 该天里程异常 warning 列表, 空数组表示正常。每条 warning 是给运营看的中文短句, 建议在编辑页该天显示红色感叹号 / 黄色徽章, 鼠标悬停展示具体内容 | `[]` | + +#### 三条 warning 规则(后端自动检测) + +| 规则 | 触发条件 | warning 文案样例 | +|------|----------|-----------------| +| 单段直线超长 | 同一天内相邻两节点直线距离 > 100km | `DAY3 第4段 直线距离 173.6km, 跨城市级跳跃, 可能 POI 坐标错位` | +| 驾车/直线比异常 | 某段 driving / linear > 3.5 (正常 1.4~2.5) | `DAY3 第4段 驾车/直线比 4.2, 正常 1.4~2.5, 强烈疑似 POI 错位或绕远` | +| 全天里程过大 | `dailyMileage > 600km` | `DAY3 全天里程 720km 异常大` | + +不阻塞保存, 不持久化, 每次 GET 实时计算。资源服务异常时静默退化为空数组。 + +#### 响应示例 + +```json +{ + "code": 0, + "data": { + "id": "2053003990289129474", + "name": "一次走透呼伦贝尔的旷野心脏", + "days": [ + { + "dayNumber": 3, + "dailyMileage": 275.0, + "dailyDuration": 210, + "mileageWarnings": [] + }, + { + "dayNumber": 4, + "dailyMileage": null, + "dailyDuration": null, + "mileageWarnings": [ + "DAY4 第2段 直线距离 145.2km, 跨城市级跳跃, 可能 POI 坐标错位" + ] + } + ] + } +} +``` + +--- + +## 四、前端建议改造(强烈推荐, 防再发) + +### A. step2 编辑页展示 mileageWarnings + +每天的里程展示位旁加一个图标: +- `mileageWarnings.length === 0` → 不显示 / 显示绿色 ✓ +- `mileageWarnings.length > 0` → 显示红色 ⚠️, 鼠标 hover 展开 warning 列表 + +### B. POI 搜索控件 UX 改进(根因防御) + +当前组件:运营搜"恩和", 高德 API 返回多个同名 POI, 用户只看到 name 选错。 + +建议改造: +1. **搜索结果项显示完整地址**:`name | district + township`, 例如: + - `恩和 | 呼伦贝尔市 / 陈巴尔虎旗 / 宝日希勒镇` ← 错的恩和 + - `恩和 | 呼伦贝尔市 / 额尔古纳市 / 恩和俄罗斯族民族乡` ← 对的恩和 +2. **按产品 cityCode 限定搜索范围**:产品基础信息已存 city/adcode, POI 搜索时 region 参数限定本市, 同名异地 POI 自然过滤 +3. **选完 POI 后展示地图小预览**:``, 让运营肉眼校核位置对不对 + +不强求一次做完, B.1 最便宜也最有效。 + +--- + +## 五、不需要前端做的事 + +- 后端已修 6 条已发现错坐标记录(SQL JSON_SET), 前端不需要清缓存或重建索引 +- `daily_mileage` NULL 的天 = 等运营在后台对该产品 step2 点一次「保存」让 `ItineraryAutoCalculator` 走高德重算, 前端展示 NULL 即可 + +--- + +## 六、回归风险 + +- `ProductDetailAggregator.fillItinerary` 多一次 Feign 调用资源服务取节点坐标, 已 try/catch 退化, 资源服务挂掉不影响详情主流程 +- 阈值 100km 对跨地级市出发产品会触发 warning(例如"鄂尔多斯出发去敦煌"), 这是 feature 不是 bug, 让运营核对一下确认 POI 没选错就好 + +--- + +## 七、相关 PR / Issue + +- PR #1938 后端实现 +- Issue #1937 工单 +- 上下文相关 PR: 6 条错坐标 SQL 修复在工单 #1937 评论里记录