hejianhao
2026-04-15 5b0fa01f64ba8a86117f1181404191e50e0e4917
feat(vehicle-tracking): 动态调整车辆轨迹动画时长并优化位置同步逻辑

- 基于推送间隔动态计算平移动画时长,适配1-2秒频率的轨迹推送
- 移除moveAlong路径动画逻辑,统一使用translateMarker进行车辆移动
- 优化车辆位置同步策略,优先使用已服务路段的最后一个点作为车辆位置
- 简化useVehicleTracking依赖项,提升代码可维护性
2个文件已修改
66 ■■■■■ 已修改文件
src/robotaxi/pages/begin-route/hooks/use-vehicle-tracking.ts 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/hooks/use-web-socket-events.ts 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/hooks/use-vehicle-tracking.ts
@@ -22,10 +22,17 @@
  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 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;
@@ -35,7 +42,6 @@
  useEffect(() => {
    if (!statusRule.translateCar) return;
    if (vehicleMoveAlongPoints.length > 1) return;
    if (!vehicleLocation) return;
    const mapCtx = Taro.createMapContext('map');
    const timer = setTimeout(() => {
@@ -48,27 +54,11 @@
        autoRotate: false,
        moveWithRotate: true,
        rotate: typeof vehicleDirection === 'number' ? ((vehicleDirection % 360) + 360) % 360 : 0,
        duration: 100
        duration: translateDurationRef.current
      });
    }, 100);
    return () => clearTimeout(timer);
  }, [statusRule.translateCar, vehicleLocation, vehicleDirection, vehicleMarkerId, vehicleMoveAlongPoints]);
  useEffect(() => {
    if (!statusRule.translateCar) return;
    if (vehicleMoveAlongPoints.length < 2) return;
    const mapCtx = Taro.createMapContext('map');
    const duration = Math.min(2000, Math.max(300, vehicleMoveAlongPoints.length * 100));
    const timer = setTimeout(() => {
      mapCtx.moveAlong({
        markerId: vehicleMarkerId,
        path: vehicleMoveAlongPoints,
        autoRotate: true,
        duration
      });
    }, 50);
    return () => clearTimeout(timer);
  }, [statusRule.translateCar, vehicleMoveAlongPoints, vehicleMarkerId]);
  }, [statusRule.translateCar, vehicleLocation, vehicleDirection, vehicleMarkerId]);
  return {
    vehicleLocation,
src/robotaxi/pages/begin-route/hooks/use-web-socket-events.ts
@@ -168,16 +168,30 @@
    }
};
const syncVehiclePointWithRoute = (points: any[], deps: UseWebSocketEventsDeps) => {
const resolveVehiclePoint = (points: any[], servedPoints: any[] = []) => {
    const servedLastPoint = Array.isArray(servedPoints) && servedPoints.length > 0
        ? servedPoints[servedPoints.length - 1]
        : null;
    if (servedLastPoint && typeof servedLastPoint.latitude === 'number' && typeof servedLastPoint.longitude === 'number') {
        return servedLastPoint;
    }
    const firstPoint = points?.[0];
    if (!firstPoint || typeof firstPoint.latitude !== 'number' || typeof firstPoint.longitude !== 'number') {
    if (firstPoint && typeof firstPoint.latitude === 'number' && typeof firstPoint.longitude === 'number') {
        return firstPoint;
    }
    return null;
};
const syncVehiclePointWithRoute = (points: any[], deps: UseWebSocketEventsDeps, servedPoints: any[] = []) => {
    const targetPoint = resolveVehiclePoint(points, servedPoints);
    if (!targetPoint) {
        return;
    }
    deps.updateVehicleLocationThrottled(firstPoint.latitude, firstPoint.longitude, true);
    deps.updateVehicleLocationThrottled(targetPoint.latitude, targetPoint.longitude, true);
};
const handleEraseRouteStatus = (points: any[], servedPoints: any[], deps: UseWebSocketEventsDeps) => {
    const firstPoint = points?.[0];
    const targetPoint = resolveVehiclePoint(points, servedPoints);
    if (deps.orderRouteInitializedRef.current && deps.currentFullRouteRef.current.length > 0) {
        deps.erasePassedRouteSegments(points, servedPoints);
    } else {
@@ -188,23 +202,23 @@
            deps.applyRoutePoints(points);
        });
    }
    if (firstPoint && typeof firstPoint.latitude === 'number' && typeof firstPoint.longitude === 'number') {
    if (targetPoint) {
        setTimeout(() => {
            deps.updateVehicleLocationThrottled(firstPoint.latitude, firstPoint.longitude, true);
            deps.updateVehicleLocationThrottled(targetPoint.latitude, targetPoint.longitude, true);
        }, 50);
    }
};
const handleNormalRouteStatus = (points: any[], deps: UseWebSocketEventsDeps) => {
const handleNormalRouteStatus = (points: any[], deps: UseWebSocketEventsDeps, servedPoints: any[] = []) => {
    Taro.nextTick(() => {
        const updated = deps.applyRoutePoints(points);
        if (!updated) return;
        if (![4, 5, 6].includes(deps.tripStatusRef.current)) return;
        syncVehiclePointWithRoute(points, deps);
        syncVehiclePointWithRoute(points, deps, servedPoints);
    });
};
const handleForceFullRouteRedraw = (points: any[], deps: UseWebSocketEventsDeps) => {
const handleForceFullRouteRedraw = (points: any[], deps: UseWebSocketEventsDeps, servedPoints: any[] = []) => {
    deps.setRoutePoints([]);
    deps.setPolyline([]);
    deps.orderRouteInitializedRef.current = false;
@@ -220,7 +234,7 @@
        deps.currentFullRouteRef.current = [...points];
        deps.lastErasedIndexRef.current = 0;
        deps.applyRoutePoints(points);
        syncVehiclePointWithRoute(points, deps);
        syncVehiclePointWithRoute(points, deps, servedPoints);
    });
};
@@ -234,7 +248,7 @@
        deps.setVehicleMoveAlongPoints(servedPoints);
    }
    if (forceFullRedraw) {
        handleForceFullRouteRedraw(points, deps);
        handleForceFullRouteRedraw(points, deps, servedPoints);
        return;
    }
    const isEraseStatus = [4, 6].includes(deps.tripStatusRef.current);
@@ -242,7 +256,7 @@
        handleEraseRouteStatus(points, servedPoints, deps);
        return;
    }
    handleNormalRouteStatus(points, deps);
    handleNormalRouteStatus(points, deps, servedPoints);
};
export default function useWebSocketEvents(deps: UseWebSocketEventsDeps) {