| | |
| | | |
| | | /** |
| | | * 更新地图业务数据:围栏内判断、站点列表、自动缩放。 |
| | | * @param seq 可选的请求序号,传入时仅当其为最新一次拖动请求才会回写页面状态, |
| | | * 用于丢弃连续/快速拖动时乱序返回的过期结果,避免旧站点数据回填。 |
| | | */ |
| | | const updateMapData = async (lat: number, lng: number) => { |
| | | const updateMapData = async (lat: number, lng: number, seq?: number) => { |
| | | const selectedCity = Taro.getStorageSync('selectedCity'); |
| | | const pointOnOff = state.pageType === 'start' |
| | | ? SELECT_MAP_POINT_ON_OFF.start |
| | |
| | | pointOnOff, |
| | | { allowedElectronicAreaId: referenceElectronicAreaId } |
| | | ); |
| | | state.setIsOperatingArea(isInside); |
| | | state.setMarkers(newMarkers); |
| | | state.setNearbySites(sites); |
| | | if (state.selectionMode === 'station' && state.selectedStation?.stationId) { |
| | | const nextStationSites = filterSelectableSites(sites).filter((item: any) => String(item?.stationId || '') === String(state.selectedStation.stationId)); |
| | | state.setStationSiteList(nextStationSites); |
| | | } |
| | | |
| | | const isStationFocused = state.selectedSite && state.selectedSite.stationId; |
| | | |
| | | if (!isStationFocused && !state.autoScaleLockedRef.current) { |
| | | const autoScale = getAutoScaleBySites(sites?.length > 0 ? sites : newMarkers, lat, lng); |
| | | if (typeof autoScale === 'number') { |
| | | state.setMapScale((prev) => { |
| | | const nextScale = Math.max(AUTO_SCALE_MIN, Math.min(AUTO_SCALE_MAX, autoScale)); |
| | | if (Math.abs(prev - nextScale) < 0.01) return prev; |
| | | return nextScale; |
| | | }); |
| | | // 仅最新一次拖动请求才回写状态;过期请求只返回数据、不污染 markers/nearbySites 等状态, |
| | | // 防止过期 nearbySites 触发场站副作用回填 selectedSite,导致大头针离开点位后旧信息滞留。 |
| | | const isStaleRequest = typeof seq === 'number' && seq !== state.regionSeqRef.current; |
| | | if (!isStaleRequest) { |
| | | state.setIsOperatingArea(isInside); |
| | | state.setMarkers(newMarkers); |
| | | state.setNearbySites(sites); |
| | | if (state.selectionMode === 'station' && state.selectedStation?.stationId) { |
| | | const nextStationSites = filterSelectableSites(sites).filter((item: any) => String(item?.stationId || '') === String(state.selectedStation.stationId)); |
| | | state.setStationSiteList(nextStationSites); |
| | | } |
| | | state.autoScaleLockedRef.current = true; |
| | | |
| | | const isStationFocused = state.selectedSite && state.selectedSite.stationId; |
| | | |
| | | if (!isStationFocused && !state.autoScaleLockedRef.current) { |
| | | const autoScale = getAutoScaleBySites(sites?.length > 0 ? sites : newMarkers, lat, lng); |
| | | if (typeof autoScale === 'number') { |
| | | state.setMapScale((prev) => { |
| | | const nextScale = Math.max(AUTO_SCALE_MIN, Math.min(AUTO_SCALE_MAX, autoScale)); |
| | | if (Math.abs(prev - nextScale) < 0.01) return prev; |
| | | return nextScale; |
| | | }); |
| | | } |
| | | state.autoScaleLockedRef.current = true; |
| | | } |
| | | } |
| | | return { isInside, newMarkers, sites, electronicAreaId }; |
| | | } finally { |
| | |
| | | |
| | | if (causedBy === 'gesture' || causedBy === 'drag' || causedBy === 'scale') { |
| | | state.pickupConfirmTypeRef.current = 'drag'; |
| | | // 同步自增请求序号,标记本次拖动为「最新」。连续/快速拖动时每个 end 事件都会派生一条 |
| | | // 独立异步链,借助该序号在异步返回后判定是否为最新一次,丢弃乱序返回的过期结果。 |
| | | const currentRegionSeq = (state.regionSeqRef.current += 1); |
| | | mapCtx.getCenterLocation({ |
| | | success: async (res) => { |
| | | const { latitude: lat, longitude: lng } = res; |
| | | const { newMarkers, sites, isInside, electronicAreaId } = await updateMapData(lat, lng); |
| | | const { newMarkers, sites, isInside, electronicAreaId } = await updateMapData(lat, lng, currentRegionSeq); |
| | | // 已有更新的拖动发生,当前为过期结果,直接丢弃,避免用旧中心点的吸附/清空结论覆盖最新状态。 |
| | | if (currentRegionSeq !== state.regionSeqRef.current) return; |
| | | const selectableMarkers = getSelectableMarkers(newMarkers, sites); |
| | | const { targetMarker, minDistance } = findNearestMarker(lat, lng, selectableMarkers); |
| | | if (targetMarker && minDistance < state.distanceConfig.adsorptionDistance) { |