@mmg 前端 picker 切换 + 落库 JSON schema 升级。后端 PR #1570 已合 dev + 部署测试服 round-trip 完成 (#1563)。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6.0 KiB
行程编排集合地/解散地:行政区 → 高德 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 起新数据按这个落库)
{
"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 之前已落库的存量数据,零迁移继续工作)
{
"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;输入关键字 → 用户选择 POI → 把 POI 数据组装成上面的新 JSON 结构。
2. 落库 JSON 字段映射(高德 POI → 后端字段)
// 高德 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 双实例。
# 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 前端改完后:
- 本地起 mock 服务返回新 POI 结构,验证组件回显
- 接到测试服
api.test.1814.love:9443后端,PUT → GET round-trip 验证字段对齐 - 看路线图 / 团报 / 每日里程,确认坐标用的是 POI 精确坐标(比之前 adcode 中心点更精准)