liaof
2026-07-13 6ef35af5ed4cb8479a4d7fda5220b4fc26f08ee4
Merge branch 'fix-dgq-070904' into 'feature_v2.3'

Fix dgq 070904:修改bug-运营区域的ui显示

See merge request robotaxi1/xp-robotaxi-miniprogram!148
2个文件已修改
209 ■■■■■ 已修改文件
src/robotaxi/pages/operating-area/index.less 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/operating-area/index.tsx 137 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/operating-area/index.less
@@ -16,23 +16,54 @@
    background-size: 40px 40px;
  }
  .back-btn {
    position: fixed;
  .top-bar-container {
    position: absolute;
    top: 92px;
    left: 31px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 72px;
    height: 72px;
    border-radius: 200px;
    background: rgba(255, 255, 255, 0.9);
    backdrop-filter: blur(40px);
    box-shadow: 0px 4px 16px 0px rgba(84, 92, 143, 0.1);
    z-index: 100;
    .back-icon {
      width: 40px;
      height: 40px;
    .back-btn {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 72px;
      height: 72px;
      border-radius: 200px;
      background: rgba(255, 255, 255, 0.9);
      backdrop-filter: blur(40px);
      box-shadow: 0px 4px 16px 0px rgba(84, 92, 143, 0.1);
      margin-right: 16px;
      .back-icon {
        width: 40px;
        height: 40px;
      }
    }
    .select-city {
      display: flex;
      align-items: center;
      font-size: 32px;
      font-weight: 500;
      line-height: 48px;
      color: rgba(0, 0, 0, 0.9);
      margin-top: 32px;
      .city-name {
        max-width: 200px;
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
      }
      .select-city-icon {
        width: 28px;
        height: 28px;
        margin-left: 4px;
      }
    }
  }
@@ -50,10 +81,10 @@
    .origin-icon {
      position: absolute;
      top: -118rpx;
      top: -104rpx;
      right: 32px;
      width: 88rpx;
      height: 88rpx;
      width: 72rpx;
      height: 72rpx;
    }
    .header {
@@ -77,17 +108,17 @@
      }
    }
    .city-scroll {
    .fence-scroll {
      width: 100%;
      white-space: nowrap;
      margin-bottom: 32rpx;
      .city-list {
      .fence-list {
        display: flex;
        flex-direction: row;
        align-items: center;
        .city-item {
        .fence-item {
          display: inline-block;
          font-size: 28rpx;
          font-weight: 500;
@@ -112,6 +143,8 @@
      border-radius: 16rpx;
      padding: 32rpx 32rpx 36rpx 32rpx;
      box-sizing: border-box;
      height: 410rpx;
      overflow: auto;
      .content-title {
        font-size: 24rpx;
@@ -147,6 +180,9 @@
            white-space: normal;
          }
        }
        .desc-item:last-child {
          margin-bottom: 0;
        }
      }
    }
  }
src/robotaxi/pages/operating-area/index.tsx
@@ -1,4 +1,4 @@
import Taro from "@tarojs/taro";
import Taro, { useDidShow } from "@tarojs/taro";
import { useEffect, useRef, useState } from 'react';
import { View, Map, Text, Image, ScrollView } from '@tarojs/components';
import './index.less';
@@ -24,11 +24,11 @@
  const [longitude, setLongitude] = useState<number | null>(null);
  const [latitude, setLatitude] = useState<number | null>(null);
  const [polygons, setPolygons] = useState<any[]>([]);
  const [cityList, setCityList] = useState<any[]>([]);
  const [selectedCityCode, setSelectedCityCode] = useState<string>('');
  const [selectedCity, setSelectedCity] = useState<any>(null);
  const [rawGeofenceData, setRawGeofenceData] = useState<any[]>([]);
  const [selectedPolygonId, setSelectedPolygonId] = useState<number | null>(null);
  const [operatingTimeInfo, setOperatingTimeInfo] = useState<any>(null);
  const [scrollIntoViewId, setScrollIntoViewId] = useState<string>('');
  // 地图是否处于加载/切换中:为 true 时用占位图覆盖地图,避免定位跳动可见
  const [isMapLoading, setIsMapLoading] = useState<boolean>(true);
  const lastPolygonTapTimeRef = useRef(0);
@@ -53,21 +53,27 @@
    };
  }, []);
  useEffect(() => {
  useDidShow(() => {
    const cachedSelectedCity = Taro.getStorageSync('selectedCity');
    if (cachedSelectedCity && cachedSelectedCity.code && cachedSelectedCity.code !== selectedCity?.code) {
      handleSelectCity(cachedSelectedCity);
    }
  });
  useEffect(() => {
    getOpenCity().then((res: any) => {
      const openCities = res.cities || [];
      setCityList(openCities);
      const cachedSelectedCity = Taro.getStorageSync('selectedCity');
      const cachedCityCode = cachedSelectedCity?.code;
      const matchedCity = openCities.find((city: any) => (city.code || city.adcode) === cachedCityCode);
      if (matchedCity) {
        handleSelectCity(matchedCity.code || matchedCity.adcode);
      } else if (cachedCityCode) {
        handleSelectCity(cachedCityCode);
        handleSelectCity(matchedCity);
      } else if (cachedSelectedCity) {
        handleSelectCity(cachedSelectedCity);
      } else if (openCities.length > 0) {
        handleSelectCity(openCities[0].code || openCities[0].adcode);
        handleSelectCity(openCities[0]);
      } else {
        getLocationInfo();
      }
@@ -131,7 +137,8 @@
    return matchedPolygon?.mapPolygonId ?? null;
  };
  const handleSelectCity = (cityCode: string) => {
  const handleSelectCity = (city: any) => {
    const cityCode = city.code || city.adcode;
    if (!cityCode) return;
    // 进入/切换城市:先用占位图盖住地图,避免定位与缩放过程的跳动被看到
    setIsMapLoading(true);
@@ -139,13 +146,17 @@
      clearTimeout(revealTimerRef.current);
      revealTimerRef.current = null;
    }
    setSelectedCityCode(cityCode);
    setSelectedCity(city);
    getGeofence({ cityCode }).then((res: any) => {
      if (res && Array.isArray(res)) {
        res=res.filter(item =>item.type==1);
        const normalizedGeofenceData = normalizeGeofenceData(res);
        setRawGeofenceData(normalizedGeofenceData);
        const firstPolygonId = normalizedGeofenceData.length > 0 ? normalizedGeofenceData[0].mapPolygonId : null;
        setSelectedPolygonId(firstPolygonId);
        if (firstPolygonId !== null) {
          setScrollIntoViewId(`fence-${firstPolygonId}`);
        }
        if (firstPolygonId !== null) {
          const firstPolygonData = normalizedGeofenceData.find(item => item.mapPolygonId === firstPolygonId);
@@ -156,27 +167,21 @@
        const newPolygons = updatePolygonsStyle(normalizedGeofenceData, firstPolygonId);
        setPolygons(newPolygons);
        if (normalizedGeofenceData.length > 0 && normalizedGeofenceData[0]?.points?.length > 0) {
          const firstPoint = normalizedGeofenceData[0].points[0];
          const lat = Number(firstPoint.lat);
          const lng = Number(firstPoint.lng);
          setLatitude(lat);
          setLongitude(lng);
        if (normalizedGeofenceData.length > 0 && normalizedGeofenceData[0]?.polygonPoints?.length > 0) {
          const firstPolygonPoints = normalizedGeofenceData[0].polygonPoints;
          const firstPoint = firstPolygonPoints[0];
          setLatitude(firstPoint.latitude);
          setLongitude(firstPoint.longitude);
          const mapCtx = Taro.createMapContext('map');
          const points = extractPointsFromPolygons(newPolygons);
          if (points.length > 0) {
            setTimeout(() => {
              mapCtx.includePoints({
                points: points,
                padding: MAP_INCLUDE_POINTS_PADDING
              });
              // includePoints 的缩放动画结束后再显示地图,避免“先展示再放大”
              revealTimerRef.current = setTimeout(() => revealMap(), MAP_FIT_ANIMATION_DURATION);
            }, 500);
          } else {
            revealMap();
          }
          setTimeout(() => {
            mapCtx.includePoints({
              points: firstPolygonPoints,
              padding: MAP_INCLUDE_POINTS_PADDING
            });
            // includePoints 的缩放动画结束后再显示地图,避免“先展示再放大”
            revealTimerRef.current = setTimeout(() => revealMap(), MAP_FIT_ANIMATION_DURATION);
          }, 500);
        } else {
          revealMap();
        }
@@ -197,6 +202,25 @@
    });
  };
  const handleFenceTabClick = (polygonId: number) => {
    if (polygonId === selectedPolygonId) {
      setScrollIntoViewId('');
      setTimeout(() => setScrollIntoViewId(`fence-${polygonId}`), 10);
      return;
    }
    setScrollIntoViewId(`fence-${polygonId}`);
    selectPolygon(polygonId, rawGeofenceData);
    const targetPolygon = rawGeofenceData.find(item => item.mapPolygonId === polygonId);
    if (targetPolygon && targetPolygon.polygonPoints && targetPolygon.polygonPoints.length > 0) {
      const mapCtx = Taro.createMapContext('map');
      mapCtx.includePoints({
        points: targetPolygon.polygonPoints,
        padding: MAP_INCLUDE_POINTS_PADDING
      });
    }
  };
  const handlePolygonTap = (e: any) => {
    let tapPolygonId = null;
    if (e.detail && e.detail.polygonId) {
@@ -207,7 +231,7 @@
    if (tapPolygonId !== null && rawGeofenceData.length > 0) {
      lastPolygonTapTimeRef.current = Date.now();
      selectPolygon(tapPolygonId, rawGeofenceData);
      handleFenceTabClick(tapPolygonId);
    }
  };
@@ -222,7 +246,7 @@
    }
    const nearestPolygonId = findNearestPolygonIdByTap(tapLatitude, tapLongitude);
    if (nearestPolygonId !== null) {
      selectPolygon(nearestPolygonId, rawGeofenceData);
      handleFenceTabClick(nearestPolygonId);
    }
  };
@@ -244,11 +268,12 @@
  };
  const toOrigin = () => {
    const mapCtx = Taro.createMapContext('map');
    const points = extractPointsFromPolygons(polygons);
    if (points.length > 0) {
    if (selectedPolygonId === null) return;
    const targetPolygon = rawGeofenceData.find(item => item.mapPolygonId === selectedPolygonId);
    if (targetPolygon && targetPolygon.polygonPoints && targetPolygon.polygonPoints.length > 0) {
      const mapCtx = Taro.createMapContext('map');
      mapCtx.includePoints({
        points,
        points: targetPolygon.polygonPoints,
        padding: MAP_INCLUDE_POINTS_PADDING
      });
    }
@@ -321,31 +346,37 @@
      >
        {isMapLoading && <View className="map-placeholder-grid" />}
      </Map>
      {/* 返回按钮 */}
      <View onClick={toBack} className="back-btn">
        <Image className="back-icon" src="https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/back-icon.png" />
      {/* 顶部返回和城市选择 */}
      <View className="top-bar-container">
        <View onClick={toBack} className="back-btn">
          <Image className="back-icon" src="https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/back-icon.png" />
        </View>
        <View className="select-city" onClick={() => Taro.navigateTo({ url: '/robotaxi/pages/select-city/index' })}>
          <Text className="city-name">{selectedCity?.name || '选择城市'}</Text>
          <Image className="select-city-icon" src="https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/select-city.png" />
        </View>
      </View>
      {/* 底部面板 */}
      {
        cityList.length != 0 &&
        rawGeofenceData.length !== 0 &&
        <View className="bottom-sheet">
          <Image className="origin-icon" src='https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/origin-icon.png' onClick={toOrigin} />
          <View className="header">
            <Text className="title">查看运营区域</Text>
          </View>
          <ScrollView scrollX className="city-scroll">
            <View className="city-list">
              {cityList.map((city, index) => {
                const code = city.code || city.adcode;
          <ScrollView scrollX className="fence-scroll" scrollIntoView={scrollIntoViewId} scrollWithAnimation>
            <View className="fence-list">
              {rawGeofenceData.map((fence, index) => {
                return (
                  <View
                    key={index}
                    className={`city-item ${selectedCityCode === code ? 'active' : ''}`}
                    onClick={() => handleSelectCity(code)}
                    id={`fence-${fence.mapPolygonId}`}
                    className={`fence-item ${selectedPolygonId === fence.mapPolygonId ? 'active' : ''}`}
                    onClick={() => handleFenceTabClick(fence.mapPolygonId)}
                  >
                    {city.name}
                    {fence.name || `区域${index + 1}`}
                  </View>
                );
              })}
@@ -359,12 +390,14 @@
            </View>
            <View className="content-desc">
              <View className="desc-item">
                <Text className="text">各站点运营时间可能存在调整,实际运营情况请以页面实时展示为准</Text>
                <Text className="text">1. 运营时间内可正常使用打车服务,超出运营时间无法使用打车功能</Text>
              </View>
              {/* <View className="desc-item">
                <Text className="index">2.</Text>
                <Text className="text">各站点运营时间可能存在调整,实际运营情况请以页面实时展示为准</Text>
              </View> */}
               <View className="desc-item">
                <Text className="text">2. 各站点运营时间可能存在差异,站点运营情况请依照实际情况</Text>
              </View>
               <View className="desc-item">
                <Text className="text">3. 有问题可联系区域负责人,联系电话:4008208820</Text>
              </View>
            </View>
          </View>
        </View>