6.2 KiB
admin/product-v2: 行程编辑详情新增里程异常 warnings 字段 + 建议前端 POI 搜索控件改进
服务: hl-product-service-v2 (端口 8083) PR: #1938 Issue: #1937 日期: 2026-05-11 影响范围: 管理端产品编辑(step2 行程编排)详情响应; POI 搜索控件(可选改进)
⚠️ 关键变化
后端在产品编辑详情响应里新增了一个 mileageWarnings: List<String> 字段(按天), 用于在运营选错 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<String>, 默认空数组 |
三、接口详情
1. 管理端获取产品详情 GET /admin/product/item/{id}
VO: ProductDetailRespVO.days[] -> ItineraryDayRespVO
出参新增字段
| 字段 | 类型 | 说明 | 默认 |
|---|---|---|---|
days[i].mileageWarnings |
List<String> |
该天里程异常 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 实时计算。资源服务异常时静默退化为空数组。
响应示例
{
"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 选错。
建议改造:
- 搜索结果项显示完整地址:
name | district + township, 例如:恩和 | 呼伦贝尔市 / 陈巴尔虎旗 / 宝日希勒镇← 错的恩和恩和 | 呼伦贝尔市 / 额尔古纳市 / 恩和俄罗斯族民族乡← 对的恩和
- 按产品 cityCode 限定搜索范围:产品基础信息已存 city/adcode, POI 搜索时 region 参数限定本市, 同名异地 POI 自然过滤
- 选完 POI 后展示地图小预览:
<map markers={[poi.location]}>, 让运营肉眼校核位置对不对
不强求一次做完, B.1 最便宜也最有效。
五、不需要前端做的事
- 后端已修 6 条已发现错坐标记录(SQL JSON_SET), 前端不需要清缓存或重建索引
daily_mileageNULL 的天 = 等运营在后台对该产品 step2 点一次「保存」让ItineraryAutoCalculator走高德重算, 前端展示 NULL 即可
六、回归风险
ProductDetailAggregator.fillItinerary多一次 Feign 调用资源服务取节点坐标, 已 try/catch 退化, 资源服务挂掉不影响详情主流程- 阈值 100km 对跨地级市出发产品会触发 warning(例如"鄂尔多斯出发去敦煌"), 这是 feature 不是 bug, 让运营核对一下确认 POI 没选错就好
七、相关 PR / Issue
- PR #1938 后端实现
- Issue #1937 工单
- 上下文相关 PR: 6 条错坐标 SQL 修复在工单 #1937 评论里记录