hejianhao
2026-03-19 4751388366054fd8c062b6f01dc308ec4cf3ffe3
fix(robotaxi): 修复行程结束文案、优惠券显示及位置更新逻辑

- 修正结束行程弹窗中的多余字符“开”
- 优化优惠券和折扣显示逻辑,避免零值显示
- 为路线和车辆位置更新添加节流函数,减少不必要的渲染
- 修复取消弹窗和评价弹窗的交互细节
- 改进地图定位授权处理逻辑,增强用户体验
9个文件已修改
432 ■■■■■ 已修改文件
src/pages/robotaxi/home/index.tsx 247 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/calling-car.tsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/cancel-popup.tsx 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/css-folder/evaluate-popup.less 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/evaluate-popup.tsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/over-route.tsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/index.tsx 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/expense-detail/index.tsx 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/Robotaxi-public-method.ts 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/robotaxi/home/index.tsx
@@ -222,84 +222,61 @@
      success: (res) => {
        const auth = res.authSetting['scope.userLocation'];
        console.log('getSetting获取scope.userLocation授权状态', auth);
        const startSite = Taro.getStorageSync('startSite');
        const hasStartSite = startSite && startSite.latitude && startSite.longitude;
        if (auth === false) {
          setIsLocationAuthDenied(true);
        } else {
          setIsLocationAuthDenied(false);
        }
        if (hasStartSite) {
          if (isCitySwitchingRef.current) {
            isCitySwitchingRef.current = false;
            const shouldMoveToCityCenter = shouldMoveToSwitchedCityCenterRef.current;
            shouldMoveToSwitchedCityCenterRef.current = false;
            if (shouldMoveToCityCenter) {
              return;
            }
          }
          setLatitude(startSite.latitude);
          setLongitude(startSite.longitude);
          setCurrentSite(startSite);
          setIsAdsorbed(true);
          shouldIgnoreRegionChange.current = true;
          const cachedCity = Taro.getStorageSync('selectedCity');
          if (cachedCity?.code) {
            updateMapData(startSite.latitude, startSite.longitude, cachedCity.code);
          } else {
            ensureSelectedCityReady(startSite.longitude, startSite.latitude, true).then((cityInfo) => {
              if (cityInfo?.code) {
                updateMapData(startSite.latitude, startSite.longitude, cityInfo.code);
              }
            });
          }
          return;
        }
        if (auth === false) {
          setMapScale(3);
          setLatitude(DEFAULT_LATITUDE);
          setLongitude(DEFAULT_LONGITUDE);
          return;
        }
        if (auth == undefined) {
          getLocationInfo();
          // skipCityChangeEffectRef.current = true;
          return;
        }
        if (auth === false) {
          setIsLocationAuthDenied(true);
          setMapScale(3);
          setLatitude(DEFAULT_LATITUDE);
          setLongitude(DEFAULT_LONGITUDE);
          return;
        } else {
          setIsLocationAuthDenied(false);
          // 检查缓存中是否有 startSite
          const startSite = Taro.getStorageSync('startSite');
          if (startSite && startSite.latitude && startSite.longitude) {
            if (isCitySwitchingRef.current) {
              isCitySwitchingRef.current = false;
              const shouldMoveToCityCenter = shouldMoveToSwitchedCityCenterRef.current;
              shouldMoveToSwitchedCityCenterRef.current = false;
              if (shouldMoveToCityCenter) {
                return;
              }
            }
            setLatitude(startSite.latitude);
            setLongitude(startSite.longitude);
            setCurrentSite(startSite);
            setIsAdsorbed(true);
            shouldIgnoreRegionChange.current = true;
            const cachedCity = Taro.getStorageSync('selectedCity');
            if (cachedCity?.code) {
              updateMapData(startSite.latitude, startSite.longitude, cachedCity.code);
            } else {
              ensureSelectedCityReady(startSite.longitude, startSite.latitude, true).then((cityInfo) => {
                if (cityInfo?.code) {
                  updateMapData(startSite.latitude, startSite.longitude, cityInfo.code);
                }
              });
            }
          } else {
            if (isCitySwitchingRef.current) {
              isCitySwitchingRef.current = false;
              const shouldMoveToCityCenter = shouldMoveToSwitchedCityCenterRef.current;
              shouldMoveToSwitchedCityCenterRef.current = false;
              if (!shouldMoveToCityCenter) {
                const shouldUpdateCenter = !skipNextLocationCenterRef.current;
                skipNextLocationCenterRef.current = false;
                const hasEntered = Taro.getStorageSync(FIRST_ENTER_KEY) === 'true';
                if (!hasEntered) {
                  skipFenceIncludePointsRef.current = true;
                  getLocationInfo(true);
                  Taro.setStorageSync(FIRST_ENTER_KEY, 'true');
                  return;
                }
                getLocationInfo(shouldUpdateCenter);
                return;
              }
              const switchedCity = Taro.getStorageSync('selectedCity');
              if (switchedCity?.name) {
                getCityLocation(switchedCity.name).then((loc) => {
                  shouldIgnoreRegionChange.current = true;
                  skipNextLocationCenterRef.current = true;
                  const mapCtx = Taro.createMapContext('map');
                  mapCtx.moveToLocation({
                    latitude: loc.latitude,
                    longitude: loc.longitude,
                  });
                  if (switchedCity?.code) {
                    updateMapData(loc.latitude, loc.longitude, switchedCity.code);
                  }
                }).catch(() => {
                  skipNextLocationCenterRef.current = true;
                });
              } else {
                skipNextLocationCenterRef.current = true;
              }
              return;
            }
        if (isCitySwitchingRef.current) {
          isCitySwitchingRef.current = false;
          const shouldMoveToCityCenter = shouldMoveToSwitchedCityCenterRef.current;
          shouldMoveToSwitchedCityCenterRef.current = false;
          if (!shouldMoveToCityCenter) {
            const shouldUpdateCenter = !skipNextLocationCenterRef.current;
            skipNextLocationCenterRef.current = false;
            const hasEntered = Taro.getStorageSync(FIRST_ENTER_KEY) === 'true';
@@ -310,8 +287,40 @@
              return;
            }
            getLocationInfo(shouldUpdateCenter);
            return;
          }
          const switchedCity = Taro.getStorageSync('selectedCity');
          if (switchedCity?.name) {
            getCityLocation(switchedCity.name).then((loc) => {
              shouldIgnoreRegionChange.current = true;
              skipNextLocationCenterRef.current = true;
              const mapCtx = Taro.createMapContext('map');
              mapCtx.moveToLocation({
                latitude: loc.latitude,
                longitude: loc.longitude,
              });
              if (switchedCity?.code) {
                updateMapData(loc.latitude, loc.longitude, switchedCity.code);
              }
            }).catch(() => {
              skipNextLocationCenterRef.current = true;
            });
          } else {
            skipNextLocationCenterRef.current = true;
          }
          return;
        }
        const shouldUpdateCenter = !skipNextLocationCenterRef.current;
        skipNextLocationCenterRef.current = false;
        const hasEntered = Taro.getStorageSync(FIRST_ENTER_KEY) === 'true';
        if (!hasEntered) {
          skipFenceIncludePointsRef.current = true;
          getLocationInfo(true);
          Taro.setStorageSync(FIRST_ENTER_KEY, 'true');
          return;
        }
        getLocationInfo(shouldUpdateCenter);
      }
    });
  });
