From 85f2f9e946d3787b4e5ad8a9c1f108652066c54b Mon Sep 17 00:00:00 2001 From: API Changelog Bot Date: Thu, 30 Apr 2026 16:11:27 +0800 Subject: [PATCH] =?UTF-8?q?feat(product):=20=E8=A1=8C=E7=A8=8B=E9=9B=86?= =?UTF-8?q?=E5=90=88=E5=9C=B0/=E8=A7=A3=E6=95=A3=E5=9C=B0=E4=BB=8E?= =?UTF-8?q?=E8=A1=8C=E6=94=BF=E5=8C=BA=E6=94=B9=E9=AB=98=E5=BE=B7=20POI=20?= =?UTF-8?q?=E7=B2=BE=E5=87=86=E5=AE=9A=E4=BD=8D=20(#1570)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @mmg 前端 picker 切换 + 落库 JSON schema 升级。后端 PR #1570 已合 dev + 部署测试服 round-trip 完成 (#1563)。 Co-Authored-By: Claude Opus 4.7 (1M context) --- ...t_product_itinerary-place-poi-precision.md | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 changelogs/2026-04/30_feat_product_itinerary-place-poi-precision.md diff --git a/changelogs/2026-04/30_feat_product_itinerary-place-poi-precision.md b/changelogs/2026-04/30_feat_product_itinerary-place-poi-precision.md new file mode 100644 index 0000000..763f333 --- /dev/null +++ b/changelogs/2026-04/30_feat_product_itinerary-place-poi-precision.md @@ -0,0 +1,144 @@ +# 行程编排集合地/解散地:行政区 → 高德 POI 精准定位 + +**类型**: 后端 FEAT(字段扩展+读路径增强) + 前端 picker 切换 +**关联**: 工单 #1563 / PR #1570 +**日期**: 2026-04-30 +**前端处理者**: mmg +**影响范围**: 管理后台产品编辑页 Step 2「行程编排」→ DAY X 的「开始 / 结束」字段(即 `gatherPlace` / `dismissalPlace`) + +--- + +## 业务目的 + +集合地 / 解散地从「行政区」(如「海拉尔区」)升级为「精准 POI」(如「海拉尔东山国际机场 / 海拉尔火车站」)。前端 `gatherPlace/dismissalPlace` 选择器从行政区下拉换成**高德 POI Autocomplete**。 + +途经路线 (`routePoints`) 不在本次范围内(已是 lng/lat 结构)。 + +--- + +## JSON Schema 升级 + +### 新格式(POI 精准定位,2026-04-30 起新数据按这个落库) + +```jsonc +{ + "name": "海拉尔东山国际机场", // POI 名称 + "address": "内蒙古呼伦贝尔市海拉尔区机场路", // 详细地址 + "location": { "lng": 119.825, "lat": 49.205 },// 嵌套对象,POI 精确坐标 + "poiId": "B0FFGTEST1", // 高德 POI ID + "adcode": "150702", // POI 解析所属行政区编码 + "cityName": "呼伦贝尔市", // POI 解析所属城市 + "districtName": "海拉尔区" // POI 解析所属行政区 +} +``` + +### 老格式(行政区,2026-04-30 之前已落库的存量数据,零迁移继续工作) + +```jsonc +{ + "name": "海拉尔区", + "level": "district", + "adcode": "150702", + "fullPath": "内蒙古自治区/呼伦贝尔市/海拉尔区", + "levelName": "区/县" +} +``` + +后端**同时兼容三种格式**: +- 新 POI 精准定位(含 `location`) +- 老行政区无 `center`(依赖 `adcode` 反查) +- 更早期行政区带 `center: 'lng,lat'`(直接 split) + +--- + +## mmg 前端要做的事(hl-ui 仓库) + +### 1. 替换 picker 组件 + +`src/views/product/edit/Step2*.vue` 行程编排 DAY X 块里,「开始」「结束」两个 `n-select` / 行政区 picker,**替换成高德 POI Autocomplete 输入框**。 + +参考高德 JS API:[`AMap.Autocomplete` + `AMap.PlaceSearch`](https://lbs.amap.com/api/javascript-api-v2/documentation#autocomplete);输入关键字 → 用户选择 POI → 把 POI 数据组装成上面的新 JSON 结构。 + +### 2. 落库 JSON 字段映射(高德 POI → 后端字段) + +```js +// 高德 PlaceSearch 单个 POI 结果 → 后端 gatherPlace/dismissalPlace +function poiToPlace(poi) { + return { + name: poi.name, // POI 名称 + address: poi.address || '', // 详细地址 + location: { + lng: Number(poi.location.lng), // 高德 LngLat 对象 + lat: Number(poi.location.lat) + }, + poiId: poi.id || '', + adcode: poi.adcode || '', // POI 自带 adcode + cityName: poi.cityname || '', // 高德 cityname 全小写 + districtName: poi.adname || '' // 高德 adname + }; +} +``` + +### 3. PUT 行程接口 + +接口路径不变:`PUT /admin/product/item/{productId}/itinerary`,`days[].gatherPlace` / `days[].dismissalPlace` 用上面的新 JSON 结构。后端字段全保留(向后兼容)。 + +### 4. 详情回显 + +`GET /admin/product/item/{productId}` 的 `data.itinerary[i].gatherPlace` / `dismissalPlace`: +- **新数据**:包含 `name / address / location / poiId / adcode / cityName / districtName`(7 字段全在) +- **老数据**:包含 `name / level / adcode / fullPath / levelName`(5 字段) +- 前端组件渲染时按字段存在性切换:有 `location.lng` 就用 POI 模式回显;否则按老行政区回显(兼容期) + +--- + +## 后端测试服 round-trip(已完成) + +测试服部署:commit `982558f9` 已部署 hl-product-service-v2 + hl-order-service-v2 双实例。 + +```bash +# 1) 老格式产品 GET 详情 → PlaceItem 老字段完整回显(零回归) +GET /admin/product/item/2047268852147875842 +→ day1.gatherPlace = {"name":"海拉尔区","level":"district","adcode":"150702","fullPath":"内蒙古...","levelName":"区/县"} ✅ + +# 2) PUT 新 POI 格式 → GET 详情回显 7 字段全在 +PUT /admin/product/item/{draftId}/itinerary + body: { days:[{ gatherPlace:{name,address,location:{lng,lat},poiId,adcode,cityName,districtName} }] } +→ HTTP 200 「行程保存成功」 +GET → day1.gatherPlace 7 字段完整含 location.lng=119.825/lat=49.205 ✅ + +# 3) 同 day 混合格式 (gather=POI, dismiss=老) 兼容 +→ 两边各自字段完整回显,互不干扰 ✅ +``` + +--- + +## 后端改动(参考) + +13 个文件 +846 / -48,PR #1570: + +- `InternalProductDetailVO.PlaceItem` + `ProductDetailVO.PlaceItem` (Feign 镜像) **扩展 7 个 POI 字段 + 嵌套 Location 静态类**,旧字段保留兼容 +- `MpProductRouteMapService.parsePlaceVO`:路径优先级 `location → center → adcode 反查` +- `AmapDrivingService.parseCenterToLngLat`:同上优先级 +- `TeamReportService.parseCityFromSnapshot`:取城市优先 `cityName/districtName`,回退 `fullPath` +- VO 注释批量升级三种格式说明 +- 单测 +13(含 Hutool BeanUtil 嵌套 Map → Location 运行时验证) +- DB schema 不变(仍是 JSON 列) +- 老数据零迁移 + +--- + +## 风险 / 兼容性 + +- **零回归承诺**:老行政区数据继续按原行为工作(路线图 origin/destination / 每日里程 / 团报城市 全部正常) +- **新旧混合期**:同一产品 itinerary 不同 day 可以混存新 POI / 老行政区结构,互不影响 +- **降级**:POI 缺 `location` 时自动回退到 `adcode` 反查中心点(高德 API),与现行 `MpProductRouteMapService` 老路径一致 + +--- + +## 联调建议 + +mmg 前端改完后: +1. 本地起 mock 服务返回新 POI 结构,验证组件回显 +2. 接到测试服 `api.test.1814.love:9443` 后端,PUT → GET round-trip 验证字段对齐 +3. 看路线图 / 团报 / 每日里程,确认坐标用的是 POI 精确坐标(比之前 adcode 中心点更精准)