hejianhao
2026-06-16 1a9b0ceecbe4b654fcd20699324cc7672632c435
feat(robotaxi/home): 为首页地图添加用户定位缓存功能
1个文件已添加
4个文件已修改
155 ■■■■■ 已修改文件
src/pages/robotaxi/home/components/home-map-panel.tsx 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/robotaxi/home/hooks/use-home-bootstrap.ts 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/robotaxi/home/hooks/use-location-flow.ts 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/robotaxi/home/hooks/use-user-location-cache.ts 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/robotaxi/home/index.tsx 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/robotaxi/home/components/home-map-panel.tsx
@@ -12,6 +12,10 @@
  longitude: number | null;
  /** 地图纬度。 */
  latitude: number | null;
  /** 地图默认经度。 */
  defaultLongitude: number;
  /** 地图默认纬度。 */
  defaultLatitude: number;
  /** 地图缩放等级。 */
  mapScale: number;
  /** 地图 marker 列表。 */
@@ -96,8 +100,8 @@
  return (
    <Map
      id={HOME_MAP_ID}
      longitude={props.longitude ?? DEFAULT_LONGITUDE}
      latitude={props.latitude ?? DEFAULT_LATITUDE}
      longitude={props.longitude ?? props.defaultLongitude ?? DEFAULT_LONGITUDE}
      latitude={props.latitude ?? props.defaultLatitude ?? DEFAULT_LATITUDE}
      scale={props.mapScale}
      markers={displayMarkers}
      polygons={props.polygons}
src/pages/robotaxi/home/hooks/use-home-bootstrap.ts
@@ -13,6 +13,7 @@
  writeHomeStartSiteDisplayState
} from '../../../../robotaxi/hooks/use-home-start-site-display';
import useStationScaleFocus from '../../../../robotaxi/hooks/use-station-scale-focus';
import { readHomeCachedUserLocation } from './use-user-location-cache';
type HomeTripStatus = TripStatus | 0;
@@ -108,6 +109,16 @@
 * 首页启动流程编排。
 */
export default function useHomeBootstrap(deps: Deps) {
  /**
   * 优先使用最近一次成功定位的缓存坐标,否则回落默认坐标。
   */
  const applyCachedUserLocationOrDefault = () => {
    const cachedUserLocation = readHomeCachedUserLocation();
    deps.setMapScale(3);
    deps.setLatitude(cachedUserLocation?.lat ?? deps.defaultLatitude);
    deps.setLongitude(cachedUserLocation?.lng ?? deps.defaultLongitude);
  };
  const toHomeTripStatus = (value: unknown): HomeTripStatus => {
    const numericValue = Number(value); // 统一转数值后做状态归一
    return numericValue === 0 ? 0 : toTripStatus(numericValue);
@@ -292,9 +303,7 @@
      return;
    }
    if (auth === false) {
      deps.setMapScale(3);
      deps.setLatitude(deps.defaultLatitude);
      deps.setLongitude(deps.defaultLongitude);
      applyCachedUserLocationOrDefault();
      return;
    }
    if (shouldUseNearestSiteByOrder) {
src/pages/robotaxi/home/hooks/use-location-flow.ts
@@ -12,6 +12,7 @@
  readHomeStartSiteDisplayState,
  shouldRetainManualSelectedHomeStartSiteOnNextHome
} from '../../../../robotaxi/hooks/use-home-start-site-display';
import { readHomeCachedUserLocation } from './use-user-location-cache';
type Deps = {
  mapState: any;
@@ -48,6 +49,33 @@
  onLocationSettled,
  onUserLocationResolved
}: Deps) {
  /**
   * 按“最近用户位置缓存 -> 默认城市中心 -> 故宫”顺序兜底地图中心。
   */
  const updateByCachedUserLocationOrDefault = async () => {
    const cachedUserLocation = readHomeCachedUserLocation();
    if (cachedUserLocation) {
      mapState.setLatitude(cachedUserLocation.lat);
      mapState.setLongitude(cachedUserLocation.lng);
      siteState.setCurrentAddress(String(cachedUserLocation.poi_name || cachedUserLocation.city || ''));
      onUserLocationResolved?.(cachedUserLocation);
      return;
    }
    const cachedCity = Taro.getStorageSync('selectedCity');
    if (cachedCity?.name) {
      try {
        const loc = await getCityLocation(cachedCity.name);
        mapState.setLatitude(loc.latitude);
        mapState.setLongitude(loc.longitude);
        return;
      } catch (error) {
      }
    }
    mapState.setMapScale(3);
    mapState.setLatitude(DEFAULT_LATITUDE);
    mapState.setLongitude(DEFAULT_LONGITUDE);
  };
  /**
   * 同步用户当前位置快照,供页面埋点直接复用。
   */
@@ -105,22 +133,6 @@
    return true;
  };
  const updateDefaultByCachedCity = async () => {
    const cachedCity = Taro.getStorageSync('selectedCity');
    if (cachedCity?.name) {
      try {
        const loc = await getCityLocation(cachedCity.name);
        mapState.setLatitude(loc.latitude);
        mapState.setLongitude(loc.longitude);
        return;
      } catch (error) {
      }
    }
    mapState.setMapScale(3);
    mapState.setLatitude(DEFAULT_LATITUDE);
    mapState.setLongitude(DEFAULT_LONGITUDE);
  };
  const updateByIP = async () => {
    try {
      const res: any = await getLocationByIP();
@@ -144,8 +156,7 @@
        city: cityName
      });
    } catch (error) {
      mapState.setLatitude(DEFAULT_LATITUDE);
      mapState.setLongitude(DEFAULT_LONGITUDE);
      await updateByCachedUserLocationOrDefault();
    }
  };
