hejianhao
2026-04-16 45dd55e3d38d65f75b045550dee93f99998e64c3
fix(vehicle-tracking): 移除动态平移时长并优化后备箱状态轮询

- 将车辆位置更新的平移时长固定为 100ms,移除基于推送间隔的动态计算逻辑
- 优化后备箱状态轮询逻辑,增加轮询次数至5次并改进状态值解析
- 修复车辆位置在清除路线状态时立即更新,移除不必要的 setTimeout 延迟
- 移除行程状态为5时的订单路线处理限制,确保路线数据正常处理
3个文件已修改
104 ■■■■■ 已修改文件
src/robotaxi/pages/begin-route/components/calling-car-modules/door-trunk-control.tsx 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/hooks/use-vehicle-tracking.ts 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/hooks/use-web-socket-events.ts 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/calling-car-modules/door-trunk-control.tsx
@@ -67,7 +67,7 @@
            doorType,
            ...locationPayload
        }).then((res: any) => {
            console.log(res,'***********');
            console.log('解锁结果:', res);
            
            if (!res) {
                Taro.showToast({ title: '解锁失败,请重试或联系客服', icon: 'none' });
@@ -75,22 +75,34 @@
            }
            if (doorType === 'trunk') {
                const loadingText = trunkStatus ? '正在关闭后备箱' : '正在开启后备箱';
                const isCloseAction = !!trunkStatus;
                const loadingText = isCloseAction ? '正在关闭后备箱' : '正在开启后备箱';
                Taro.showLoading({ title: loadingText, mask: true });
                let pollCount = 0;
                const maxPolls = 3;
                const maxPolls = 5;
                const pollInterval = 2000;
                const expectedTrunkState = trunkStatus ? '0' : '1';
                const expectedTrunkState = isCloseAction ? 0 : 1;
                const successToastText = isCloseAction ? '关闭后备箱成功' : '打开后备箱成功';
                const failToastText = isCloseAction ? '关闭后备箱失败' : '开启后备箱失败';
                const stopPolling = () => {
                    if (trunkPollTimerRef.current) {
                        clearTimeout(trunkPollTimerRef.current);
                        trunkPollTimerRef.current = null;
                    }
                };
                const handlePollFail = (reason: string, actualValue?: any) => {
                    pollCount++;
                    if (pollCount < maxPolls) {
                        stopPolling();
                        trunkPollTimerRef.current = setTimeout(doPoll, pollInterval);
                    } else {
                        stopPolling();
                        Taro.hideLoading();
                        Taro.showToast({
                            title: trunkStatus ? '关闭后备箱失败' : '开启后备箱失败',
                            title: failToastText,
                            icon: 'none'
                        });
                    }
@@ -98,19 +110,31 @@
                const doPoll = () => {
                    queryVehicleTrunkOpenStatus({ orderId: targetOrderId }).then((pollRes: any) => {
                        const data = pollRes;
                        const rawValue = data?.stateMap?.trunkAjarCloseSt?.value;
                        if (!data || rawValue === undefined || rawValue === null || rawValue === '') {
                        console.log('第', pollCount, '次查询后备箱状态:', pollRes);
                        const rawValue = typeof pollRes === 'number'
                            ? pollRes
                            : (
                                pollRes?.data ??
                                pollRes?.stateMap?.trunkAjarCloseSt?.value ??
                                pollRes?.value
                            );
                        if (rawValue === undefined || rawValue === null || rawValue === '') {
                            handlePollFail('empty_data_or_value', rawValue);
                            return;
                        }
                        const value = String(rawValue);
                        const value = Number(rawValue);
                        if (Number.isNaN(value)) {
                            handlePollFail('invalid_value', rawValue);
                            return;
                        }
                        if (value === expectedTrunkState) {
                            const isOpen = value === '1';
                            stopPolling();
                            const isOpen = !isCloseAction;
                            setTrunkStatus(isOpen);
                            Taro.hideLoading();
                            Taro.showToast({
                                title: isOpen ? '打开成功' : '关闭成功',
                                title: successToastText,
                                icon: 'none'
                            });
                            onSuccess?.();
@@ -139,7 +163,7 @@
    if (tripStatus === 5) {
        return (
            <View className="car-card-arrive">
                <View className={`car-card-arrive-item ${trunkStatus && 'close-btn-item'}`} onClick={() => handleUnlock('trunk')}>
                <View className={`car-card-arrive-item ${trunkStatus && 'close-btn-item'}`} onClick={() => handleUnlock('trunk', () => setTrunkStatus(!trunkStatus))}>
                    <Image className="car-card-arrive-item-img" src={trunkStatus ? require('../../../../assets/trunk-open.png') : require('../../../../assets/trunk-close.png')} />
                    <View className="car-card-arrive-item-text">{trunkStatus ? '关闭后备箱' : '打开后备箱'}</View>
                </View>
@@ -157,7 +181,7 @@
                <View className="car-card-reach-text">点击按钮开车门</View>
                <Image className='car-card-reach-img' src='https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/door-anim.webp' />
                <View className="car-card-reach-btn">
                    <View className={`car-card-reach-btn-item ${trunkStatus && 'close-btn-item'}`} onClick={() => handleUnlock('trunk')}>
                    <View className={`car-card-reach-btn-item ${trunkStatus && 'close-btn-item'}`} onClick={() => handleUnlock('trunk', () => setTrunkStatus(!trunkStatus))}>
                        <Image className="car-card-reach-btn-item-img" src={trunkStatus ? require('../../../../assets/trunk-open.png') : require('../../../../assets/trunk-close.png')} />
                        <View className="car-card-reach-btn-item-text">{trunkStatus ? '关闭后备箱' : '打开后备箱'}</View>
                    </View>
@@ -171,4 +195,4 @@
    }
    return null;
}
}
src/robotaxi/pages/begin-route/hooks/use-vehicle-tracking.ts
@@ -22,17 +22,11 @@
  const [trunkStatus, setTrunkStatus] = useState(false);
  const lastVehiclePointRef = useRef<{ latitude: number; longitude: number } | null>(null);
  const lastVehicleUpdateAtRef = useRef<number>(0);
  const translateDurationRef = useRef<number>(900);
  const TRANSLATE_DURATION_MS = 100;
  // 更新车辆位置并维护最近位置引用
  const updateVehicleLocationThrottled = (lat: number, lng: number, force = false) => {
    const now = Date.now();
    const prevUpdateAt = lastVehicleUpdateAtRef.current;
    if (prevUpdateAt > 0) {
      // 基于推送间隔动态调整平移时长,适配 1-2 秒频率的轨迹推送
      const interval = now - prevUpdateAt;
      translateDurationRef.current = Math.max(350, Math.min(1600, Math.floor(interval * 0.85)));
    }
    if (Number.isFinite(lat) && Number.isFinite(lng)) {
      lastVehiclePointRef.current = { latitude: lat, longitude: lng };
      lastVehicleUpdateAtRef.current = now;
@@ -44,20 +38,17 @@
    if (!statusRule.translateCar) return;
    if (!vehicleLocation) return;
    const mapCtx = Taro.createMapContext('map');
    const timer = setTimeout(() => {
      mapCtx.translateMarker({
        markerId: vehicleMarkerId,
        destination: {
          latitude: vehicleLocation.latitude,
          longitude: vehicleLocation.longitude,
        },
        autoRotate: false,
        moveWithRotate: true,
        rotate: typeof vehicleDirection === 'number' ? ((vehicleDirection % 360) + 360) % 360 : 0,
        duration: translateDurationRef.current
      });
    }, 100);
    return () => clearTimeout(timer);
    mapCtx.translateMarker({
      markerId: vehicleMarkerId,
      destination: {
        latitude: vehicleLocation.latitude,
        longitude: vehicleLocation.longitude,
      },
      autoRotate: false,
      moveWithRotate: true,
      rotate: typeof vehicleDirection === 'number' ? ((vehicleDirection % 360) + 360) % 360 : 0,
      duration: TRANSLATE_DURATION_MS
    });
  }, [statusRule.translateCar, vehicleLocation, vehicleDirection, vehicleMarkerId]);
  return {
src/robotaxi/pages/begin-route/hooks/use-web-socket-events.ts
@@ -182,6 +182,14 @@
    return null;
};
const resolveVehiclePointForErase = (points: any[], servedPoints: any[] = []) => {
    const firstPoint = points?.[0];
    if (firstPoint && typeof firstPoint.latitude === 'number' && typeof firstPoint.longitude === 'number') {
        return firstPoint;
    }
    return resolveVehiclePoint(points, servedPoints);
};
const syncVehiclePointWithRoute = (points: any[], deps: UseWebSocketEventsDeps, servedPoints: any[] = []) => {
    const targetPoint = resolveVehiclePoint(points, servedPoints);
    if (!targetPoint) {
@@ -191,7 +199,10 @@
};
const handleEraseRouteStatus = (points: any[], servedPoints: any[], deps: UseWebSocketEventsDeps) => {
    const targetPoint = resolveVehiclePoint(points, servedPoints);
    const targetPoint = resolveVehiclePointForErase(points, servedPoints);
    if (targetPoint) {
        deps.updateVehicleLocationThrottled(targetPoint.latitude, targetPoint.longitude, true);
    }
    if (deps.orderRouteInitializedRef.current && deps.currentFullRouteRef.current.length > 0) {
        deps.erasePassedRouteSegments(points);
    } else {
@@ -201,11 +212,6 @@
        Taro.nextTick(() => {
            deps.applyRoutePoints(points);
        });
    }
    if (targetPoint) {
        setTimeout(() => {
            deps.updateVehicleLocationThrottled(targetPoint.latitude, targetPoint.longitude, true);
        }, 50);
    }
};
@@ -241,7 +247,6 @@
};
const handleOrderRoutePayload = (payload: any, deps: UseWebSocketEventsDeps) => {
    if (deps.tripStatusRef.current === 5) return;
    const points = payload?.points || [];
    const servedPoints = Array.isArray(payload?.servedPoints) ? payload.servedPoints : [];
    const forceFullRedraw = payload?.forceFullRedraw === true;