hejianhao
2026-03-15 9bc666dcaafc88777d7d5e1b9cf9c1ce2c3cd10a
fix: 修复多个页面样式、逻辑及API调用问题

- 将查询订单轨迹的API方法从POST改为GET
- 修复选择城市页面的搜索结果布局和滚动问题
- 为多个页面的富文本图片添加自适应样式
- 修复订单详情页评价弹窗关闭时地图状态异常
- 修复站点搜索页的距离格式化及缓存逻辑
- 优化首页系统维护状态判断逻辑
- 修复行程页面地图缩放、复位按钮及气泡显示问题
- 优化叫车组件倒计时缓存和费用明细显示
12个文件已修改
168 ■■■■■ 已修改文件
src/pages/robotaxi/home/index.tsx 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/api/begin-route.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/calling-car.tsx 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/passenger-notice.tsx 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/index.tsx 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/coupon/index.tsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/order/detail/index.tsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/passenger-notice/index.tsx 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/pricing-rules/index.tsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/select-city/index.less 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/select-city/index.tsx 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/site-search/index.tsx 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/robotaxi/home/index.tsx
@@ -283,24 +283,11 @@
      if (!s) return NaN;
      return new Date(s.replace(/-/g, '/')).getTime();
    };
    const formatEnd = (s: string) => {
      if (!s) return '';
      const d = new Date(s.replace(/-/g, '/'));
      if (isNaN(d.getTime())) return '';
      const hh = String(d.getHours()).padStart(2, '0');
      const mm = String(d.getMinutes()).padStart(2, '0');
      return `${hh}:${mm}`;
    };
    const check = () => {
      getHotFixInfo().then((res: any) => {
        const status = Number(res?.hotfixStatus ?? res?.data?.hotfixStatus ?? 0);
        const start = parseTime(res?.hotfixStartTime ?? res?.data?.hotfixStartTime ?? '');
        const end = parseTime(res?.hotfixEndTime ?? res?.data?.hotfixEndTime ?? '');
        const endRaw = res?.hotfixEndTime ?? res?.data?.hotfixEndTime ?? '';
        const now = Date.now();
        if (status === 1 && Number.isFinite(start) && Number.isFinite(end) && now >= start && now <= end) {
        if (status === 1 ) {
          setIsMaintain(true);
          setHotfixEndText(formatEnd(endRaw));
          setHotfixEndText(res?.hotfixEndTime);
        } else {
          setIsMaintain(false);
          setHotfixEndText('');
@@ -1101,7 +1088,7 @@
            }
            {/* 系统维护 */}
            {
              isMaintain && <View className={`is-maintain ml-32 ${maintainBounce ? 'maintain-bounce' : ''}`}>系统维护中,预计今日{hotfixEndText || '-:-'}恢复服务</View>
              isMaintain && <View className={`is-maintain ml-32 ${maintainBounce ? 'maintain-bounce' : ''}`}>系统维护中,预计{hotfixEndText || '-:-'}恢复服务</View>
            }
            {/* 查看运营区域 */}
            {
src/robotaxi/api/begin-route.ts
@@ -144,7 +144,7 @@
export const queryOrderTrajectory = async (payload) => {
    return request({
        url: _ROBOTAXI_HOST + `/order/api/v1/mini-program/order/queryOrderTrajectory`,
        method: 'POST',
        method: 'GET',
        payload
    });
}
src/robotaxi/pages/begin-route/components/calling-car.tsx
@@ -8,7 +8,17 @@
import activeGood from '../../../assets/active-good.png'
import activeBad from '../../../assets/active-bad.png'
import activeNormal from '../../../assets/active-normal.png'
import { formatCountdown, getRemainingSeconds, parseFlexibleEndTimeMs, formatDurationDisplay, formatNumber, getTypeLabel, formatMoney, formatTripDistance, formatTripDurationFromSeconds } from '../../../../utils/Robotaxi-public-method';
import {
    formatCountdown,
    getRemainingSeconds,
    parseFlexibleEndTimeMs,
    formatDurationDisplay,
    formatNumber,
    getTypeLabel,
    formatMoney,
    formatTripDistance,
    formatTripDurationFromSeconds
} from '../../../../utils/Robotaxi-public-method';
import {
    getWaitTime,
    setTemperature,
@@ -89,6 +99,7 @@
    const lastFareOrderIdRef = useRef<string | null>(null);
    const hasShownAnnouncementsRef = useRef(false); // 是否已展示过公告弹窗
    const PICKUP_END_TIME_KEY = 'pickupEndTime'; // 上车点限停结束时间缓存键
    const FINISH_END_TIME_KEY = 'finishEndTime'; // 到达目的地倒计时结束时间缓存键
    const TEMP_MIN = 22;
    const TEMP_MAX = 28;
@@ -226,11 +237,18 @@
                }
                finishEndTimeRef.current = null;
                setFinishCountdownSeconds(null);
                Taro.removeStorageSync(FINISH_END_TIME_KEY);
                return;
            }
            queryOrderFinishTime().then((res: any) => {
                const endTimeMs = parseFlexibleEndTimeMs(res);
            const cachedEndTime = Taro.getStorageSync(FINISH_END_TIME_KEY);
            const hasValidCached = typeof cachedEndTime === 'number' && cachedEndTime > Date.now();
            const initFinishCountdown = (endTimeMs: number | null) => {
                finishEndTimeRef.current = endTimeMs;
                if (typeof endTimeMs === 'number' && endTimeMs > Date.now()) {
                    Taro.setStorageSync(FINISH_END_TIME_KEY, endTimeMs);
                } else {
                    Taro.removeStorageSync(FINISH_END_TIME_KEY);
                }
                const remainingSeconds = getRemainingSeconds(endTimeMs);
                if (remainingSeconds === null) {
                    setFinishCountdownSeconds(null);
@@ -247,6 +265,7 @@
                            clearTimeout(finishCountdownTimerRef.current);
                        }
                        setFinishCountdownSeconds(0);
                        Taro.removeStorageSync(FINISH_END_TIME_KEY);
                        handleFinishTimeout?.();
                        return;
                    }
@@ -260,11 +279,21 @@
                    finishCountdownTimerRef.current = setTimeout(scheduleFinishTick, delay);
                };
                scheduleFinishTick();
            };
            if (hasValidCached) {
                initFinishCountdown(cachedEndTime);
                return;
            }
            queryOrderFinishTime().then((res: any) => {
                const endTimeMs = parseFlexibleEndTimeMs(res);
                initFinishCountdown(endTimeMs);
            }).catch(() => {
                setFinishCountdownSeconds(null);
                finishEndTimeRef.current = null;
                Taro.removeStorageSync(FINISH_END_TIME_KEY);
            });
        } else if (tripStatus === 8 || tripStatus === 9) {
            Taro.removeStorageSync(FINISH_END_TIME_KEY);
            const targetOrderId = orderId || Taro.getStorageSync('orderId');
            if (targetOrderId && lastFareOrderIdRef.current !== targetOrderId) {
                lastFareOrderIdRef.current = targetOrderId;
@@ -276,6 +305,9 @@
        }
        return () => {
            isActive = false;
            if (tripStatus === 7 && finishCountdownEnabled && typeof finishEndTimeRef.current === 'number' && finishEndTimeRef.current > Date.now()) {
                Taro.setStorageSync(FINISH_END_TIME_KEY, finishEndTimeRef.current);
            }
            if (countdownTimerRef.current) {
                clearTimeout(countdownTimerRef.current);
            }
@@ -608,7 +640,7 @@
                                        </View>
                                        {fareBreakdown.mileage.filter((item: any) => item?.money || item?.mileage).map((item: any, index: number) => (
                                            <View key={`mileage-${index}`} className="particulars-detail-item-content">
                                                <View>{getTypeLabel(item?.type)}({formatNumber(item?.mileage)}公里)</View>
                                                <View>{getTypeLabel(item?.type)}({formatTripDistance(item?.mileage)})</View>
                                                <View>{formatMoney(item?.money)}元</View>
                                            </View>
                                        ))}
@@ -636,7 +668,7 @@
                                        </View>
                                        {fareBreakdown.longDistance.filter((item: any) => item?.money || item?.mileage).map((item: any, index: number) => (
                                            <View key={`long-${index}`} className="particulars-detail-item-content">
                                                <View>{getTypeLabel(item?.type)}({formatNumber(item?.mileage)}公里)</View>
                                                <View>{getTypeLabel(item?.type)}({formatTripDistance(item?.mileage)})</View>
                                                <View>{formatMoney(item?.money)}元</View>
                                            </View>
                                        ))}
src/robotaxi/pages/begin-route/components/passenger-notice.tsx
@@ -43,6 +43,10 @@
            return;
        }
        getPrivacyContent(5).then((res: any) => {
            if (res.content) {
                res.content = res.content.replace(/<img/gi,
                    '<img style="max-width:100%;height:auto;margin:0 auto;display:block"')
            }
            setNoticeContent(res.content);
        }).catch(() => { });
    }, [show]);
src/robotaxi/pages/begin-route/index.tsx
@@ -104,6 +104,7 @@
  const [carCalloutStyle, setCarCalloutStyle] = useState<any>({});
  const [carCalloutVisible, setCarCalloutVisible] = useState(false);
  const [distanceConfig, setDistanceConfig] = useState<any>({});
  const [mapScale, setMapScale] = useState(14);
  const markersRef = useRef<any[]>([]);
  const tripStatusRef = useRef(tripStatus); // 行程状态引用
@@ -1089,6 +1090,11 @@
        points,
        padding
      });
      if (viewportType === 'dropoff') {
        setTimeout(() => {
          setMapScale(13);
        }, 50);
      }
    });
    if (tripStatus === 6 && viewportType === 'route') {
      tripStatus6ViewportLockedRef.current = true;
@@ -1474,8 +1480,6 @@
  };
  // 打开取消弹窗
  const handleOpenCancelPopupByTripStatus = (status: number, durationDisplay?: any) => {
    console.log(status);
    if (durationDisplay) {
      setCancelType(2);
      setShowCancelPopup(true);
@@ -1648,7 +1652,7 @@
        id="map"
        longitude={mapLongitude}
        latitude={mapLatitude}
        scale={14}
        scale={mapScale}
        markers={markers}
        polyline={polyline}
        showLocation={!!longitude}
@@ -1690,7 +1694,11 @@
                {
                  (!['车辆位置', '已到达'].includes(item.name)) &&
                  <CoverView className={`custom-callout-content`}>
                    {item.name}<CoverView style={{ width: '2px' }}></CoverView>
                    {item.name}
                    {
                      !isAndroid &&
                      <CoverView style={{ width: '2px' }}></CoverView>
                    }
                    {
                      tripStatus == 1 && <CoverImage className="custom-callout-icon" src={customCalloutIconSrc} />
                    }
@@ -1748,7 +1756,7 @@
          <View className="container-inner">
            {/* 复位按钮 */}
            {
              [7, 8, 9].includes(tripStatus) &&
              ![7, 8, 9].includes(tripStatus) &&
              <View className="origin-box" style={{ opacity: originBoxHidden ? 0 : originOpacity, transition: 'opacity 0.2s ease-out', pointerEvents: originBoxHidden ? 'none' : 'auto' }}>
                <Image onClick={toOrigin} className="origin-icon" src={originIcon} />
              </View>
src/robotaxi/pages/coupon/index.tsx
@@ -72,6 +72,10 @@
    try {
      Taro.showLoading({ title: '加载中...' });
      const detail = await getCouponDetail(item.couponId);
      if (detail.couponDesc) {
        detail.couponDesc = detail.couponDesc.replace(/<img/gi,
          '<img style="max-width:100%;height:auto;margin:0 auto;display:block"')
      }
      setCurrentCoupon(detail);
      Taro.hideLoading();
@@ -190,7 +194,7 @@
          </View>
          <View className='remark-card'>
            <Text className='remark-label'>使用说明</Text>
            <Text className='remark-value'><RichText nodes={currentCoupon.decodeURIComponent} /></Text>
            <Text className='remark-value'><RichText nodes={currentCoupon.couponDesc} /></Text>
          </View>
        </View>
src/robotaxi/pages/order/detail/index.tsx
@@ -1,5 +1,5 @@
import Taro, { useRouter, useDidShow, useDidHide } from '@tarojs/taro';
import { useState, useEffect } from 'react';
import Taro, { useRouter, useDidHide } from '@tarojs/taro';
import { useState, useEffect, useRef } from 'react';
import { View, Text, Image, Map } from '@tarojs/components';
import './index.less';
import good from '../../../assets/good.png'
@@ -22,6 +22,7 @@
  const [activeIndex, setActiveIndex] = useState<number | null>(null) // 默认选中"非常满意"
  const [orderData, setOrderData] = useState<OrderDetail | null>(null);
  const [showEvaluatePopup, setShowEvaluatePopup] = useState(false);
  const showEvaluatePopupRef = useRef(false);
  // 地图相关状态
  const [longitude, setLongitude] = useState(116.397128) // 地图中心点经度
@@ -52,7 +53,14 @@
    }
  }, [orderId]);
  useEffect(() => {
    showEvaluatePopupRef.current = showEvaluatePopup;
  }, [showEvaluatePopup]);
  useDidHide(() => {
    if (showEvaluatePopupRef.current) {
      return;
    }
    setMarkers([]);
    setPolyline([]);
    setLongitude(116.397128);
src/robotaxi/pages/passenger-notice/index.tsx
@@ -20,6 +20,10 @@
    };
    setTitle(titleMap[type] || '乘车须知');
    getPrivacyContent(type).then((res: any) => {
      if (res.content) {
        res.content = res.content.replace(/<img/gi,
          '<img style="max-width:100%;height:auto;margin:0 auto;display:block"')
      }
      setContent(res?.content);
    }).catch(() => { });
  }, []);
src/robotaxi/pages/pricing-rules/index.tsx
@@ -22,7 +22,12 @@
    try {
      setLoading(true);
      const res: any = await getPricingRules(cityId);
      setPricingHtml(res);
      let pricingContent = res;
      if (pricingContent) {
        pricingContent = pricingContent.replace(/<img/gi,
          '<img style="max-width:100%;height:auto;margin:0 auto;display:block"')
      }
      setPricingHtml(pricingContent);
    } catch (error) {
      console.error('获取定价规则失败', error);
      Taro.showToast({
src/robotaxi/pages/select-city/index.less
@@ -216,7 +216,8 @@
    }
    .search-result-box {
        margin: 32px;
        padding: 32px;
        box-sizing: border-box;
        .search-result-item {
            display: flex;
@@ -248,6 +249,11 @@
        }
    }
    .search-result-scroll {
        flex: 1;
        min-height: 0;
    }
    .no-data-box {
        display: flex;
        flex-direction: column;
src/robotaxi/pages/select-city/index.tsx
@@ -220,22 +220,24 @@
          {/* 搜索后 */}
          {
            searchValue &&
            <View>
            <View className='city-content'>
              {
                searchResultList.length > 0 ?
                  <View className='search-result-box'>
                    {
                      searchResultList.map((item, index) => {
                        const isOpen = openCityList.some(open => open.name === item.name);
                        return (
                          <View key={index} className='search-result-item' onClick={() => handleSelectCity(item, isOpen)}>
                            <View className='search-result-city'>{item.name}</View>
                            <View className={`search-result-zone ${!isOpen ? 'search-result-zone-disabled' : ''}`}>{isOpen ? '运营区' : '待开放'}</View>
                          </View>
                        )
                      })
                    }
                  </View>
                  <ScrollView className='search-result-scroll' scrollY>
                    <View className='search-result-box'>
                      {
                        searchResultList.map((item, index) => {
                          const isOpen = openCityList.some(open => open.name === item.name);
                          return (
                            <View key={index} className='search-result-item' onClick={() => handleSelectCity(item, isOpen)}>
                              <View className='search-result-city'>{item.name}</View>
                              <View className={`search-result-zone ${!isOpen ? 'search-result-zone-disabled' : ''}`}>{isOpen ? '运营区' : '待开放'}</View>
                            </View>
                          )
                        })
                      }
                    </View>
                  </ScrollView>
                  :
                  <View className='no-data-box'>
                    <Image className='no-data-image' src={require('../../assets/no-data-city.png')} />
src/robotaxi/pages/site-search/index.tsx
@@ -131,7 +131,7 @@
      if (Array.isArray(availablePoints)) {
        const list = availablePoints.map(item => ({
          ...item,
          distance: item.distance
          distance: formatDistance(item.distance)
        }));
        setSiteList(list.slice(0, MAX_EXPANDED_COUNT));
      } else {
@@ -323,16 +323,20 @@
    }
  }
  const startSiteCache = pageType === 'end' || pageType === 'start' ? Taro.getStorageSync('startSite') : null;
  const filteredNearbyList = startSiteCache
  const currentSiteCache = pageType === 'start'
    ? Taro.getStorageSync('startSite')
    : pageType === 'end'
      ? Taro.getStorageSync('endSite')
      : null;
  const filteredNearbyList = currentSiteCache
    ? nearbySiteList.filter((item: any) => {
      const startId = startSiteCache?.id;
      const startId = currentSiteCache?.id;
      const itemId = item?.id;
      if (startId && itemId) {
        return String(startId) !== String(itemId);
      }
      const startLng = Number(startSiteCache?.longitude);
      const startLat = Number(startSiteCache?.latitude);
      const startLng = Number(currentSiteCache?.longitude);
      const startLat = Number(currentSiteCache?.latitude);
      const itemLng = Number(item?.longitude);
      const itemLat = Number(item?.latitude);
      if (!Number.isNaN(startLng) && !Number.isNaN(startLat) && !Number.isNaN(itemLng) && !Number.isNaN(itemLat)) {