@@ -153,7 +164,7 @@
    mapState.setIsLocationAuthDenied(true);
    const usedStartSite = await updateByStartSite();
    if (!usedStartSite) {
      await updateDefaultByCachedCity();
      await updateByCachedUserLocationOrDefault();
    }
  };
src/pages/robotaxi/home/hooks/use-user-location-cache.ts
New file
@@ -0,0 +1,60 @@
import Taro from '@tarojs/taro';
/** 最近一次成功定位的用户位置缓存键。 */
export const HOME_CACHED_USER_LOCATION_KEY = 'robotaxi_home_cached_user_location';
/** 首页用户位置缓存结构。 */
export type HomeCachedUserLocation = {
  /** 纬度。 */
  lat: number;
  /** 经度。 */
  lng: number;
  /** poi id。 */
  poi_id: string;
  /** poi 名称。 */
  poi_name: string;
  /** 城市名。 */
  city: string;
};
/**
 * 判断缓存的用户位置是否可用于地图中心。
 */
export const isValidHomeCachedUserLocation = (
  location: Partial<HomeCachedUserLocation> | null | undefined
) => {
  return Number.isFinite(Number(location?.lat)) && Number.isFinite(Number(location?.lng));
};
/**
 * 读取最近一次成功定位的用户位置缓存。
 */
export const readHomeCachedUserLocation = (): HomeCachedUserLocation | null => {
  const cachedLocation = Taro.getStorageSync(HOME_CACHED_USER_LOCATION_KEY);
  if (!isValidHomeCachedUserLocation(cachedLocation)) {
    return null;
  }
  return {
    lat: Number(cachedLocation.lat),
    lng: Number(cachedLocation.lng),
    poi_id: String(cachedLocation.poi_id || ''),
    poi_name: String(cachedLocation.poi_name || ''),
    city: String(cachedLocation.city || '')
  };
};
/**
 * 写入最近一次成功定位的用户位置缓存。
 */
