zjk
2026-06-05 84cf477a665b64fbee3265e108b7d49a4112c6e5
refactor(robotaxi): 优化地图气泡定位并隐藏车辆编码展示

- 注释三个车辆信息页面的车辆编码展示内容
- 重构地图标记气泡定位逻辑,适配连环派单场景的偏移调整
- 提取复用的地图视口调整函数,修复不同行驶方向的锚点计算问题
- 将customCallout的anchorX参数纳入标记签名计算逻辑
5个文件已修改
103 ■■■■■ 已修改文件
src/robotaxi/pages/begin-route/components/calling-car-modules/vehicle-info-card.tsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/hooks/use-map-markers.ts 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/hooks/use-map-viewport.ts 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/order/detail/index.tsx 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/share-trip/components/share-trip-view.tsx 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/calling-car-modules/vehicle-info-card.tsx
@@ -19,15 +19,15 @@
                <View className="car-card-detail-num">{vehicleInfo?.plateNumber}</View>
                <View className="car-card-detail-color">
                    {vehicleInfo?.vehicleColor}
                    <View className="car-card-detail-color-line"></View>
                    车身编码: {vehicleInfo?.vehicleCode}
                    {/* <View className="car-card-detail-color-line"></View>
                    车身编码: {vehicleInfo?.vehicleCode} */}
                </View>
            </View>
            {
                vehicleInfo?.vehiclePictures &&
                <Image
                    className="car-card-detail-img"
                    src={safeParse(vehicleInfo?.vehiclePictures, {})?.url || 'https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/vehicle-default.png'}
                <Image
                    className="car-card-detail-img"
                    src={safeParse(vehicleInfo?.vehiclePictures, {})?.url || 'https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/vehicle-default.png'}
                />
            }
        </View>
src/robotaxi/pages/begin-route/hooks/use-map-markers.ts
@@ -26,6 +26,7 @@
      shouldIgnoreDynamicCarPosition ? 'translate' : Number(marker.longitude).toFixed(6),
      marker.name || '',
      typeof marker.rotate === 'number' ? marker.rotate : '',
      marker?.customCallout?.anchorX ?? '',
      marker?.customCallout?.anchorY ?? '',
    ].join('|');
  })
