From b298b7953fa88b274dcff9e20acd8e79243904f1 Mon Sep 17 00:00:00 2001
From: hejianhao <15708179461@qq.com>
Date: 星期一, 30 三月 2026 18:47:33 +0800
Subject: [PATCH] feat: 优化地图交互与UI样式

---
 src/robotaxi/pages/begin-route/components/calling-car.tsx                  |    2 
 src/robotaxi/pages/site-search/index.tsx                                   |   21 ++
 src/robotaxi/pages/operating-area/index.tsx                                |  159 ++++++++++++++--------
 src/robotaxi/pages/begin-route/components/css-folder/passenger-notice.less |   35 ++++
 src/robotaxi/pages/site-search/index.less                                  |    2 
 src/robotaxi/pages/select-map-site/index.tsx                               |   24 +++
 src/pages/robotaxi/home/index.tsx                                          |   26 +++
 src/robotaxi/pages/begin-route/index.tsx                                   |   41 +++--
 src/robotaxi/pages/operating-area/index.less                               |    1 
 src/robotaxi/pages/begin-route/components/css-folder/release-route.less    |    7 
 src/robotaxi/pages/begin-route/components/passenger-notice.tsx             |   72 +++++++++
 11 files changed, 297 insertions(+), 93 deletions(-)

diff --git a/src/pages/robotaxi/home/index.tsx b/src/pages/robotaxi/home/index.tsx
index ed3391c..574d3df 100644
--- a/src/pages/robotaxi/home/index.tsx
+++ b/src/pages/robotaxi/home/index.tsx
@@ -1208,6 +1208,29 @@
     jumpTo({ url: '/pages/user/login?hideBack=1' });
   }
 
+  // 处理点击地图 marker
+  const handleMarkerTap = (e: any) => {
+    if (isLocationAuthDenied) return;
+    const markerId = e?.detail?.markerId;
+    if (markerId === undefined) return;
+
+    const targetMarker = markers.find(m => m.id === markerId);
+    if (targetMarker) {
+      // 忽略因调用 moveToLocation 引起的 region change,避免重复吸附计算
+      shouldIgnoreRegionChange.current = true;
+      
+      const mapCtx = Taro.createMapContext('map');
+      mapCtx.moveToLocation({
+        latitude: targetMarker.latitude,
+        longitude: targetMarker.longitude,
+      });
+
+      setIsAdsorbed(true);
+      setCurrentSite(targetMarker);
+      setShowToolTip(true);
+    }
+  };
+
   return (
     <View className="home-container">
       <Map
@@ -1215,10 +1238,11 @@
         longitude={longitude ?? DEFAULT_LONGITUDE}
         latitude={latitude ?? DEFAULT_LATITUDE}
         scale={mapScale}
-        markers={isLocationAuthDenied ? [] : markers}
+        markers={isLocationAuthDenied ? [] : markers.map(m => ({ ...m, title: '', name: '' }))}
         polygons={polygons}
         showLocation={!!longitude}
         onRegionChange={handleRegionChange}
+        onMarkerTap={handleMarkerTap}
         style={{ width: '100%', height: '85vh', flex: 'none' }}
       >
         {/* 选择城市 */}
diff --git a/src/robotaxi/pages/begin-route/components/calling-car.tsx b/src/robotaxi/pages/begin-route/components/calling-car.tsx
index e5aae11..c0c249c 100644
--- a/src/robotaxi/pages/begin-route/components/calling-car.tsx
+++ b/src/robotaxi/pages/begin-route/components/calling-car.tsx
@@ -576,7 +576,7 @@
                         }
                     </View>
                     {
-                        tripStatus == 4 && <View>
+                        (tripStatus == 4 && typeof tempStatus === 'number') && <View>
                             <View className="car-card-line"></View>
                             {/* 温度调节 */}
                             <View className="car-card-temp">
diff --git a/src/robotaxi/pages/begin-route/components/css-folder/passenger-notice.less b/src/robotaxi/pages/begin-route/components/css-folder/passenger-notice.less
index 72e1990..1cd4f8c 100644
--- a/src/robotaxi/pages/begin-route/components/css-folder/passenger-notice.less
+++ b/src/robotaxi/pages/begin-route/components/css-folder/passenger-notice.less
@@ -33,12 +33,39 @@
             color: rgba(0, 0, 0, 0.9);
         }
 
