hejianhao
2026-06-30 aabcb54ec4896613eb88eadaf0b389a65da12830
fix(begin-route): 修复地图与组件相关问题并清理代码

1. 添加乘车须知弹窗开关后的地图事件冷却过滤,避免多余视口更新
2. 修复非中文地名在调用气泡中被截断的显示问题
3. 调整呼叫车辆列表项的对齐方式与文字行高
4. 优化地图视口处理的依赖项与事件逻辑
5. 清理组件中的模板字符串格式与JSX结构
4个文件已修改
94 ■■■■■ 已修改文件
src/robotaxi/pages/begin-route/components/css-folder/calling-car.less 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/hooks/use-map-viewport.ts 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/hooks/use-view-delegates.tsx 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/index.tsx 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/css-folder/calling-car.less
@@ -498,6 +498,7 @@
    &-item {
      display: flex;
      align-items: center;
      box-sizing: border-box;
      &-disabled {
@@ -511,6 +512,7 @@
      }
      &-destination {
        .trip-action-bar-item-icon {
          width: 44px;
          height: 44px;
@@ -520,7 +522,7 @@
      &-text {
        flex-shrink: 0;
        font-size: 24px;
        line-height: 40px;
        line-height: 24px;
        color: rgba(0, 0, 0, 0.9);
      }
    }
@@ -794,4 +796,4 @@
      height: 17.5px;
    }
  }
}
}
src/robotaxi/pages/begin-route/hooks/use-map-viewport.ts
@@ -395,8 +395,10 @@
    return Promise.all([getMapScale(), getMapCenterLocation()])
      .then(([scaleRes, centerRes]) => {
        const actualScale = Number(scaleRes?.scale);
        const roundedScale = Number.isFinite(actualScale)
          ? Math.round(actualScale)
          : null;
        if (Number.isFinite(actualScale)) {
          const roundedScale = Math.round(actualScale);
          setMapScale(prev => (prev === roundedScale ? prev : roundedScale));
        }
        const centerLatitude = Number(centerRes?.latitude);
@@ -409,7 +411,7 @@
        }
      })
      .catch(() => {});
  }, [getMapScale, getMapCenterLocation, setMapScale, deps.setLatitude, deps.setLongitude]);
  }, [getMapScale, getMapCenterLocation, setMapScale, deps.setLatitude, deps.setLongitude, deps.tripStatus]);
  /**
   * 将经纬度映射为当前地图上的屏幕坐标。
src/robotaxi/pages/begin-route/hooks/use-view-delegates.tsx
@@ -213,11 +213,10 @@
    const { hasBeforeUserEndSite, routeDistance, durationDisplay } = props;
    return (
      <View
        className={`custom-callout-content ${
          hasBeforeUserEndSite
        className={`custom-callout-content ${hasBeforeUserEndSite
            ? "car-callout-with-before car-callout-double-line"
            : ""
        }`.trim()}
          }`.trim()}
        style={{ padding: "6px 10px" }}
      >
        {hasBeforeUserEndSite && (
@@ -292,11 +291,9 @@
  const routeSummaryText = useMemo(
    () =>
      deps.routeDistance && deps.routeDuration !== null
        ? `${vehicleMetricDurationDisplay.value}${
            vehicleMetricDurationDisplay.unit
          } ${deps.routeDistance.value}${
            deps.routeDistance.unit === "m" ? "米" : "公里"
          }`
        ? `${vehicleMetricDurationDisplay.value}${vehicleMetricDurationDisplay.unit
        } ${deps.routeDistance.value}${deps.routeDistance.unit === "m" ? "米" : "公里"
        }`
        : "",
    [deps.routeDistance, deps.routeDuration, vehicleMetricDurationDisplay]
  );
@@ -448,8 +445,9 @@
                    }}
                  >
                    {item.name}
                    {!deps.isAndroid && item.name.length > 16 && (
                      <CoverView style={{ color: "transparent",width: "3px" }}>占</CoverView>
                    {/* 包含非中文字符时占位  因为非中文字符渲染时存在额外间距(比如:‘地名123地名’ 会被渲染为:‘地名 123 地名’ ) 但是气泡宽度又没有自动计算上这个间距  导致名称会被截断 */}
                    {!deps.isAndroid && /[^\u4e00-\u9fa5]/.test(item.name) && (
                      <CoverView style={{ color: "transparent", width: "3px" }}>占</CoverView>
                    )}
                  </CoverView>
                  {deps.isAndroid && (
@@ -474,11 +472,10 @@
              !deps.isAndroid &&
              shouldShowVehicleMetricCallout && (
                <CoverView
                  className={`custom-callout-content ${
                    deps.hasBeforeUserEndSite
                  className={`custom-callout-content ${deps.hasBeforeUserEndSite
                      ? "car-callout-with-before car-callout-double-line"
                      : ""
                  }`.trim()}
                    }`.trim()}
                  style={{
                    padding: "6px 10px",
                    minWidth: "40px",
@@ -591,15 +588,15 @@
            {androidCarCalloutContent}
          </View>
        )}
      {deps.isAndroid && deps.arriveCalloutVisible && deps.arrivedTooltipReady && (
        <View className="car-callout-android" style={deps.arriveCalloutStyle}>
          <View className="custom-callout-content">
            已到达
        {deps.isAndroid && deps.arriveCalloutVisible && deps.arrivedTooltipReady && (
          <View className="car-callout-android" style={deps.arriveCalloutStyle}>
            <View className="custom-callout-content">
              已到达
            </View>
          </View>
        </View>
      )}
    </>
  ), [
        )}
      </>
    ), [
    androidCarCalloutContent,
    deps.arriveCalloutStyle,
    deps.arriveCalloutVisible,
src/robotaxi/pages/begin-route/index.tsx
@@ -93,6 +93,19 @@
const COUPON_POPUP_CLOSE_VIEWPORT_REFRESH_DELAY_MS = 320; // 优惠券弹窗退场动画结束后,再刷新完成态视口
const ROUTE_SELECTABLE_TRIP_STATUSES = [TripStatus.PublishRoute, TripStatus.VehicleApproaching] as const; // 允许展示并切换候选路线的行程状态
const PICKUP_ROUTE_CHANGE_ELIGIBLE_ORDER_ID_KEY = 'pickupRouteChangeEligibleOrderId'; // 接驾态允许切路线的订单 ID,仅在当前订单生命周期内有效
const PASSENGER_NOTICE_REGIONCHANGE_COOLDOWN_MS = 1000;
/**
 * 归一化原生地图回传的 causedBy,兼容 update 的异常拼写。
 */
const normalizeRegionChangeCause = (causedBy: unknown) => {
  const normalized = String(causedBy || '').toLowerCase();
  if (['update', 'udpate', 'upudate'].includes(normalized)) {
    return 'update';
  }
  return normalized;
};
type StatusRule = {
  showPickup: boolean;
  showDropoff: boolean;
@@ -238,6 +251,7 @@
    longitudeRef.current = value;
  }, []);
  const globalFitSyncRef = useRef(false); // 标记全局 includePoints 触发,用于在 regionchange end 时同步原生缩放
  const passengerNoticeRegionChangeIgnoreUntilRef = useRef(0); // 乘车须知开关后的地图 regionchange(update) 冷却截止时间
  const markViewportFitSyncing = useCallback(() => {
    globalFitSyncRef.current = true;
  }, []);
@@ -1679,19 +1693,21 @@
    setShowEvaluatePopup(true);
  };
  const handleOpenPassengerNotice = useCallback(async () => {
    if (tripStatus === TripStatus.PublishRoute) {
      await syncNativeViewportToControlledState();
    }
  const handleOpenPassengerNotice = useCallback(() => {
    pendingFitSyncRef.current = false;
    globalFitSyncRef.current = false;
    passengerNoticeRegionChangeIgnoreUntilRef.current =
      Date.now() + PASSENGER_NOTICE_REGIONCHANGE_COOLDOWN_MS;
    rawHandleOpenPassengerNotice();
  }, [tripStatus, syncNativeViewportToControlledState, rawHandleOpenPassengerNotice]);
  }, [rawHandleOpenPassengerNotice, pendingFitSyncRef]);
  const handleClosePassengerNotice = useCallback(async () => {
    if (tripStatus === TripStatus.PublishRoute) {
      await syncNativeViewportToControlledState();
    }
  const handleClosePassengerNotice = useCallback(() => {
    pendingFitSyncRef.current = false;
    globalFitSyncRef.current = false;
    passengerNoticeRegionChangeIgnoreUntilRef.current =
      Date.now() + PASSENGER_NOTICE_REGIONCHANGE_COOLDOWN_MS;
    rawHandleClosePassengerNotice();
  }, [tripStatus, syncNativeViewportToControlledState, rawHandleClosePassengerNotice]);
  }, [rawHandleClosePassengerNotice, pendingFitSyncRef]);
  const handleCloseEvaluatePopup = () => {
    setEvaluateCloseVersion(v => v + 1);
@@ -1709,13 +1725,18 @@
  }
  const handleRegionChange = (e) => {
    const causedBy = normalizeRegionChangeCause(e?.causedBy || e?.detail?.causedBy || '');
    const isPassengerNoticeRegionChangeCoolingDown =
      passengerNoticeRegionChangeIgnoreUntilRef.current > Date.now();
    if (causedBy === 'update' && isPassengerNoticeRegionChangeCoolingDown) {
      return;
    }
    activeTripScale.handleRegionChange(e);
    handleRouteSummaryRegionChange(e);
    handleAndroidOverlayRegionChange(e);
    // 用户手势导致的缩放/拖拽结束后,把原生地图的实际 scale 同步回 React 状态,
    // 避免受控 <Map scale={mapScale}> 与原生实际缩放漂移,影响后续视口编排判断。
    const causedBy = String(e?.causedBy || e?.detail?.causedBy || '').toLowerCase();
    const eventType = String(e?.type || e?.detail?.type || '').toLowerCase();
    if (eventType === 'end' && (causedBy === 'scale' || causedBy === 'drag' || causedBy === 'gesture')) {
        notifyUserMapGesture();