Merge branch 'feature_v2.0' into hc/fix_630
| | |
| | | // order_detail 视口(行程已结束/支付成功)下的上车点 marker 会显示向上突出的 customCallout 气泡, |
| | | // 需要在系统安全区之上再叠加 ≈灵动岛 + 气泡高度的缓冲,避免气泡被灵动岛/状态栏遮挡。 |
| | | // 数值与接驾态 ACTIVE_TRIP_CAMERA_TOP_EXTRA_PADDING 保持一致(80),其它视口沿用原有 32。 |
| | | const topInsetExtra = |
| | | viewportType === "order_detail" |
| | | ? ROUTE_VIEWPORT_TOP_EXTRA_PADDING + 10 |
| | | : ROUTE_VIEWPORT_TOP_EXTRA_PADDING; |
| | | const topInsetExtra = ROUTE_VIEWPORT_TOP_EXTRA_PADDING |
| | | const topPadding = Math.max( |
| | | baseTopPadding, |
| | | resolveSafeTopInset() + topInsetExtra |
| | |
| | | } else if (s && s.latitude && s.longitude) { |
| | | if([TripStatus.VehicleApproaching, TripStatus.InService].includes(cachedTripStatus)) { |
| | | deps.getLocationInfo(); |
| | | } else { |
| | | } else if (![TripStatus.TripFinished, TripStatus.PaymentSuccess].includes(cachedTripStatus)) { |
| | | // 完成态(TripFinished/PaymentSuccess)地图中心由 useMapViewport 的 order_detail includePoints 主导, |
| | | // 这里不再用上车点覆盖,否则受控中心会被拉到路线一端导致路线偏离屏幕中央。 |
| | | deps.setLatitude(s.latitude); |
| | | deps.setLongitude(s.longitude); |
| | | } |
| | |
| | | /** 地图视口最小顶部内边距。 */ |
| | | export const ROUTE_VIEWPORT_MIN_TOP_PADDING = 32; |
| | | /** 地图视口顶部附加安全区内边距。 */ |
| | | export const ROUTE_VIEWPORT_TOP_EXTRA_PADDING = 50; |
| | | export const ROUTE_VIEWPORT_TOP_EXTRA_PADDING = 60; |
| | | /** 地图视口底部附加安全区内边距,因为地图的高度是 87vh,到时底部 padding 偏高,要减去一点 */ |
| | | export const ROUTE_VIEWPORT_BOTTOM_EXTRA_PADDING = 0; |
| | | /** 地图视口左右内边距。 */ |
| | |
| | | longitude: task.longitude, |
| | | }, |
| | | autoRotate: false, |
| | | moveWithRotate: false, |
| | | moveWithRotate: true, |
| | | rotate: Math.round(task.rotate), |
| | | duration, |
| | | animationEnd: () => { |
| | |
| | | // 降低车辆位置更新频率 |
| | | return; |
| | | } |
| | | if (Number.isFinite(lat) && Number.isFinite(lng)) { |
| | | lastVehiclePointRef.current = { latitude: lat, longitude: lng }; |
| | | lastVehicleUpdateAtRef.current = now; |
| | | setVehicleLocation({ latitude: lat, longitude: lng }); |
| | | if (!Number.isFinite(lat) || !Number.isFinite(lng)) { |
| | | return; |
| | | } |
| | | const lastPoint = lastVehiclePointRef.current; |
| | | // 坐标与上次一致时跳过 setState:避免静止 / 重复点位推送产生无效重渲染 |
| | | // (朝向变化由 vehicleDirection 单独驱动,不依赖此处的 vehicleLocation 写入)。 |
| | | if ( |
| | | lastPoint |
| | | && Math.abs(lastPoint.latitude - lat) <= VEHICLE_LOCATION_EPSILON |
| | | && Math.abs(lastPoint.longitude - lng) <= VEHICLE_LOCATION_EPSILON |
| | | ) { |
| | | lastVehicleUpdateAtRef.current = now; |
| | | return; |
| | | } |
| | | lastVehiclePointRef.current = { latitude: lat, longitude: lng }; |
| | | lastVehicleUpdateAtRef.current = now; |
| | | setVehicleLocation({ latitude: lat, longitude: lng }); |
| | | }; |
| | | |
| | | useEffect(() => { |
| | |
| | | setRouteDistance: (value: any) => void; |
| | | setRouteDuration: (value: number | null) => void; |
| | | setModifyDestinationSocketStatus: (value: number | null) => void; |
| | | setOrderRouteMetrics?: (metrics: { |
| | | distanceMeters: number | null; |
| | | durationSeconds: number | null; |
| | | }) => void; |
| | | setOrderRouteMetrics?: ( |
| | | metrics: |
| | | | { |
| | | distanceMeters: number | null; |
| | | durationSeconds: number | null; |
| | | } |
| | | | ((prev: { |
| | | distanceMeters: number | null; |
| | | durationSeconds: number | null; |
| | | }) => { |
| | | distanceMeters: number | null; |
| | | durationSeconds: number | null; |
| | | }) |
| | | ) => void; |
| | | setBeforeUserEndSite: (site: { longitude: number; latitude: number } | null) => void; |
| | | setHasPreviousOrder: (value: boolean) => void; |
| | | isModifyDestinationReviewVisible?: boolean; |
| | |
| | | const durationSecondsRaw = Number(route?.duration); |
| | | const distanceKm = normalizeDistanceKm(distanceMeters); |
| | | if (distanceKm !== null) { |
| | | deps.setRouteDistance(distanceKm); |
| | | // 行程中后端会持续推送 ORDER_ROUTE(车辆静止时也在上报),normalizeDistanceKm 每次都会返回新对象, |
| | | // 直接 setRouteDistance 会让每条消息都因新引用触发无效重渲染。这里用函数式更新做按值去重: |
| | | // value/unit 未变化时返回旧引用,React 据此跳过本次重渲染。 |
| | | deps.setRouteDistance((prev: { value: number; unit: 'km' | 'm' } | null) => |
| | | prev && prev.value === distanceKm.value && prev.unit === distanceKm.unit ? prev : distanceKm |
| | | ); |
| | | } |
| | | const durationSeconds = normalizeDurationSeconds(durationSecondsRaw); |
| | | if (durationSeconds !== null) { |
| | | // number:值相同时 React 自动跳过重渲染,无需额外去重。 |
| | | deps.setRouteDuration(durationSeconds); |
| | | } |
| | | deps.setOrderRouteMetrics?.({ |
| | | distanceMeters: Number.isFinite(distanceMeters) ? distanceMeters : null, |
| | | durationSeconds: Number.isFinite(durationSecondsRaw) ? durationSecondsRaw : null |
| | | }); |
| | | const nextDistanceMeters = Number.isFinite(distanceMeters) ? distanceMeters : null; |
| | | const nextDurationSeconds = Number.isFinite(durationSecondsRaw) ? durationSecondsRaw : null; |
| | | // orderRouteMetrics 同理:函数式更新按值去重,未变化保持旧引用以跳过重渲染。 |
| | | deps.setOrderRouteMetrics?.((prev) => |
| | | prev |
| | | && prev.distanceMeters === nextDistanceMeters |
| | | && prev.durationSeconds === nextDurationSeconds |
| | | ? prev |
| | | : { |
| | | distanceMeters: nextDistanceMeters, |
| | | durationSeconds: nextDurationSeconds |
| | | } |
| | | ); |
| | | }; |
| | | |
| | | /** |
| | |
| | | setDoorUnlockedInCurrentPage(false); |
| | | handleDidShow(router.params?.skipPageFlag, router.params?.fromModifyDestination); |
| | | updateMapViewportPadding(); |
| | | // 完成态下隐藏小程序再恢复时,受控中心点可能与原生地图实际中心脱钩,主动触发一次 |
| | | // order_detail includePoints 纠偏,避免路线被压在底部支付卡片附近。 |
| | | if ([TripStatus.TripFinished, TripStatus.PaymentSuccess].includes(tripStatusRef.current)) { |
| | | setOrderDetailViewportRefreshVersion((v) => v + 1); |
| | | } |
| | | }); |
| | | |
| | | /** |
| | |
| | | longitude: task.longitude, |
| | | }, |
| | | autoRotate: false, |
| | | moveWithRotate: false, |
| | | moveWithRotate: true, |
| | | rotate: task.rotate, |
| | | duration: Math.max(task.duration, 100), |
| | | animationEnd: () => { |
| | |
| | | const MAX_SHOW_COUNT = 5 // 默认最多显示5条 |
| | | const MAX_EXPANDED_COUNT = 10 |
| | | const MAX_SHOW_HISTORY = 3 // 默认历史记录最多3条 |
| | | const RECOMMEND_SHOW_COUNT = 15 // 推荐站点默认展示数量 |
| | | |
| | | const router = Taro.useRouter(); |
| | | |
| | |
| | | : recommendSourceList; |
| | | const sortedHistorySite = sortSitesByCollectedFirst(historySite); |
| | | const visibleHistory = showAllHistory ? sortedHistorySite.slice(0, MAX_EXPANDED_COUNT) : sortedHistorySite.slice(0, MAX_SHOW_HISTORY); |
| | | const visibleRecommend = showAllRecommend ? recommendList.slice(0, MAX_EXPANDED_COUNT) : recommendList.slice(0, MAX_SHOW_COUNT); |
| | | const visibleRecommend = showAllRecommend ? recommendList : recommendList.slice(0, RECOMMEND_SHOW_COUNT); |
| | | const canShowSearchFallback = !searchValue || (!isSearching && lastCompletedKeyword === searchValue.trim()); |
| | | |
| | | useEffect(() => { |
| | |
| | | }, true, true) |
| | | } |
| | | </View> |
| | | {recommendList.length > MAX_SHOW_COUNT && ( |
| | | {recommendList.length > RECOMMEND_SHOW_COUNT && ( |
| | | <View className='show-more' hoverClass='none' onClick={toggleRecommendShow}> |
| | | <Text className='more-text'>{showAllRecommend ? '收起' : '展示更多'}</Text> |
| | | <Image className={`more-icon ${showAllRecommend ? 'rotate-up' : ''}`} src="https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/arrow.png"></Image> |