-        &-desc {
+        &-desc-wrap {
+            position: relative;
             margin-top: 34px;
-            letter-spacing: normal;
-            color: rgba(0, 0, 0, 0.9);
             height: 342px;
-            overflow: hidden;
+
+            .passenger-content-desc {
+                height: 100%;
+                overflow-y: scroll;
+                margin-top: 0;
+            }
+
+            /* 自定义滚动条轨道 */
+            .custom-scrollbar-track {
+                position: absolute;
+                right: 0;
+                top: 0;
+                width: 6px;
+                height: 100%;
+                background-color: rgba(0, 0, 0, 0.05);
+                border-radius: 4px;
+                z-index: 10;
+            }
+
+            /* 自定义滚动条滑块 */
+            .custom-scrollbar-thumb {
+                position: absolute;
+                right: 0;
+                top: 0;
+                width: 6px;
+                background-color: rgba(0, 0, 0, 0.25);
+                border-radius: 4px;
+                z-index: 11;
+            }
         }
 
         &-checkbox {
diff --git a/src/robotaxi/pages/begin-route/components/css-folder/release-route.less b/src/robotaxi/pages/begin-route/components/css-folder/release-route.less
index 4ee6602..559842b 100644
--- a/src/robotaxi/pages/begin-route/components/css-folder/release-route.less
+++ b/src/robotaxi/pages/begin-route/components/css-folder/release-route.less
@@ -95,7 +95,7 @@
                     align-items: center;
 
                     .to-site-text {
-                        font-size: 32px;
+                        font-size: 28px;
                         font-weight: 500;
                         line-height: 48px;
                         letter-spacing: normal;
@@ -141,7 +141,6 @@
                     }
 
                     .money-num {
-                        
                         margin: 0 4px;
                         font-size: 48px;
                         line-height: 40px;
@@ -169,7 +168,7 @@
                     }
 
                     view:last-child {
-                        font-size: 20px;
+                        font-size: 24px;
                         font-weight: normal;
                         line-height: 36px;
                         letter-spacing: normal;
@@ -201,7 +200,7 @@
 
                     .original-fare {
                         
-                        font-size: 28px;
+                        font-size: 24px;
                         font-weight: normal;
                         line-height: 41px;
                         letter-spacing: normal;
diff --git a/src/robotaxi/pages/begin-route/components/passenger-notice.tsx b/src/robotaxi/pages/begin-route/components/passenger-notice.tsx
index 2ce8edd..30a1935 100644
--- a/src/robotaxi/pages/begin-route/components/passenger-notice.tsx
+++ b/src/robotaxi/pages/begin-route/components/passenger-notice.tsx
@@ -7,13 +7,52 @@
 type Props = {
     show?: boolean;
     onClose?: () => void;
+    onCheckedChange?: (checked: boolean) => void;
 }
 
-export default function PassengerNotice({ show = false, onClose }: Props) {
+export default function PassengerNotice({ show = false, onClose, onCheckedChange }: Props) {
     const [visible, setVisible] = useState(false);
     const [animationData, setAnimationData] = useState<any>();
     const [checked, setChecked] = useState(true);
     const [noticeContent, setNoticeContent] = useState('');
+    const [thumbHeight, setThumbHeight] = useState(0);
+    const [thumbTop, setThumbTop] = useState(0);
+    const [containerHeight, setContainerHeight] = useState(0);
+    const [showScrollbar, setShowScrollbar] = useState(false);
+
+    const onScroll = (e) => {
+        const { scrollHeight, scrollTop } = e.detail;
+        if (containerHeight > 0 && scrollHeight > containerHeight) {
+            const newThumbTop = (scrollTop / scrollHeight) * containerHeight;
+            setThumbTop(newThumbTop);
+        }
+    };
+
+    useEffect(() => {
+        if (noticeContent && visible) {
+            // Give it a little time to render
+            setTimeout(() => {
+                const query = Taro.createSelectorQuery();
+                query.select('.passenger-content-desc').boundingClientRect();
+                query.select('.passenger-content-desc-inner').boundingClientRect();
+                query.exec((res) => {
+                    if (res[0] && res[1]) {
+                        const wrapperHeight = res[0].height;
+                        const contentHeight = res[1].height;
+                        setContainerHeight(wrapperHeight);
+                        if (contentHeight > wrapperHeight) {
+                            setShowScrollbar(true);
+                            // thumb height = (container height / content height) * container height
+                            const calculatedThumbHeight = (wrapperHeight / contentHeight) * wrapperHeight;
+                            setThumbHeight(Math.max(calculatedThumbHeight, 20)); // min height 20px
+                        } else {
+                            setShowScrollbar(false);
+                        }
+                    }
+                });
+            }, 300);
+        }
+    }, [noticeContent, visible]);
 
     useEffect(() => {
         if (show && !visible) {
@@ -60,13 +99,36 @@
     if (!visible) return null;
 
     return (
-        <View className='passenger-popup'>
+        <View className='passenger-popup' onClick={() => onCheckedChange?.(true)}>
             <View className='passenger-mask' catchMove></View>
             <View className='passenger-content' animation={animationData}>
                 <View className='passenger-content-title'>乘车需知</View>
-                <ScrollView className='passenger-content-desc' scrollY enhanced lowerThreshold={30} upperThreshold={30} showScrollbar={true}>
-                    <RichText nodes={noticeContent} />
-                </ScrollView>
+                <View className='passenger-content-desc-wrap'>
+                    <ScrollView 
+                        className='passenger-content-desc' 
+                        scrollY 
+                        enhanced 
+                        lowerThreshold={30} 
+                        upperThreshold={30} 
+                        showScrollbar={false}
+                        onScroll={onScroll}
+                    >
+                        <View className='passenger-content-desc-inner'>
+                            <RichText nodes={noticeContent} />
+                        </View>
+                    </ScrollView>
+                    {showScrollbar && (
+                        <View className='custom-scrollbar-track'>
+                            <View 
+                                className='custom-scrollbar-thumb' 
+                                style={{ 
+                                    height: `${thumbHeight}px`,
+                                    transform: `translateY(${thumbTop}px)`
+                                }} 
+                            />
+                        </View>
+                    )}
+                </View>
                 <View onClick={() => setChecked(!checked)} className='passenger-content-checkbox'>
                     {
                         checked ?
diff --git a/src/robotaxi/pages/begin-route/index.tsx b/src/robotaxi/pages/begin-route/index.tsx
index 55433c7..51d3f3f 100644
--- a/src/robotaxi/pages/begin-route/index.tsx
+++ b/src/robotaxi/pages/begin-route/index.tsx
@@ -50,6 +50,7 @@
 import { getOrderDistance } from '../../api/select-map-site';
 import { checkOtp } from '../../../utils/tools';
 import { jumpTo } from '../../../utils/jump';
+import { _ROBOTAXI_WS_HOST } from '../../../constants/api';
 
 export default function SelectMapSite() {
   const WAITING_TIMER_START_KEY = 'waitingTimerStartAt'; // 等待计时开始时间
@@ -756,7 +757,10 @@
         if (durationSeconds !== null) {
           setRouteDuration(durationSeconds);
         }
-        setVehicleDirection(data?.direction);
+        const dir = Number(data?.direction);
+        if (Number.isFinite(dir)) {
+          setVehicleDirection(dir);
+        }
       })
       .catch(() => { });
   };
@@ -923,11 +927,11 @@
         return;
       }
       const points = payload?.points || [];
-      const direction = payload?.direction;
-      if (typeof direction === 'number' && Number.isFinite(direction)) {
+      const direction = Number(payload?.direction);
+      if (Number.isFinite(direction)) {
         setVehicleDirection(direction);
       }
-      const distance = Number(JSON.parse(payload?.content?.route)?.distance);
+      const distance = Number(JSON.parse(payload?.content?.route || '{}')?.distance);
       const duration = Number(JSON.parse(payload?.content?.route)?.duration);
       const distanceKm = normalizeDistanceKm(distance);
       if (distanceKm !== null) {
@@ -954,7 +958,7 @@
             applyRoutePoints(points);
           });
         }
-        
+
         // 延迟执行车辆位置更新,确保路线擦除(同步调用或极短时间生效)先于小车平移发生
         if (firstPoint && typeof firstPoint.latitude === 'number' && typeof firstPoint.longitude === 'number') {
           setTimeout(() => {
@@ -1393,7 +1397,7 @@
     if (!carMarkerInitialized.current) return;
     if (!vehicleLocation) return;
     const mapCtx = Taro.createMapContext('map');
-    
+
     // 增加延迟,确保 markers 已经在原生视图中完成渲染,避免 translateMarker 找不到 markerId 导致 fail
     const timer = setTimeout(() => {
       mapCtx.translateMarker({
@@ -1403,7 +1407,8 @@
           longitude: vehicleLocation.longitude,
         },
         autoRotate: false,
-        rotate: typeof vehicleDirection === 'number' ? vehicleDirection : 0,
+        moveWithRotate: true,
+        rotate: typeof vehicleDirection === 'number' ? Number(vehicleDirection.toFixed(0)) : 0,
         duration: 100,
         fail: (err) => {
           console.log('translateMarker fail:', err, 'markerId:', vehicleMarkerId);
@@ -1445,6 +1450,7 @@
       return;
     }
     if (socketOpenHandlerRef.current) {
+      wsManager.connect(_ROBOTAXI_WS_HOST);
       return;
     }
     const handleOpen = () => {
@@ -1452,6 +1458,7 @@
     };
     socketOpenHandlerRef.current = handleOpen;
     wsManager.on('open', handleOpen);
+    wsManager.connect(_ROBOTAXI_WS_HOST);
   };
 
   // 页面初始化
@@ -1585,14 +1592,16 @@
   // 返回当前位置或车辆位置
   const toOrigin = () => {
     const mapCtx = Taro.createMapContext('map');
-    // 如果是状态6(车辆行驶中)且有车辆位置,则回到车辆位置
-    if (tripStatus === 6 && vehicleLocation?.latitude && vehicleLocation?.longitude) {
-      mapCtx.moveToLocation({
-        latitude: vehicleLocation.latitude,
-        longitude: vehicleLocation.longitude,
+    // 如果是状态6(车辆行驶中)且有路线数据,则展示完整路线
+    if (tripStatus === 6 && routePoints.length > 0) {
+      const bottomPadding = computeBottomPadding(routePoints, 'route');
+      const topPadding = Math.max(24, resolveSafeTopInset() + 32);
+      mapCtx.includePoints({
+        points: routePoints,
+        padding: [topPadding, 100, bottomPadding, 100]
       });
-      // 恢复视口锁定状态,让地图重新跟随车辆
-      tripStatus6ViewportLockedRef.current = false;
+      // 锁定视口状态,防止后续路线数据更新时频繁改变缩放比例
+      tripStatus6ViewportLockedRef.current = true;
     } else {
       mapCtx.moveToLocation();
     }
@@ -1941,6 +1950,9 @@
       url: `/robotaxi/pages/site-search/index?pageType=${pageType}&longitude=${startSite.longitude}&latitude=${startSite.latitude}&electronicAreaId=${startSite.electronicAreaId}`
     })
   }
+  const changeCheckedEnter = (checked: boolean) => {
+    isCheckedEnter.current = checked;
+  }
 
   // 点击气泡
   const handleCalloutTap = (e) => {
@@ -2238,6 +2250,7 @@
         <PassengerNotice
           show={showPassengerNotice}
           onClose={handleClosePassengerNotice}
+          onCheckedChange={changeCheckedEnter}
         />
       }
       {/* 评价弹窗 */}
diff --git a/src/robotaxi/pages/operating-area/index.less b/src/robotaxi/pages/operating-area/index.less
index d4bc76e..7b52db0 100644
--- a/src/robotaxi/pages/operating-area/index.less
+++ b/src/robotaxi/pages/operating-area/index.less
@@ -16,7 +16,6 @@
     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;
diff --git a/src/robotaxi/pages/operating-area/index.tsx b/src/robotaxi/pages/operating-area/index.tsx
index b9d949d..770c03a 100644
--- a/src/robotaxi/pages/operating-area/index.tsx
+++ b/src/robotaxi/pages/operating-area/index.tsx
@@ -27,7 +27,7 @@
     getOpenCity().then((res: any) => {
       const openCities = res.cities || [];
       setCityList(openCities);
-      
+
       const cachedCityCode = cachedSelectedCity?.code;
       const matchedCity = openCities.find((city: any) => (city.code || city.adcode) === cachedCityCode);
 
@@ -240,7 +240,7 @@
         setRawGeofenceData(normalizedGeofenceData);
         const firstPolygonId = normalizedGeofenceData.length > 0 ? normalizedGeofenceData[0].mapPolygonId : null;
         setSelectedPolygonId(firstPolygonId);
-        
+
         if (firstPolygonId !== null) {
           const firstPolygonData = normalizedGeofenceData.find(item => item.mapPolygonId === firstPolygonId);
           setOperatingTimeInfo(firstPolygonData);
@@ -250,14 +250,14 @@
         const newPolygons = updatePolygonsStyle(normalizedGeofenceData, firstPolygonId);
         setPolygons(newPolygons);
         setPolylines(updatePolylineStyle(normalizedGeofenceData, firstPolygonId));
-        
+
         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);
-          
+
           const mapCtx = Taro.createMapContext('map');
           const points = extractPointsFromPolygons(newPolygons);
           if (points.length > 0) {
@@ -293,7 +293,7 @@
     } else if (e.markerId) {
       tapPolygonId = e.markerId;
     }
-    
+
     if (tapPolygonId !== null && rawGeofenceData.length > 0) {
       lastPolygonTapTimeRef.current = Date.now();
       selectPolygon(tapPolygonId, rawGeofenceData);
@@ -326,9 +326,7 @@
   };
 
   const toBack = () => {
-    Taro.navigateBack({
-      delta: 1,
-    });
+    Taro.navigateBack();
   };
 
   const toOrigin = () => {
@@ -339,6 +337,57 @@
         points,
         padding: [10, 10, 10, 10]
       });
+    }
+  };
+
+  const renderOperatingTime = (info: any) => {
+    if (!info?.rule) {
+      return `全天`;
+    }
+
+    try {
+      const rules = JSON.parse(info.rule);
+      if (!Array.isArray(rules) || rules.length === 0) {
+        return `全天`;
+      }
+
+      const getDayText = (typeStr: number[]) => {
+        if (!typeStr || typeStr.length === 0 || typeStr.includes(0)) return '每天';
+        const dayMap = { 1: '周一', 2: '周二', 3: '周三', 4: '周四', 5: '周五', 6: '周六', 7: '周日' };
+        const days = typeStr.map(d => dayMap[d]).filter(Boolean);
+        if (days.length === 7) return '每天';
+        return days.join('、');
+      };
+
+      const parts = rules.map((rule: any) => {
+        let prefix = '';
+        if (rule.type === 0) {
+          prefix = '工作日';
+        } else if (rule.type === 1) {
+          prefix = '节假日';
+        } else if (rule.type === 2) {
+          prefix = '非工作日';
+        } else if (rule.type === 3) {
+          prefix = getDayText(rule.typeStr);
+        }
+
+        let timeStr = '';
+        if (rule.type === 3 && (!rule.time || rule.time.length === 0)) {
+          timeStr = '全天';
+        } else {
+          timeStr = Array.isArray(rule.time) ? rule.time.join(', ') : rule.time;
+        }
+
+        return `${prefix}: ${timeStr}`;
+      });
+      const resultStr = parts.join('     ');
+      if (resultStr.includes('工作日: 全天') && resultStr.includes('非工作日: 全天') || resultStr.includes('每天: 全天') && resultStr.includes('每天: 全天')) {
+        return '';
+      }
+      return resultStr;
+    } catch (e) {
+      console.error('解析围栏规则失败', e);
+      return ``;
     }
   };
 
@@ -357,66 +406,60 @@
         onPolygonTap={handlePolygonTap}
         onTap={handleMapTap}
       >
-        {/* 返回按钮 */}
-        <View onClick={toBack} className="back-btn">
-          <Image className="back-icon" src={backIcon} />
-        </View>
       </Map>
+      {/* 返回按钮 */}
+      <View onClick={toBack} className="back-btn">
+        <Image className="back-icon" src={backIcon} />
+      </View>
 
       {/* 底部面板 */}
-      <View className="bottom-sheet">
-        <Image className="origin-icon" src={originIcon} onClick={toOrigin} />
-        <View className="header">
-          <Text className="title">查看运营区域</Text>
-          {/* <Image onClick={toBack} className="close-icon" src={closeIcon} /> */}
-        </View>
-
-        <ScrollView scrollX className="city-scroll">
-          <View className="city-list">
-            {cityList.map((city, index) => {
-              const code = city.code || city.adcode;
-              return (
-                <View 
-                  key={index}
-                  className={`city-item ${selectedCityCode === code ? 'active' : ''}`}
-                  onClick={() => handleSelectCity(code)}
-                >
-                  {city.name}
-                </View>
-              );
-            })}
-            {/* Fallback mock data if cityList is empty */}
-            {cityList.length === 0 && (
-              <>
-                <View className="city-item active">北京市</View>
-                <View className="city-item">广州市</View>
-                <View className="city-item">佛山市</View>
-              </>
-            )}
+      {
+        cityList.length != 0 &&
+        <View className="bottom-sheet">
+          <Image className="origin-icon" src={originIcon} onClick={toOrigin} />
+          <View className="header">
+            <Text className="title">查看运营区域</Text>
           </View>
-        </ScrollView>
 
-        <View className="content-box">
-          <View className="content-title">区域运营时间:</View>
-          <View className="content-time">
-            工作日: {operatingTimeInfo?.workDayOpenTime || '07:00'}-{operatingTimeInfo?.workDayCloseTime || '22:00'}     周末: {operatingTimeInfo?.weekendOpenTime || '07:00'}-{operatingTimeInfo?.weekendCloseTime || '22:00'}
-          </View>
-          <View className="content-desc">
-            <View className="desc-item">
-              <Text className="index">1.</Text>
-              <Text className="text">在运营时段可正常使用打车服务,非运营时段服务暂停</Text>
+          <ScrollView scrollX className="city-scroll">
+            <View className="city-list">
+              {cityList.map((city, index) => {
+                const code = city.code || city.adcode;
+                return (
+                  <View
+                    key={index}
+                    className={`city-item ${selectedCityCode === code ? 'active' : ''}`}
+                    onClick={() => handleSelectCity(code)}
+                  >
+                    {city.name}
+                  </View>
+                );
+              })}
             </View>
-            <View className="desc-item">
-              <Text className="index">2.</Text>
-              <Text className="text">各站点运营时间可能存在调整,实际运营情况请以页面实时展示为准</Text>
+          </ScrollView>
+
+          <View className="content-box">
+            <View className="content-title">区域运营时间:</View>
+            <View className="content-time">
+              {renderOperatingTime(operatingTimeInfo)}
             </View>
-            <View className="desc-item">
-              <Text className="index">3.</Text>
-              <Text className="text">如有问题,请拨打客服热线xxxxxx</Text>
+            <View className="content-desc">
+              <View className="desc-item">
+                <Text className="index">1.</Text>
+                <Text className="text">在运营时段可正常使用打车服务,非运营时段服务暂停</Text>
+              </View>
+              <View className="desc-item">
+                <Text className="index">2.</Text>
+                <Text className="text">各站点运营时间可能存在调整,实际运营情况请以页面实时展示为准</Text>
+              </View>
+              <View className="desc-item">
+                <Text className="index">3.</Text>
+                <Text className="text">如有问题,请拨打客服热线xxxxxx</Text>
+              </View>
             </View>
           </View>
         </View>
-      </View>
+      }
     </View>
   );
 }
diff --git a/src/robotaxi/pages/select-map-site/index.tsx b/src/robotaxi/pages/select-map-site/index.tsx
index 2e1cdb6..806a7eb 100644
--- a/src/robotaxi/pages/select-map-site/index.tsx
+++ b/src/robotaxi/pages/select-map-site/index.tsx
@@ -455,6 +455,27 @@
     })
   }
 
+  // 处理点击地图 marker
+  const handleMarkerTap = (e: any) => {
+    const markerId = e?.detail?.markerId;
+    if (markerId === undefined) return;
+
+    const targetMarker = markers.find(m => m.id === markerId);
+    if (targetMarker) {
+      const mapCtx = Taro.createMapContext('map');
+      mapCtx.moveToLocation({
+        latitude: targetMarker.latitude,
+        longitude: targetMarker.longitude,
+      });
+
+      setSelectedSite(targetMarker);
+      setOutOfServiceRange(getOutOfServiceRange(isOperatingArea, targetMarker));
+      setLatitude(targetMarker.latitude);
+      setLongitude(targetMarker.longitude);
+      setShowToolTip(true);
+    }
+  };
+
   return (
     <View className="home-container">
       <Map
@@ -462,11 +483,12 @@
         longitude={longitude}
         latitude={latitude}
         scale={14}
-        markers={markers}
+        markers={markers.map(m => ({ ...m, title: '', name: '' }))}
         polyline={polyline}
         polygons={polygons}
         showLocation={!!longitude}
         onRegionChange={handleRegionChange}
+        onMarkerTap={handleMarkerTap}
         style={{ width: '100%', height: '100%' }}
       >
         {/* 返回 */}
diff --git a/src/robotaxi/pages/site-search/index.less b/src/robotaxi/pages/site-search/index.less
index 1bff2c5..41b81bf 100644
--- a/src/robotaxi/pages/site-search/index.less
+++ b/src/robotaxi/pages/site-search/index.less
@@ -180,7 +180,7 @@
     }
 
     .card-content {
-      padding: 16px 24px;
+      padding: 16px 0;
     }
   }
 
diff --git a/src/robotaxi/pages/site-search/index.tsx b/src/robotaxi/pages/site-search/index.tsx
index a79875b..0159ddb 100644
--- a/src/robotaxi/pages/site-search/index.tsx
+++ b/src/robotaxi/pages/site-search/index.tsx
@@ -460,9 +460,24 @@
       }
       {
         (!siteList.length && (!searchValue ? !nearbySiteList.length : true) && !nonOperationalSite.length && (!searchValue ? !historySite.length : true)) &&
-        <View className='no-data-box'>
-          <Image className='no-data-image' src={require('../../assets/no-data-site.png')} />
-          <View>暂无站点</View>
+        <View className='history-card'>
+          <View className='card-header'>暂无搜索结果,为您推荐附近站点</View>
+          <View className='card-content list-content'>
+            {
+              filteredNearbyList.slice(0, MAX_EXPANDED_COUNT).map((item, index) => {
+                return <View hoverClass='common-hover-class' onClick={() => onChangeSelectSite(item)} className='history-item' key={item.id || index}>
+                  <Image className='history-icon' src={address}></Image>
+                  <View className='history-info'>
+                    <View className='history-name'>{item.name || '_'}</View>
+                    <View className='history-address-box'>
+                      <View className='history-address'>{item.address || '-'}</View>
+                      <View className='history-distance'>{item.distance}</View>
+                    </View>
+                  </View>
+                </View>
+              })
+            }
+          </View>
         </View>
       }
       <TipPopup

--
Gitblit v1.7.1