fix(map): 修正定位落到零坐标、旧详情页路由白屏与跳转期间地图可拖动

三个问题,前两个各有独立根因。

1) 首次打开定位到几内亚湾、底图变成 HERE

   regionchange 处理里读的是 `event.detail.longitude`,但微信的 regionchange
   载荷没有这个字段,`Number(undefined)` 恒为 NaN,于是每次都落到异步的
   getCenterLocation。冷启动时地图 SDK 还没拿到有效中心点,它会回传 (0, 0),
   而两个 store 的坐标校验只查 Number.isFinite,(0, 0) 直接通过。

   (0, 0) 落在几内亚湾(Null Island),微信 <map> 一到境外坐标就切 HERE 底图。
   全程不需要用户点过定位按钮。

   数据集校验器本来就在拒绝零坐标,只是运行时 store 没套用同一条规则。现把它
   提成共享守卫 isTrustworthyCoordinate,validateCoordinates 改为复用,并铺到
   map store、location store 和打卡定位服务。regionchange 一侧改为优先读微信
   真正给的 detail.centerLocation,回落路径校验后才写入,且 mapReady 为 false
   时不接受任何回写。

2) 冷启动白屏、左上角只剩回首页的小房子

   f8ad5e1 把详情页从 pages/poi/detail 移进 pages-poi 分包,源码调用点都改了,
   但旧路由本身从 app.json 消失。任何还攥着旧路径的入口 —— 开发者工具模拟器上次
   停留的路由、预览启动页、已发出的分享卡片或二维码 —— 冷启动会落到微信解析不出
   的路由,渲染成白屏;因为不是 tabBar 页且栈深为 1,左上角只剩小房子。

   旧路径补一个只做重定向的跳板页,带 poiId 就 redirectTo 新路径,不带就 reLaunch
   回地图。用 redirectTo 是为了让跳板不留在页面栈里。主包 +1 KB。等所有入口都刷新
   过可以删掉。

3) 跳转详情页时地图仍可拖动几毫秒

   <map> 是渲染在 webview 之上的原生组件,销毁是异步的,页面转场开始了它还在。
   navigating 之前只用于防重复点击,没接到地图上。现在接上 enable-scroll /
   enable-zoom,并给 selectMarker、openCheckInRecords 补同一个守卫(后者原先完全
   没有防护),regionchange 在跳转期间也不再回写 viewport。onShow 里直接复位
   navigating,返回时立刻恢复交互,不等 500ms 兜底定时器。

   原生组件的异步销毁消不掉,但那几毫秒里地图不再响应拖动和缩放。

验证:测试 100 passed(map store 新增零坐标、越界、resetViewport 兜底用例),
type-check 干净。build 主包 1187 KB / 分包 1841 KB,dev 1527 KB / 1847 KB,
均过 verify:mp-weixin。
This commit is contained in:
周瑞哲
2026-08-03 10:45:28 +08:00
parent f8ad5e1faf
commit 1bcdd40729
10 changed files with 201 additions and 31 deletions
+13 -6
View File
@@ -1,5 +1,6 @@
import type { GeoPoint, MapViewport } from '@/domain/poi'
import type { MapViewport } from '@/domain/poi'
import { defineStore } from 'pinia'
import { isTrustworthyCoordinate } from '@/domain/poi'
export const DEFAULT_GUANGMING_VIEWPORT: MapViewport = {
longitude: 113.935,
@@ -14,8 +15,10 @@ interface MapSessionState {
plannedRouteVisible: boolean
}
function isFinitePoint(point: GeoPoint): boolean {
return Number.isFinite(point.longitude) && Number.isFinite(point.latitude)
function isUsableViewport(viewport: MapViewport): boolean {
return isTrustworthyCoordinate(viewport.longitude, viewport.latitude)
&& Number.isFinite(viewport.scale)
&& viewport.scale > 0
}
export const useMapStore = defineStore('map-session', {
@@ -33,13 +36,15 @@ export const useMapStore = defineStore('map-session', {
this.selectedPoiId = poiId
},
updateViewport(viewport: MapViewport) {
if (!isFinitePoint(viewport) || !Number.isFinite(viewport.scale) || viewport.scale <= 0)
if (!isUsableViewport(viewport))
return
this.viewport = { ...viewport }
},
resetViewport(viewport: MapViewport = DEFAULT_GUANGMING_VIEWPORT) {
this.viewport = { ...viewport }
this.viewport = isUsableViewport(viewport)
? { ...viewport }
: { ...DEFAULT_GUANGMING_VIEWPORT }
},
showPlannedRoute() {
this.plannedRouteVisible = true
@@ -50,7 +55,9 @@ export const useMapStore = defineStore('map-session', {
resetSession(viewport: MapViewport = DEFAULT_GUANGMING_VIEWPORT) {
this.categoryCode = null
this.selectedPoiId = null
this.viewport = { ...viewport }
this.viewport = isUsableViewport(viewport)
? { ...viewport }
: { ...DEFAULT_GUANGMING_VIEWPORT }
this.plannedRouteVisible = false
},
},