@@ -583,9 +592,40 @@
            const auth = res.authSetting['scope.userLocation'];
            if (auth === false || auth === undefined) {
              setIsLocationAuthDenied(true);
              setMapScale(3);
              setLatitude(DEFAULT_LATITUDE);
              setLongitude(DEFAULT_LONGITUDE);
              const startSite = Taro.getStorageSync('startSite');
              if (startSite && startSite.latitude && startSite.longitude) {
                setLatitude(startSite.latitude);
                setLongitude(startSite.longitude);
                setCurrentSite(startSite);
                setIsAdsorbed(true);
                shouldIgnoreRegionChange.current = true;
                const cachedCity = Taro.getStorageSync('selectedCity');
                if (cachedCity?.code) {
                  updateMapData(startSite.latitude, startSite.longitude, cachedCity.code);
                } else {
                  ensureSelectedCityReady(startSite.longitude, startSite.latitude, true).then((cityInfo) => {
                    if (cityInfo?.code) {
                      updateMapData(startSite.latitude, startSite.longitude, cityInfo.code);
                    }
                  });
                }
              } else {
                const cachedCity = Taro.getStorageSync('selectedCity');
                if (cachedCity?.name) {
                  getCityLocation(cachedCity.name).then((loc) => {
                    setLatitude(loc.latitude);
                    setLongitude(loc.longitude);
                  }).catch(() => {
                    setMapScale(3);
                    setLatitude(DEFAULT_LATITUDE);
                    setLongitude(DEFAULT_LONGITUDE);
                  });
                } else {
                  setMapScale(3);
                  setLatitude(DEFAULT_LATITUDE);
                  setLongitude(DEFAULT_LONGITUDE);
                }
              }
              return;
            }
            setIsLocationAuthDenied(false);
