From 13c960a2b6bb54797bdbd03aa3184af507d94a9b Mon Sep 17 00:00:00 2001
From: 卢春龙 <lucl@xiaopeng.com>
Date: 星期一, 20 四月 2026 10:42:28 +0800
Subject: [PATCH] Merge branch 'feature_pr_fix' into 'develop'

---
 src/robotaxi/pages/site-search/hooks/use-site-search.ts |  111 ++++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 85 insertions(+), 26 deletions(-)

diff --git a/src/robotaxi/pages/site-search/hooks/use-site-search.ts b/src/robotaxi/pages/site-search/hooks/use-site-search.ts
index df70be5..8f8b302 100644
--- a/src/robotaxi/pages/site-search/hooks/use-site-search.ts
+++ b/src/robotaxi/pages/site-search/hooks/use-site-search.ts
@@ -1,7 +1,6 @@
 import Taro from '@tarojs/taro';
 import { useEffect, useMemo, useRef, useState } from 'react';
 import { getStartPoints, getEndPoints, queryPointByName } from '../../../api/site-search';
-import { debounce } from '../../../../utils/Robotaxi-public-method';
 import { checkOtp } from '../../../../utils/tools';
 import { getNearestSite } from '../../../api/home';
 import { _AMAP_KEY } from '../../../../constants/api';
@@ -30,6 +29,12 @@
   const [nearbySiteList, setNearbySiteList] = useState<any[]>([]);
   // 页面类型(start/end)
   const [pageType, setPageType] = useState('');
+  // 当前关键词是否仍在搜索中(含高德补充结果)
+  const [isSearching, setIsSearching] = useState(false);
+  // 最近一次完成搜索的关键词
+  const [lastCompletedKeyword, setLastCompletedKeyword] = useState('');
+  const searchSeqRef = useRef(0);
+  const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
 
   // 拉取附近站点
   const fetchNearbySites = async (lat: number, lon: number, electronicAreaId?: string) => {
@@ -50,9 +55,17 @@
 
   // 站点搜索请求与结果处理
   const searchSite = async (val?: string) => {
-    setNonOperationalSite([]);
     const queryVal = val !== undefined ? val : deps.searchValue;
-    if (!queryVal) return;
+    const normalizedQuery = String(queryVal || '').trim();
+    searchSeqRef.current += 1;
+    const requestSeq = searchSeqRef.current;
+    setNonOperationalSite([]);
+    if (!normalizedQuery) {
+      setIsSearching(false);
+      setLastCompletedKeyword('');
+      return;
+    }
+    setIsSearching(true);
     const { latitude, longitude, electronicAreaId } = deps.router.params;
     const selectedCity = Taro.getStorageSync('selectedCity');
     const payload = {
@@ -60,42 +73,63 @@
       electronicAreaId: electronicAreaId ? Number(electronicAreaId) : 0,
       lat: Number(latitude),
       lon: Number(longitude),
-      pointPoi: queryVal
+      pointPoi: normalizedQuery
     };
     try {
       const res = await queryPointByName(payload);
+      if (requestSeq !== searchSeqRef.current) return;
       const { availablePoints } = res;
       if (Array.isArray(availablePoints)) {
         const list = availablePoints.map(normalizeSiteItem);
-        const sorted = sortSitesByNameMatchAndDistance(list, queryVal);
+        const sorted = sortSitesByNameMatchAndDistance(list, normalizedQuery);
         setSiteList(sorted.slice(0, deps.maxExpandedCount));
       } else {
         setSiteList([]);
       }
       const myAmapFun = new amapFile.AMapWX({ key: _AMAP_KEY });
-      myAmapFun.getPoiAround({
-        querykeywords: queryVal,
-        location: `${longitude},${latitude}`,
-        success: (data: any) => {
-          if (data && data.poisData) {
-            const list = data.poisData.map((item: any) => {
-              const locationArr = item.location.split(',');
-              return {
-                ...item,
-                longitude: Number(locationArr[0]),
-                latitude: Number(locationArr[1]),
-                ...normalizeSiteItem(item)
-              };
-            });
-            const sorted = sortSitesByNameMatchAndDistance(list, queryVal);
-            setNonOperationalSite(sorted.slice(0, deps.maxShowCount));
+      await new Promise<void>((resolve) => {
+        myAmapFun.getPoiAround({
+          querykeywords: normalizedQuery,
+          location: `${longitude},${latitude}`,
+          success: (data: any) => {
+            if (requestSeq !== searchSeqRef.current) {
+              resolve();
+              return;
+            }
+            if (data && data.poisData) {
+              const list = data.poisData.map((item: any) => {
+                const locationArr = item.location.split(',');
+                return {
+                  ...item,
+                  longitude: Number(locationArr[0]),
+                  latitude: Number(locationArr[1]),
+                  ...normalizeSiteItem(item)
+                };
+              });
+              const sorted = sortSitesByNameMatchAndDistance(list, normalizedQuery);
+              setNonOperationalSite(sorted.slice(0, deps.maxShowCount));
+            } else {
+              setNonOperationalSite([]);
+            }
+            resolve();
+          },
+          fail: () => {
+            if (requestSeq === searchSeqRef.current) {
+              setNonOperationalSite([]);
+            }
+            resolve();
           }
-        },
-        fail: () => { }
+        });
       });
     } catch {
+      if (requestSeq !== searchSeqRef.current) return;
       setSiteList([]);
       setNonOperationalSite([]);
+    } finally {
+      if (requestSeq === searchSeqRef.current) {
+        setIsSearching(false);
+        setLastCompletedKeyword(normalizedQuery);
+      }
     }
   };
 
@@ -103,15 +137,38 @@
   searchSiteRef.current = searchSite;
 
   // 搜索输入防抖
-  const debouncedSearch = useMemo(() => debounce((val) => {
-    searchSiteRef.current(val);
-  }, 300), []);
+  const debouncedSearch = useMemo(() => {
+    return (val: string) => {
+      if (debounceTimerRef.current) {
+        clearTimeout(debounceTimerRef.current);
+      }
+      debounceTimerRef.current = setTimeout(() => {
+        searchSiteRef.current(val);
+      }, 300);
+    };
+  }, []);
 
   // 清空搜索结果列表
   const clearSearchResults = () => {
+    if (debounceTimerRef.current) {
+      clearTimeout(debounceTimerRef.current);
+      debounceTimerRef.current = null;
+    }
+    // 推进请求序号,使清空前已发出的请求结果失效
+    searchSeqRef.current += 1;
     setSiteList([]);
     setNonOperationalSite([]);
+    setIsSearching(false);
+    setLastCompletedKeyword('');
   };
+
+  useEffect(() => {
+    return () => {
+      if (debounceTimerRef.current) {
+        clearTimeout(debounceTimerRef.current);
+      }
+    };
+  }, []);
 
   // 初始化:拉取附近站点、历史记录、页面类型
   useEffect(() => {
@@ -145,6 +202,8 @@
     historySite,
     nonOperationalSite,
     nearbySiteList,
+    isSearching,
+    lastCompletedKeyword,
     searchSite,
     debouncedSearch,
     clearSearchResults

--
Gitblit v1.7.1