export const writeHomeCachedUserLocation = (location: HomeCachedUserLocation) => {
  if (!isValidHomeCachedUserLocation(location)) {
    return;
  }
  Taro.setStorageSync(HOME_CACHED_USER_LOCATION_KEY, {
    lat: Number(location.lat),
    lng: Number(location.lng),
    poi_id: String(location.poi_id || ''),
    poi_name: String(location.poi_name || ''),
    city: String(location.city || '')
  });
};
src/pages/robotaxi/home/index.tsx
@@ -65,6 +65,10 @@
  createReportStationPayload,
  createReportUserCurrentLocationPayload
} from '../../../robotaxi/constants/report-structures';
import {
  readHomeCachedUserLocation,
  writeHomeCachedUserLocation
} from './hooks/use-user-location-cache';
type HomeTripStatus = TripStatus | 0;
type UserCurrentLocation = {
@@ -79,6 +83,7 @@
 * Robotaxi 首页页面容器:仅负责组合领域 hook 与布局组件。
 */
function Home() {
  const initialCachedUserLocation = readHomeCachedUserLocation(); // 首页最近一次成功定位缓存
  const [showPrivacy, setShowPrivacy] = useState(false); // 隐私协议弹窗是否显示
  const [showCustomerService, setShowCustomerService] = useState(false); // 客服弹窗是否显示
  const [tripStatus, setTripStatus] = useState<HomeTripStatus>(0); // 当前行程状态
@@ -88,7 +93,7 @@
  const [overlayAnchorBottom, setOverlayAnchorBottom] = useState<number | null>(null); // 地图浮层锚点
  const [temperatureUnit, setTemperatureUnit] = useState(DEFAULT_TEMPERATURE_UNIT); // 温度单位配置
  const [preferredStartSite, setPreferredStartSite] = useState<any>(null); // 首页确认上车点
  const [userCurrentLocation, setUserCurrentLocation] = useState<UserCurrentLocation | null>(null); // 用户当前位置快照
  const [userCurrentLocation, setUserCurrentLocation] = useState<UserCurrentLocation | null>(initialCachedUserLocation); // 用户当前位置快照
  /**
   * 归一化首页当前位置埋点字段。
@@ -159,6 +164,16 @@
  const isGuest = needLogin; // 当前是否游客态
  const shouldShowLoginEntry = needLogin; // 当前是否展示登录引导
  const shouldShowGuestTip = Taro.getStorageSync('has_show_privicy_Robotaxi') !== 'true' && isGuest; // 当前是否展示游客隐私提示
  const mapFallbackLatitude = userCurrentLocation?.lat ?? DEFAULT_LATITUDE; // 地图兜底纬度
  const mapFallbackLongitude = userCurrentLocation?.lng ?? DEFAULT_LONGITUDE; // 地图兜底经度
  /**
   * 同步首页用户当前位置快照,并持久化最近一次成功定位。
   */
  const handleUserLocationResolved = (location: UserCurrentLocation) => {
    setUserCurrentLocation(location);
    writeHomeCachedUserLocation(location);
  };
  const {
    boxHeight,
@@ -206,7 +221,7 @@
    cityState,
    isLoggedIn,
    onLocationSettled: syncStationFenceVisibility,
    onUserLocationResolved: setUserCurrentLocation
    onUserLocationResolved: handleUserLocationResolved
  });
  const { toOrigin } = useOriginAction({
    isLocationAuthDenied,
@@ -217,7 +232,7 @@
    setLongitude,
    ensureSelectedCityReady,
    lastSelectedCityCodeRef,
    onUserLocationResolved: setUserCurrentLocation
    onUserLocationResolved: handleUserLocationResolved
  });
  const bootstrap = useHomeBootstrap({
    wsHost: _ROBOTAXI_WS_HOST,
@@ -510,6 +525,8 @@
      <HomeMapPanel
        longitude={longitude}
        latitude={latitude}
        defaultLongitude={mapFallbackLongitude}
        defaultLatitude={mapFallbackLatitude}
        mapScale={mapScale}
        mergedMapMarkers={mergedMapMarkers}
        polygons={displayPolygons}