@@ -663,9 +703,31 @@
    if (isLocationAuthDenied) return;
    shouldIgnoreRegionChange.current = false;
    isReturningToOrigin.current = true;
    // 强制触发缩放更新:如果当前是16,则设置为16.000001以触发props变化
    setMapScale(prev => Math.abs(prev - 16) < 0.001 ? 16.000001 : 16);
    const mapCtx = Taro.createMapContext('map');
    // 解决 Taro/微信小程序中 scale 状态未同步导致重新设置相同 scale 不生效的问题
    // 我们先将 scale 设置为一个临时值,然后再在下一个事件循环中设置为目标值 16
    mapCtx.getScale({
      success: (res) => {
        if (Math.abs(res.scale - 16) > 0.1) {
          // 如果当前不是 16,直接设置可能因为 React 状态缓存问题不生效
          // 我们可以先设置为当前实际值的一个微调,然后再设为 16
          setMapScale(res.scale);
          setTimeout(() => {
            setMapScale(16);
          }, 50);
        } else {
          // 如果已经是 16 附近,强制触发微调
          setMapScale(prev => {
            if (prev === 16) return 16.000001;
            if (prev === 16.000001) return 16.000002;
            return 16;
          });
        }
      }
    });
    mapCtx.moveToLocation();
    try {
      const loc = await Taro.getLocation({ type: 'gcj02' });
@@ -755,27 +817,22 @@
      mapCtx.getCenterLocation({
        success: async (res) => {
          const { latitude: lat, longitude: lng } = res;
          // 移除 setLatitude 和 setLongitude,避免拖动后地图中心点跳动回旧位置
          // if (causedBy === 'gesture' || causedBy === 'drag') {
          //   setLatitude(lat);
          //   setLongitude(lng);
          // }
          try {
              // 更新地图数据
              const { newMarkers, sites } = await updateMapData(lat, lng);
            // 更新地图数据
            const { newMarkers, sites } = await updateMapData(lat, lng);
              const nearestCandidates = sites.length > 0 ? sites : newMarkers;
              const { targetMarker, minDistance } = findNearestMarker(lat, lng, nearestCandidates);
            const nearestCandidates = sites.length > 0 ? sites : newMarkers;
            const { targetMarker, minDistance } = findNearestMarker(lat, lng, nearestCandidates);
              // 用户手势拖动或点击回到原点触发的移动,进行吸附判断
              if ((causedBy === 'gesture' || causedBy === 'drag' || wasReturningToOrigin) && targetMarker && minDistance < adsorptionDistance) {
                // 使用 moveToLocation 实现吸附效果
                mapCtx.moveToLocation({
                  latitude: targetMarker.latitude,
                  longitude: targetMarker.longitude,
                });
              }
            // 用户手势拖动或点击回到原点触发的移动,进行吸附判断
            if ((causedBy === 'gesture' || causedBy === 'drag' || wasReturningToOrigin) && targetMarker && minDistance < adsorptionDistance) {
              // 使用 moveToLocation 实现吸附效果
              mapCtx.moveToLocation({
                latitude: targetMarker.latitude,
                longitude: targetMarker.longitude,
              });
            }
            // 根据距离决定是否显示 ToolTip
            setTimeout(() => {
src/robotaxi/pages/begin-route/components/calling-car.tsx
@@ -610,10 +610,13 @@
                            <View className="car-card-end-particulars">
                                <View className="car-card-end-particulars-money">
                                    <View>{formatMoney(
                                        (fareBreakdown?.orderMoney - fareBreakdown?.redPacketMoney - fareBreakdown?.couponMoney) < 0
                                        (fareBreakdown?.orderMoney - fareBreakdown?.redPacketMoney - fareBreakdown?.couponMoney) <= 0
                                            ? 0 : (fareBreakdown?.orderMoney - fareBreakdown?.redPacketMoney - fareBreakdown?.couponMoney))}</View>
                                    <View>元</View>
                                    <View>{formatMoney(fareBreakdown?.orderMoney)}元</View>
                                    {
                                        fareBreakdown?.redPacketMoney + fareBreakdown?.couponMoney > 0 &&
                                        <View>{formatMoney(fareBreakdown?.orderMoney)}元</View>
                                    }
                                    {
                                        fareBreakdown?.redPacketMoney + fareBreakdown?.couponMoney > 0 &&
                                        <View>已优惠{formatMoney(fareBreakdown?.redPacketMoney + fareBreakdown?.couponMoney)}元</View>
src/robotaxi/pages/begin-route/components/cancel-popup.tsx
@@ -35,13 +35,13 @@
    const STATUS_MAP = {
        1: {
            title: `${waitMinutesValue}分钟内预计有车,确定取消吗?`,
            tip: `本单限时优惠${discountAmountValue}元,重新叫车可能等待更久`,
            tip: discountAmountValue > 0 ? `本单限时优惠${discountAmountValue}元,重新叫车可能等待更久` : '',
        },
        2: {
            title: tripStatus === 4
                ? `车辆还有${durationDisplay.value}${durationDisplay.unit}到达,确定取消吗`
                : `车辆还有${waitMinutesValue}分钟到达,确定取消吗`,
            tip: `本单限时优惠${discountAmountValue}元,重新叫车可能等待更久`,
            tip: discountAmountValue > 0 ? `本单限时优惠${discountAmountValue}元,重新叫车可能等待更久` : '',
        },
        3: {
            title: '车辆已到达,确定取消吗?',
src/robotaxi/pages/begin-route/components/css-folder/evaluate-popup.less
@@ -188,9 +188,27 @@
                    }
                }
                &-delete {
                    position: absolute;
                    top: 8px;
                    right: 8px;
                    box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.2);
                    z-index: 2;
                    .delete-icon {
                        width: 40px;
                        height: 40px;
                    }
                }
                @keyframes rotate {
                    0% { transform: rotate(0); }
                    100% { transform: rotate(360deg); }
                    0% {
                        transform: rotate(0);
                    }
                    100% {
                        transform: rotate(360deg);
                    }
                }
                &-upload {
@@ -237,4 +255,4 @@
            background: linear-gradient(97deg, #8475FF 0%, #7DD6FF 103%);
        }
    }
}
}
src/robotaxi/pages/begin-route/components/evaluate-popup.tsx
@@ -224,6 +224,14 @@
        uploadSingle(index, item.localUrl);
    };
    const handleDelete = (index: number) => {
        setPictures(prev => {
            const next = [...prev];
            next.splice(index, 1);
            return next;
        });
    };
    useEffect(() => {
        if (!show) {
            return;
@@ -295,6 +303,13 @@
                                        </View>
                                    )
                                }
                                {
                                    p.status === 'success' && (
                                        <View className='evaluate-problem-pic-box-delete' onClick={() => handleDelete(idx)}>
                                            <Image className='delete-icon' src={require('../../../assets/clear-icon.png')} />
                                        </View>
                                    )
                                }
                            </View>
                        ))}
                        {
src/robotaxi/pages/begin-route/components/over-route.tsx
@@ -98,7 +98,7 @@
            <View className='over-content' animation={animationData}>
                <Image onClick={onClose} className='close-icon' src={require('../../../assets/close-icon.png')} />
                <View className='over-title'>确认结束行程?</View>
                <View className='over-txt'>行程结束{finishMinutes}分钟后车辆将自动驶离开</View>
                <View className='over-txt'>行程结束{finishMinutes}分钟后车辆将自动驶离</View>
                <View onClick={handleConfirm} className='reselect-btn'>确认结束</View>
            </View>
        </View>
src/robotaxi/pages/begin-route/index.tsx
@@ -31,7 +31,8 @@
  getAddressByLocation,
  convertAdcodeToCityCode,
  getCityInfoWithId,
  getDistance
  getDistance,
  shouldUpdateRoute
} from '../../../utils/Robotaxi-public-method';
import {
  saveOrder,
@@ -154,6 +155,8 @@
  const orderDetailRouteRequestIdRef = useRef(0);
  const lastRoutePointRef = useRef<{ latitude: number; longitude: number } | null>(null);
  const lastRouteUpdateAtRef = useRef<number>(0);
  const lastVehiclePointRef = useRef<{ latitude: number; longitude: number } | null>(null);
  const lastVehicleUpdateAtRef = useRef<number>(0);
  const lastPolylineUpdateAtRef = useRef<number>(0);
  const lastRouteAndFareRequestAtRef = useRef<number>(0);
  const markersSignatureRef = useRef<string>('');
@@ -309,7 +312,7 @@
          setCarCalloutStyle({
            position: 'fixed',
            left: `${rect.left + x}px`,
            top: `${rect.top + y}px`,
            top: `${rect.top + y + 45}px`,
            transform: 'translate(-50%, -120%)'
          });
          setCarCalloutVisible(true);
@@ -463,31 +466,62 @@
  // 应用路线点
  const applyRoutePoints = (points: any[]) => {
    if (Array.isArray(points) && points.length > 0) {
      const lastPoint = points[points.length - 1];
      const lastLatitude = Number(lastPoint?.latitude);
      const lastLongitude = Number(lastPoint?.longitude);
      // 使用代表车辆当前位置的第一个点来做节流判断
      const firstPoint = points[0];
      const newLat = Number(firstPoint?.latitude);
      const newLng = Number(firstPoint?.longitude);
      const now = Date.now();
      const prev = lastRoutePointRef.current;
      if (Number.isFinite(lastLatitude) && Number.isFinite(lastLongitude) && prev) {
        const delta = Math.abs(prev.latitude - lastLatitude) + Math.abs(prev.longitude - lastLongitude);
        const minDelta = isAndroid ? 0.00003 : 0.00002;
        const minInterval = isAndroid ? 1200 : 800;
        if (delta < minDelta && now - lastRouteUpdateAtRef.current < minInterval) {
          return;
      const lastUpdateAt = lastRouteUpdateAtRef.current;
      if (Number.isFinite(newLat) && Number.isFinite(newLng) && prev && lastUpdateAt > 0) {
        // 使用新的判断逻辑:100米和10秒
        const isUpdate = shouldUpdateRoute(prev.latitude, prev.longitude, newLat, newLng, lastUpdateAt);
        if (!isUpdate) {
          return false; // 未达到更新阈值,直接返回
        }
      }
      if (Number.isFinite(lastLatitude) && Number.isFinite(lastLongitude)) {
        lastRoutePointRef.current = { latitude: lastLatitude, longitude: lastLongitude };
      if (Number.isFinite(newLat) && Number.isFinite(newLng)) {
        lastRoutePointRef.current = { latitude: newLat, longitude: newLng };
        lastRouteUpdateAtRef.current = now;
      } else {
        lastRoutePointRef.current = null;
        lastRouteUpdateAtRef.current = 0;
      }
      setRoutePoints(points);
      return true;
    } else {
      lastRoutePointRef.current = null;
      lastRouteUpdateAtRef.current = 0;
      setRoutePoints([]);
      return true;
    }
  };
  // 更新车辆位置(带节流)
  const updateVehicleLocationThrottled = (lat: number, lng: number, force = false) => {
    if (force) {
      lastVehiclePointRef.current = { latitude: lat, longitude: lng };
      lastVehicleUpdateAtRef.current = Date.now();
      setVehicleLocation({ latitude: lat, longitude: lng });
      return;
    }
    const now = Date.now();
    const prev = lastVehiclePointRef.current;
    const lastUpdateAt = lastVehicleUpdateAtRef.current;
    if (Number.isFinite(lat) && Number.isFinite(lng) && prev && lastUpdateAt > 0) {
      const isUpdate = shouldUpdateRoute(prev.latitude, prev.longitude, lat, lng, lastUpdateAt);
      if (!isUpdate) {
        return;
      }
    }
    if (Number.isFinite(lat) && Number.isFinite(lng)) {
      lastVehiclePointRef.current = { latitude: lat, longitude: lng };
      lastVehicleUpdateAtRef.current = now;
      setVehicleLocation({ latitude: lat, longitude: lng });
    }
  };
@@ -651,11 +685,11 @@
        if (points.length > 0) {
          if (status === 5) {
            const last = points[points.length - 1];
            setVehicleLocation({ latitude: last.latitude, longitude: last.longitude });
            updateVehicleLocationThrottled(last.latitude, last.longitude, true);
          } else {
            applyRoutePoints(points);
            const first = points[0];
            setVehicleLocation({ latitude: first.latitude, longitude: first.longitude });
            updateVehicleLocationThrottled(first.latitude, first.longitude, true);
          }
        }
        const distance = Number(data?.distance);
@@ -760,6 +794,8 @@
        lastPolylineUpdateAtRef.current = 0;
        lastRoutePointRef.current = null;
        lastRouteUpdateAtRef.current = 0;
        lastVehiclePointRef.current = null;
        lastVehicleUpdateAtRef.current = 0;
      }
      if (mappedTripStatus === 4) {
        setRoutePoints([]);
@@ -768,6 +804,8 @@
        lastPolylineUpdateAtRef.current = 0;
        lastRoutePointRef.current = null;
        lastRouteUpdateAtRef.current = 0;
        lastVehiclePointRef.current = null;
        lastVehicleUpdateAtRef.current = 0;
      }
      if (payload?.showCancelPopup) {
        setTripStatus(10);
@@ -802,10 +840,12 @@
      // 仅在呼叫及后续阶段允许展示路线
      if (isHoldMapStatus && orderRouteInitializedRef.current) {
        setTimeout(() => {
          applyRoutePoints(points);
          const firstPoint = points?.[0];
          if (firstPoint && typeof firstPoint.latitude === 'number' && typeof firstPoint.longitude === 'number') {
            setVehicleLocation({ latitude: firstPoint.latitude, longitude: firstPoint.longitude });
          const updated = applyRoutePoints(points);
          if (updated) {
            const firstPoint = points?.[0];
            if (firstPoint && typeof firstPoint.latitude === 'number' && typeof firstPoint.longitude === 'number') {
              updateVehicleLocationThrottled(firstPoint.latitude, firstPoint.longitude, true);
            }
          }
        }, 500);
        return;
@@ -816,11 +856,11 @@
      // 发布行程状态也允许展示路线
      setTimeout(() => {
        applyRoutePoints(points);
        if ([4, 5, 6].includes(tripStatusRef.current)) {
        const updated = applyRoutePoints(points);
        if (updated && [4, 5, 6].includes(tripStatusRef.current)) {
          const firstPoint = points?.[0];
          if (firstPoint && typeof firstPoint.latitude === 'number' && typeof firstPoint.longitude === 'number') {
            setVehicleLocation({ latitude: firstPoint.latitude, longitude: firstPoint.longitude });
            updateVehicleLocationThrottled(firstPoint.latitude, firstPoint.longitude, true);
          }
        }
      }, 500);
@@ -832,7 +872,7 @@
      const longitude = payload?.longitude;
      if (typeof latitude === 'number' && typeof longitude === 'number') {
        if ([4, 5, 6, 7].includes(tripStatusRef.current)) {
          setVehicleLocation({ latitude, longitude });
          updateVehicleLocationThrottled(latitude, longitude);
        }
      }
    };
@@ -1047,11 +1087,11 @@
      height: 40,
      anchor: { x: 0.5, y: 1 },
      zIndex: 1,
      name: [7, 9].includes(tripStatus) ? '已到达' : (dropoffSite.name || '目的地'),
      name: [7].includes(tripStatus) ? '已到达' : (dropoffSite.name || '目的地'),
      ...(useAndroidNativeTrip1Callout
        ? {
          callout: {
            content: `${[7, 9].includes(tripStatus) ? '已到达' : (dropoffSite.name || '目的地')} >`,
            content: `${[7].includes(tripStatus) ? '已到达' : (dropoffSite.name || '目的地')} >`,
            color: '#000000',
            fontSize: 12,
            bgColor: '#FFFFFF',
@@ -1528,7 +1568,7 @@
    }
    const selectedCity = Taro.getStorageSync('selectedCity');
    let openCityId = selectedCity?.id || 0;
    // 如果缓存中没有城市ID,尝试通过定位重新匹配一次
    if (!openCityId) {
      try {
@@ -1549,7 +1589,7 @@
        console.error('Failed to fetch city info before order:', e);
      }
    }
    // 如果还是拿不到城市ID,拦截下单
    if (!openCityId) {
      Taro.showToast({
@@ -1677,7 +1717,7 @@
    setOrderId('');
    clearOrderTripStorage();
    setCancelType(type);
    setShowCancelPopup(true);
    setShowCancelPopup(false);
    setTripStatus(1);
    updateWalkingRouteForStart();
    const s = Taro.getStorageSync('startSite');
@@ -1688,7 +1728,7 @@
  };
  // 打开取消弹窗
  const handleOpenCancelPopupByTripStatus = (status: number, durationDisplay?: any) => {
    if (durationDisplay && status != 5) {
    if (durationDisplay && ![3, 5].includes(status)) {
      setCancelType(2);
      setShowCancelPopup(true);
      return
@@ -1744,6 +1784,7 @@
        icon: 'none',
      })
      setTripStatus(9);
      Taro.setStorageSync('tripStatus', 9);
    } catch (error) {
      Taro.showToast({
        title: '支付失败,请重试',
@@ -1873,7 +1914,7 @@
        {/* 自定义callout */}
        {
          !(isAndroid && tripStatus === 1) && markers.map((item, index) => {
            const calloutKey = `${tripStatus}-${item.id}`;
            const calloutKey = `callout-${item.id}-${item.name || ''}`;
            const isWaiting = [2, 3].includes(tripStatus) && index === 0;
            if (isWaiting) {
@@ -1903,9 +1944,9 @@
            return (
              <CoverView slot="callout" marker-id={item.id} key={calloutKey} className="custom-callout">
                {
                  (item.name !== '车辆位置' && !(item.id === 2 && [7, 9].includes(tripStatus))) &&
                  (item.name !== '车辆位置' && !(item.id === 2 && [7].includes(tripStatus))) &&
                  <CoverView className={`custom-callout-content ${isAndroid && 'txt-center '}`}>
                    <CoverView>{item.name}</CoverView>
                    <CoverView style={{ lineHeight: '22px', display: 'flex', alignItems: 'center' }}>{item.name}</CoverView>
                    {
                      isAndroid &&
                      <CoverView style={{ width: '2px' }}></CoverView>
src/robotaxi/pages/expense-detail/index.tsx
@@ -67,7 +67,12 @@
              <View className='price-value'>{pricingCard.distancePriceStr}元</View>
            </View>
            <View className='flex-between-card mb-16'>
              <View className='price-notice-label'>普通时段({formatTripDistance(pricingCard.distancePriceNormal)})</View>
              <View className='price-notice-label'>普通时段
                {
                  pricingCard.distancePriceNormal > 0 &&
                  <Text>({formatTripDistance(pricingCard.distancePriceNormal)})</Text>
                }
              </View>
              <View className='price-notice-value'>{pricingCard.distancePriceStr}元</View>
            </View>
          </View>
@@ -80,17 +85,23 @@
              <View className='price-value'>{pricingCard.durationPriceStr}元</View>
            </View>
            <View className='flex-between-card mb-16'>
              <View className='price-notice-label'>普通时段({formatTripDurationFromSeconds(pricingCard.durationPriceNormal)})</View>
              <View className='price-notice-label'>普通时段
                {
                  pricingCard.durationPriceNormal > 0 &&
                  <Text>({formatTripDurationFromSeconds(pricingCard.durationPriceNormal)})</Text>
                }
              </View>
              <View className='price-notice-value'>{pricingCard.durationPriceStr}元</View>
            </View>
          </View>
        }
        {pricingCard.coupon && (
        {
          (pricingCard.coupon && pricingCard.coupon > 0) &&
          <View className='flex-between-card'>
            <View className='price-label'>优惠券</View>
            <View className='price-value color-red'>-{pricingCard.coupon}元</View>
          </View>
        )}
        }
      </View>
      {/* 总价格 */}
      <View className='flex-card total'>
src/utils/Robotaxi-public-method.ts
@@ -17,6 +17,14 @@
  return s * 1000;
};
// 判断是否需要更新路线(距离大于100米或时间超过10秒)
export const shouldUpdateRoute = (lastLat: number, lastLng: number, newLat: number, newLng: number, lastUpdateTime: number): boolean => {
  const distance = getDistance(lastLat, lastLng, newLat, newLng);
  const now = Date.now();
  const timeElapsed = now - lastUpdateTime;
  return distance > 100 || timeElapsed >= 10000;
};
// 格式化距离
export const formatDistance = (val: any) => {
  if (!val) return '0m';
@@ -354,6 +362,7 @@
// 获取包含 ID 的城市信息
export const getCityInfoWithId = async (cityCode: string, cityName: string) => {
  try {
    const res: any = await getOpenCity();