fix(share-trip): 修复分享行程页地图视口抖动并新增行程结束状态处理
| | |
| | | payload: QueryOrderRoutePayload |
| | | ): Promise<any> => { |
| | | return request({ |
| | | url: _ROBOTAXI_HOST + `/order/api/v1/mini-program/order/queryOrderTrajectory`, |
| | | // url: _ROBOTAXI_HOST + `/order/api/v1/mini-program/order/queryOrderTrajectory`, |
| | | url: _ROBOTAXI_HOST + `/order/base/v1/mini-program/orderActive/share/queryOrderTrajectory`, |
| | | method: 'GET', |
| | | payload, |
| | | showToast: false, |
| | |
| | | }, true); |
| | | } |
| | | |
| | | // 分享订单查询实时轨迹路线 |
| | | export const shareQueryOrderRoute = async (orderId: OrderId): Promise<ShareQueryOrderRouteResponse> => { |
| | | return request({ |
| | | url: _ROBOTAXI_HOST + `/order/base/v1/mini-program/orderActive/share/queryOrderRoute/${orderId}`, |
| | | method: 'GET' |
| | | }, true); |
| | | } |
| | | |
| | | // 静默查询分享订单实时路线,供分享页自行处理业务异常,避免默认拦截 toast。 |
| | | export const shareQueryOrderRouteSilently = async (orderId: OrderId): Promise<any> => { |
| | | return request({ |
| | |
| | | method: 'GET', |
| | | showToast: false, |
| | | skipException: true |
| | | }, true); |
| | | } |
| | | |
| | | // 分享订单查询订单详情 |
| | | export const shareQueryOrderInfo = async ( |
| | | payload: ShareQueryOrderInfoPayload |
| | | ): Promise<ShareQueryOrderInfoResponse> => { |
| | | return request({ |
| | | url: _ROBOTAXI_HOST + '/order/base/v1/mini-program/orderActive/share/orderInfo', |
| | | method: 'GET', |
| | | payload |
| | | }, true); |
| | | } |
| | | |
| | |
| | | useAndroidNativeTrip1Callout: boolean |
| | | ) => { |
| | | if (!(pickupSite?.latitude && pickupSite?.longitude)) return null; |
| | | if (deps.isAndroid && [TripStatus.VehicleArrivedPickup, TripStatus.InService].includes(deps.tripStatus)) { |
| | | if (deps.isAndroid && deps.tripStatus === TripStatus.InService) { |
| | | return null; |
| | | } |
| | | return { |
| | |
| | | ) => { |
| | | if (!(dropoffSite?.latitude && dropoffSite?.longitude)) return null; |
| | | // 分享行程只有从 5/6 及之后的状态才渲染下车点,避免 4 态提前入列引发地图多次缩放。 |
| | | if (deps.tripStatus < TripStatus.VehicleArrivedPickup) return null; |
| | | if (deps.tripStatus <= TripStatus.VehicleArrivedPickup) return null; |
| | | const dropoffName = |
| | | [TripStatus.ArrivedDestination].includes(deps.tripStatus) ? '已到达' : dropoffSite.name || '目的地'; |
| | | return { |
| | |
| | | const shouldWaitArrivedDirection = deps.tripStatus === TripStatus.ArrivedDestination && !deps.arrivedMarkerReady; |
| | | const effectiveShowCar = deps.statusRule.showCar && !shouldWaitArrivedDirection; |
| | | const shouldUseAndroidDropoffOnly = |
| | | deps.isAndroid && [TripStatus.VehicleArrivedPickup, TripStatus.InService].includes(deps.tripStatus); |
| | | deps.isAndroid && deps.tripStatus === TripStatus.InService; |
| | | const carMarker = createCarMarker(); |
| | | const nextMarkers: any[] = []; |
| | | if (!shouldUseAndroidDropoffOnly && deps.statusRule.showPickup && pickupMarker) nextMarkers.push(pickupMarker); |
| | |
| | | const viewportKeyRef = useRef<string>(""); |
| | | const orderDetailSyncTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null); |
| | | const completedOrderDetailViewportKeyRef = useRef<string>(""); |
| | | const arrivedPickupCenteredRef = useRef(false); // 到达上车点后仅回中一次,避免重复抖动 |
| | | const dynamicScaleHoldUntilRef = useRef(0); |
| | | const lastActiveTripViewportSyncAtRef = useRef(0); |
| | | const activeTripViewportSyncingRef = useRef(false); |
| | |
| | | keyParts.push(pickupSite?.latitude, pickupSite?.longitude); |
| | | return { points, keyParts }; |
| | | } |
| | | if (viewportType === "pickup_center") { |
| | | const pickupPoint = buildSiteViewportPoint(pickupSite); |
| | | if (pickupPoint) points.push(pickupPoint); |
| | | keyParts.push(pickupSite?.latitude, pickupSite?.longitude); |
| | | return { points, keyParts }; |
| | | } |
| | | if (viewportType === "route") { |
| | | if (deps.routePoints.length > 0) points.push(...deps.routePoints); |
| | | keyParts.push(buildPointsSignature(deps.routePoints)); |
| | |
| | | : [topPadding, 50, bottomPadding, 50]; |
| | | holdDynamicScale(); |
| | | Taro.nextTick(() => { |
| | | if (viewportType === "pickup_center") { |
| | | if (activeTripViewportSyncTimerRef.current) { |
| | | clearTimeout(activeTripViewportSyncTimerRef.current); |
| | | activeTripViewportSyncTimerRef.current = null; |
| | | } |
| | | mapCtx.moveToLocation({ |
| | | latitude: points[0].latitude, |
| | | longitude: points[0].longitude |
| | | }); |
| | | activeTripViewportSyncTimerRef.current = setTimeout(() => { |
| | | if (typeof deps.setLatitude === "function") { |
| | | deps.setLatitude(points[0].latitude); |
| | | } |
| | | if (typeof deps.setLongitude === "function") { |
| | | deps.setLongitude(points[0].longitude); |
| | | } |
| | | activeTripViewportSyncTimerRef.current = null; |
| | | }, ACTIVE_TRIP_VIEWPORT_SYNC_ANIMATION_MS); |
| | | return; |
| | | } |
| | | if (viewportType === "dropoff") { |
| | | mapCtx.moveToLocation({ |
| | | latitude: points[0].latitude, |
| | |
| | | if (![TripStatus.VehicleApproaching, TripStatus.InService].includes(deps.tripStatus)) { |
| | | lastActiveTripViewportSyncAtRef.current = 0; |
| | | activeTripViewportSyncingRef.current = false; |
| | | if (activeTripViewportSyncTimerRef.current) { |
| | | clearTimeout(activeTripViewportSyncTimerRef.current); |
| | | activeTripViewportSyncTimerRef.current = null; |
| | | } |
| | | return; |
| | | } |
| | | syncActiveTripViewportToVehicle(); |
| | |
| | | deps.vehicleLocation?.latitude, |
| | | deps.vehicleLocation?.longitude, |
| | | syncActiveTripViewportToVehicle |
| | | ]); |
| | | |
| | | // 与 begin-route 保持一致:待上车时把车辆/上车点一次性回中到可用视区中央, |
| | | // 并回写受控中心点,避免后续重渲染把地图拉回旧中心。 |
| | | useEffect(() => { |
| | | if (deps.tripStatus !== TripStatus.VehicleArrivedPickup) { |
| | | arrivedPickupCenteredRef.current = false; |
| | | return; |
| | | } |
| | | const pickupLatitude = Number(deps.startSite?.latitude); |
| | | const pickupLongitude = Number(deps.startSite?.longitude); |
| | | if (!Number.isFinite(pickupLatitude) || !Number.isFinite(pickupLongitude)) { |
| | | return; |
| | | } |
| | | if (arrivedPickupCenteredRef.current) { |
| | | return; |
| | | } |
| | | arrivedPickupCenteredRef.current = true; |
| | | holdDynamicScale(); |
| | | const moveAndCommitCenter = (centerLatitude: number, centerLongitude: number) => { |
| | | Taro.createMapContext("map").moveToLocation({ |
| | | latitude: centerLatitude, |
| | | longitude: centerLongitude |
| | | }); |
| | | setTimeout(() => { |
| | | deps.setLatitude?.(centerLatitude); |
| | | deps.setLongitude?.(centerLongitude); |
| | | }, ACTIVE_TRIP_VIEWPORT_SYNC_ANIMATION_MS); |
| | | }; |
| | | Promise.all([ensureMapRect(), getMapRegion()]) |
| | | .then(([mapRect, region]) => { |
| | | const safeAreaMetrics = buildActiveTripSafeAreaMetrics({ |
| | | tripStatus: TripStatus.VehicleArrivedPickup, |
| | | mapHeight: Number(mapRect?.height), |
| | | bottomPadding: mapBottomPaddingRef.current, |
| | | safeTopInset: resolveSafeTopInset() |
| | | }); |
| | | const pickupScreenPosition = computeMapPointScreenPosition( |
| | | { latitude: pickupLatitude, longitude: pickupLongitude }, |
| | | mapRect, |
| | | region |
| | | ); |
| | | const centerLatitude = (safeAreaMetrics && pickupScreenPosition) |
| | | ? pickupLatitude - (0.5 - safeAreaMetrics.targetMapRatio) * pickupScreenPosition.latitudeSpan |
| | | : pickupLatitude; |
| | | moveAndCommitCenter(centerLatitude, pickupLongitude); |
| | | }) |
| | | .catch(() => { |
| | | moveAndCommitCenter(pickupLatitude, pickupLongitude); |
| | | }); |
| | | }, [ |
| | | computeMapPointScreenPosition, |
| | | deps.setLatitude, |
| | | deps.setLongitude, |
| | | deps.startSite?.latitude, |
| | | deps.startSite?.longitude, |
| | | deps.tripStatus, |
| | | ensureMapRect, |
| | | getMapRegion, |
| | | holdDynamicScale |
| | | ]); |
| | | |
| | | useEffect(() => { |
| | |
| | | ]); |
| | | // 路线态统一交给 includePoints 计算视口,避免先写一次几何中心,再被视口纠正,出现地图“先偏后回”的抖动。 |
| | | // 这里只保留无路线视口的轻量兜底。 |
| | | if (center && [TripStatus.Publishing, TripStatus.CallingCar, TripStatus.VehicleArrivedPickup].includes(mappedStatus)) { |
| | | if (center && [TripStatus.Publishing, TripStatus.CallingCar].includes(mappedStatus)) { |
| | | deps.setLongitude(center.longitude); |
| | | deps.setLatitude(center.latitude); |
| | | } |
| | |
| | | stopPolling(); |
| | | return; |
| | | } |
| | | if ([TripStatus.TripFinished, TripStatus.PaymentSuccess].includes(infoState.mappedStatus)) { |
| | | const routeResponse = unwrapSilentResponse( |
| | | await requestShareRouteByStatus(infoState.mappedStatus) |
| | | ); |
| | | if (cancelled) return; |
| | | syncShareRoute(routeResponse, infoState.mappedStatus, infoState.nextStartSite, infoState.nextEndSite); |
| | | stopPolling(); |
| | | errorToastShownRef.current = false; |
| | | return; |
| | | } |
| | | const shouldContinuePolling = await fetchShareTripData(); |
| | | if (cancelled) return; |
| | | if (shouldContinuePolling) { |
| | |
| | | [TripStatus.Publishing]: { showPickup: true, showDropoff: false, showCar: false, showRoute: false, showWalking: false, viewport: 'pickup', translateCar: false }, |
| | | [TripStatus.CallingCar]: { showPickup: true, showDropoff: false, showCar: false, showRoute: false, showWalking: false, viewport: 'pickup', translateCar: false }, |
| | | [TripStatus.VehicleApproaching]: { showPickup: true, showDropoff: false, showCar: true, showRoute: true, showWalking: false, viewport: 'route', translateCar: true }, |
| | | [TripStatus.VehicleArrivedPickup]: { showPickup: true, showDropoff: false, showCar: true, showRoute: false, showWalking: false, viewport: 'car_user', translateCar: true }, |
| | | [TripStatus.VehicleArrivedPickup]: { showPickup: true, showDropoff: false, showCar: true, showRoute: false, showWalking: false, viewport: 'pickup_center', translateCar: true }, |
| | | [TripStatus.InService]: { showPickup: false, showDropoff: true, showCar: true, showRoute: true, showWalking: false, viewport: 'route', translateCar: true }, |
| | | [TripStatus.ArrivedDestination]: { showPickup: false, showDropoff: true, showCar: false, showRoute: true, showWalking: false, viewport: 'order_detail', translateCar: false }, |
| | | [TripStatus.TripFinished]: { showPickup: true, showDropoff: true, showCar: false, showRoute: true, showWalking: false, viewport: 'order_detail', translateCar: false }, |