@@ -169,29 +170,35 @@
  // 构建车辆 marker
  const createCarMarker = () => {
    if (!deps.vehicleLocation) return null;
    // 动态计算气泡位置,始终将气泡放在车辆行驶方向的后方,避免遮挡前方路线
    // 车辆图标高 40,宽 20。气泡宽约 140,高约 40。
    // 动态计算气泡位置,始终将气泡放在车辆行驶方向的后方,避免遮挡前方路线。
    // 连环派单场景会额外多一行“即将完成上一单”,气泡高度会明显增加,需要进一步拉开与车辆的距离。
    const hasBeforeUserOrderTip = Number.isFinite(Number(deps.beforeUserEndSite?.latitude))
      && Number.isFinite(Number(deps.beforeUserEndSite?.longitude));
    const verticalExtraOffset = hasBeforeUserOrderTip ? 22 : 0;
    const horizontalExtraOffset = hasBeforeUserOrderTip ? 20 : 0;
    // 车辆图标高 40,宽 20。普通气泡高约 40,连环派单气泡更高。
    // anchorY/anchorX 的基准是基于 marker 自身的坐标点 (0, 0)
    let anchorY = 60; // 默认向北行驶,气泡放在正下方,避开车身高度 (40) 和部分留白
    let anchorY = 80 + verticalExtraOffset; // 默认向北行驶,气泡放在正下方
    let anchorX = 0;
    if (typeof deps.vehicleDirection === 'number') {
      const normalizedDirection = ((deps.vehicleDirection % 360) + 360) % 360;
      if (normalizedDirection >= 45 && normalizedDirection < 135) {
        // 向东行驶,后方为西(左侧)
        // 气泡向左偏移一半的气泡宽度 (约 70) 加上车身宽度一半 (10) 和留白
        anchorY = 20; // 垂直居中于车身
        anchorX = -85;
        // 连环派单气泡更高,左侧场景同步增加一点垂直与水平避让,防止左上角压住车身。
        anchorY = 20 + Math.round(verticalExtraOffset / 2);
        anchorX = -(85 + horizontalExtraOffset);
      } else if (normalizedDirection >= 135 && normalizedDirection < 225) {
        // 向南行驶,后方为北(上方)
        // 气泡向上偏移气泡高度 (40) 加上车身高度的一半 (20)
        anchorY = -40;
        // 连环派单气泡更高,需要继续上移,避免底部压住车辆图标。
        anchorY = -(10 + verticalExtraOffset);
        anchorX = 0;
      } else if (normalizedDirection >= 225 && normalizedDirection < 315) {
        // 向西行驶,后方为东(右侧)
        // 气泡向右偏移一半的气泡宽度 (约 70) 加上车身宽度一半 (10) 和留白
        anchorY = 20; // 垂直居中于车身
        anchorX = 85;
        // 连环派单气泡更高,右侧场景同步增加一点垂直与水平避让,防止右上角压住车身。
        anchorY = 20 + Math.round(verticalExtraOffset / 2);
        anchorX = 85 + horizontalExtraOffset;
      }
    }
src/robotaxi/pages/begin-route/hooks/use-map-viewport.ts
@@ -448,21 +448,32 @@
    const toOrigin = () => {
        const mapCtx = Taro.createMapContext('map');
        if (deps.tripStatus === TripStatus.InService && deps.routePoints.length > 0) {
            const { dropoffSite } = resolveViewportSites();
            const dropoffPoint = buildSiteViewportPoint(dropoffSite);
        const includeRouteToVisibleCenter = (targetSite: any, shouldLockInService: boolean) => {
            const targetPoint = buildSiteViewportPoint(targetSite);
            const pointsToInclude = [...deps.routePoints];
            if (dropoffPoint) pointsToInclude.push(dropoffPoint);
            const bottomPadding = computeBottomPadding(pointsToInclude, 'route');
            if (targetPoint) {
                pointsToInclude.push(targetPoint);
            }
            // 接驾/送驾点击回中时统一走整路线居中,并适当收窄底部留白,避免路线整体偏上。
            const bottomPadding = computeBottomPadding(pointsToInclude, 'route') - 88;
            const topPadding = Math.max(24, resolveSafeTopInset() + 32);
            holdDynamicScale();
            mapCtx.includePoints({
                points: pointsToInclude,
                padding: [topPadding, 100, bottomPadding, 100]
            });
            tripStatus6ViewportLockedRef.current = true;
            if (shouldLockInService) {
                tripStatus6ViewportLockedRef.current = true;
            }
        };
        if (deps.tripStatus === TripStatus.InService && deps.routePoints.length > 0) {
            const { dropoffSite } = resolveViewportSites();
            includeRouteToVisibleCenter(dropoffSite, true);
            return;
        }
        if (deps.tripStatus === TripStatus.VehicleApproaching && deps.routePoints.length > 0) {
            const { pickupSite } = resolveViewportSites();
            includeRouteToVisibleCenter(pickupSite, false);
            return;
        }
        holdDynamicScale();
@@ -477,21 +488,32 @@
                }
                deps.setLongitude(res.longitude);
                deps.setLatitude(res.latitude);
                if (deps.tripStatus === TripStatus.InService && deps.routePoints.length > 0) {
                    const { dropoffSite } = resolveViewportSites();
                    const dropoffPoint = buildSiteViewportPoint(dropoffSite);
                const includeRouteToVisibleCenter = (targetSite: any, shouldLockInService: boolean) => {
                    const targetPoint = buildSiteViewportPoint(targetSite);
                    const pointsToInclude = [...deps.routePoints];
                    if (dropoffPoint) pointsToInclude.push(dropoffPoint);
                    const bottomPadding = computeBottomPadding(pointsToInclude, 'route');
                    if (targetPoint) {
                        pointsToInclude.push(targetPoint);
                    }
                    // 与 toOrigin 保持一致,接驾/送驾定位回中时统一按整路线居中。
                    const bottomPadding = computeBottomPadding(pointsToInclude, 'route') - 88;
                    const topPadding = Math.max(24, resolveSafeTopInset() + 32);
                    holdDynamicScale();
                    Taro.createMapContext('map').includePoints({
                        points: pointsToInclude,
                        padding: [topPadding, 100, bottomPadding, 100]
                    });
                    tripStatus6ViewportLockedRef.current = true;
                    if (shouldLockInService) {
                        tripStatus6ViewportLockedRef.current = true;
                    }
                };
                if (deps.tripStatus === TripStatus.InService && deps.routePoints.length > 0) {
                    const { dropoffSite } = resolveViewportSites();
                    includeRouteToVisibleCenter(dropoffSite, true);
                    return;
                }
                if (deps.tripStatus === TripStatus.VehicleApproaching && deps.routePoints.length > 0) {
                    const { pickupSite } = resolveViewportSites();
                    includeRouteToVisibleCenter(pickupSite, false);
                    return;
                }
                holdDynamicScale();
src/robotaxi/pages/order/detail/index.tsx
@@ -264,9 +264,9 @@
                <View className='car-name'>{orderData.plateNumber}</View>
                <View className='info'>
                  <Text className='car-color'>{orderData.vehicleColor}</Text>
                  <Text className='info-line'></Text>
                  {/* <Text className='info-line'></Text>
                  <Text className='car-code'>车身编码: </Text>
                  <Text className='code'>{orderData.vehicleCode}</Text>
                  <Text className='code'>{orderData.vehicleCode}</Text> */}
                </View>
              </View>
              <Image src={safeParse(orderData.vehiclePictures, {})?.url || 'https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/vehicle-default.png'} className='car-img' />
src/robotaxi/pages/share-trip/components/share-trip-view.tsx
@@ -121,8 +121,8 @@
                      <View className='car-card-detail-num'>{tripData?.plateNumber || '--'}</View>
                      <View className='car-card-detail-color'>
                        {tripData?.vehicleColor || '--'}
                        <View className='car-card-detail-color-line'></View>
                        车身编码: {tripData?.vehicleCode || '--'}
                        {/* <View className='car-card-detail-color-line'></View>
                        车身编码: {tripData?.vehicleCode || '--'} */}
                      </View>
                    </View>
                    {tripData?.vehiclePictures && (