Merge branch 'feature_v1.0' of http://gitlab.xiaopeng.local:18080/robotaxi1/xp-robotaxi-miniprogram into feature_v1.0
| | |
| | | doorType, |
| | | ...locationPayload |
| | | }).then((res: any) => { |
| | | console.log(res,'***********'); |
| | | console.log('解锁结果:', res); |
| | | |
| | | if (!res) { |
| | | Taro.showToast({ title: '解锁失败,请重试或联系客服', icon: 'none' }); |
| | |
| | | } |
| | | |
| | | if (doorType === 'trunk') { |
| | | const loadingText = trunkStatus ? '正在关闭后备箱' : '正在开启后备箱'; |
| | | const isCloseAction = !!trunkStatus; |
| | | const loadingText = isCloseAction ? '正在关闭后备箱' : '正在开启后备箱'; |
| | | Taro.showLoading({ title: loadingText, mask: true }); |
| | | |
| | | let pollCount = 0; |
| | | const maxPolls = 3; |
| | | const maxPolls = 5; |
| | | const pollInterval = 2000; |
| | | const expectedTrunkState = trunkStatus ? '0' : '1'; |
| | | const expectedTrunkState = isCloseAction ? 0 : 1; |
| | | const successToastText = isCloseAction ? '关闭后备箱成功' : '打开后备箱成功'; |
| | | const failToastText = isCloseAction ? '关闭后备箱失败' : '开启后备箱失败'; |
| | | |
| | | const stopPolling = () => { |
| | | if (trunkPollTimerRef.current) { |
| | | clearTimeout(trunkPollTimerRef.current); |
| | | trunkPollTimerRef.current = null; |
| | | } |
| | | }; |
| | | |
| | | const handlePollFail = (reason: string, actualValue?: any) => { |
| | | pollCount++; |
| | | if (pollCount < maxPolls) { |
| | | stopPolling(); |
| | | trunkPollTimerRef.current = setTimeout(doPoll, pollInterval); |
| | | } else { |
| | | stopPolling(); |
| | | Taro.hideLoading(); |
| | | Taro.showToast({ |
| | | title: trunkStatus ? '关闭后备箱失败' : '开启后备箱失败', |
| | | title: failToastText, |
| | | icon: 'none' |
| | | }); |
| | | } |
| | |
| | | |
| | | const doPoll = () => { |
| | | queryVehicleTrunkOpenStatus({ orderId: targetOrderId }).then((pollRes: any) => { |
| | | const data = pollRes; |
| | | const rawValue = data?.stateMap?.trunkAjarCloseSt?.value; |
| | | if (!data || rawValue === undefined || rawValue === null || rawValue === '') { |
| | | console.log('第', pollCount, '次查询后备箱状态:', pollRes); |
| | | |
| | | const rawValue = typeof pollRes === 'number' |
| | | ? pollRes |
| | | : ( |
| | | pollRes?.data ?? |
| | | pollRes?.stateMap?.trunkAjarCloseSt?.value ?? |
| | | pollRes?.value |
| | | ); |
| | | if (rawValue === undefined || rawValue === null || rawValue === '') { |
| | | handlePollFail('empty_data_or_value', rawValue); |
| | | return; |
| | | } |
| | | const value = String(rawValue); |
| | | const value = Number(rawValue); |
| | | if (Number.isNaN(value)) { |
| | | handlePollFail('invalid_value', rawValue); |
| | | return; |
| | | } |
| | | if (value === expectedTrunkState) { |
| | | const isOpen = value === '1'; |
| | | stopPolling(); |
| | | const isOpen = !isCloseAction; |
| | | setTrunkStatus(isOpen); |
| | | Taro.hideLoading(); |
| | | Taro.showToast({ |
| | | title: isOpen ? '打开成功' : '关闭成功', |
| | | title: successToastText, |
| | | icon: 'none' |
| | | }); |
| | | onSuccess?.(); |
| | |
| | | } |
| | | } |
| | | }).catch(() => { |
| | | console.log(res,'***********'); |
| | | |
| | | Taro.showToast({ title: '解锁失败,请重试或联系客服', icon: 'none' }); |
| | | }); |
| | | }; |
| | |
| | | if (tripStatus === 5) { |
| | | return ( |
| | | <View className="car-card-arrive"> |
| | | <View className={`car-card-arrive-item ${trunkStatus && 'close-btn-item'}`} onClick={() => handleUnlock('trunk')}> |
| | | <View className={`car-card-arrive-item ${trunkStatus && 'close-btn-item'}`} onClick={() => handleUnlock('trunk', () => setTrunkStatus(!trunkStatus))}> |
| | | <Image className="car-card-arrive-item-img" src={trunkStatus ? require('../../../../assets/trunk-open.png') : require('../../../../assets/trunk-close.png')} /> |
| | | <View className="car-card-arrive-item-text">{trunkStatus ? '关闭后备箱' : '打开后备箱'}</View> |
| | | </View> |
| | |
| | | <View className="car-card-reach-text">点击按钮开车门</View> |
| | | <Image className='car-card-reach-img' src='https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/door-anim.webp' /> |
| | | <View className="car-card-reach-btn"> |
| | | <View className={`car-card-reach-btn-item ${trunkStatus && 'close-btn-item'}`} onClick={() => handleUnlock('trunk')}> |
| | | <View className={`car-card-reach-btn-item ${trunkStatus && 'close-btn-item'}`} onClick={() => handleUnlock('trunk', () => setTrunkStatus(!trunkStatus))}> |
| | | <Image className="car-card-reach-btn-item-img" src={trunkStatus ? require('../../../../assets/trunk-open.png') : require('../../../../assets/trunk-close.png')} /> |
| | | <View className="car-card-reach-btn-item-text">{trunkStatus ? '关闭后备箱' : '打开后备箱'}</View> |
| | | </View> |
| | |
| | | } |
| | | |
| | | return null; |
| | | } |
| | | } |
| | |
| | | .join(';'); |
| | | const hasDropoffMarker = markersRef.current.some((m: any) => m.id === 2); |
| | | const shouldHoldMarkerByTranslate = [4, 6].includes(deps.tripStatus) && carMarkerInitialized.current && deps.statusRule.showCar && (!deps.statusRule.showDropoff || hasDropoffMarker); |
| | | const shouldSkipUpdate = shouldHoldMarkerByTranslate && (deps.isAndroid || tripStatus6MarkerRefreshedRef.current); |
| | | const shouldHoldMarkerWhenArrived = deps.tripStatus === 7 && carMarkerInitialized.current && deps.statusRule.showCar && (!deps.statusRule.showDropoff || hasDropoffMarker); |
| | | const shouldSkipUpdate = (shouldHoldMarkerByTranslate && (deps.isAndroid || tripStatus6MarkerRefreshedRef.current)) || shouldHoldMarkerWhenArrived; |
| | | applyMarkerState(nextMarkers, nextMarkersSignature, shouldSkipUpdate, carMarker); |
| | | }, [deps.tripStatus, deps.startSite?.name, deps.startSite?.latitude, deps.startSite?.longitude, deps.endSite?.name, deps.endSite?.latitude, deps.endSite?.longitude, deps.vehicleLocation, deps.vehicleDirection, deps.vehicleMarkerId, deps.isAndroid, deps.statusRule.showPickup, deps.statusRule.showCar, deps.statusRule.showDropoff]); |
| | | |
| | |
| | | setLatitude: () => { } |
| | | }; |
| | | |
| | | const DROPOFF_MAX_SCALE = 20; |
| | | |
| | | export default function useMapViewport(rawDeps?: Partial<Deps>) { |
| | | const deps = { ...defaultDeps, ...(rawDeps || {}) } as Deps; |
| | | // 地图底部留白 |
| | |
| | | ? [topPadding, 50, bottomPadding, 50] |
| | | : [topPadding, 100, bottomPadding, 100]; |
| | | Taro.nextTick(() => { |
| | | mapCtx.includePoints({ points, padding }); |
| | | if (viewportType === 'dropoff') { |
| | | mapCtx.moveToLocation({ |
| | | latitude: points[0].latitude, |
| | | longitude: points[0].longitude |
| | | }); |
| | | setTimeout(() => { |
| | | setMapScale(13); |
| | | setMapScale(DROPOFF_MAX_SCALE); |
| | | }, 50); |
| | | return; |
| | | } else { |
| | | mapCtx.includePoints({ points, padding }); |
| | | } |
| | | }); |
| | | }; |
| | |
| | | const getLocationInfo = () => { |
| | | Taro.getLocation({ type: 'gcj02' }) |
| | | .then((res) => { |
| | | if (deps.tripStatus === 7) { |
| | | return; |
| | | } |
| | | deps.setLongitude(res.longitude); |
| | | deps.setLatitude(res.latitude); |
| | | if (deps.tripStatus === 6 && deps.routePoints.length > 0) { |
| | |
| | | }, [deps.tripStatus]); |
| | | |
| | | useEffect(() => { |
| | | const viewportType = deps.statusRule.viewport; |
| | | if (viewportType !== 'dropoff') return; |
| | | const { pickupSite, dropoffSite } = resolveViewportSites(); |
| | | const { points, keyParts } = buildViewportPayload(viewportType, pickupSite, dropoffSite); |
| | | if (points.length === 0) return; |
| | | const nextKey = keyParts.join('|'); |
| | | if (nextKey === viewportKeyRef.current) return; |
| | | viewportKeyRef.current = nextKey; |
| | | updateViewportByPayload(viewportType, points); |
| | | }, [deps.tripStatus, deps.statusRule?.viewport, deps.endSite?.latitude, deps.endSite?.longitude]); |
| | | |
| | | useEffect(() => { |
| | | const { pickupSite, dropoffSite } = resolveViewportSites(); |
| | | const viewportType = deps.statusRule.viewport; |
| | | if (viewportType === 'dropoff') return; |
| | | const { points, keyParts } = buildViewportPayload(viewportType, pickupSite, dropoffSite); |
| | | if (points.length === 0) return; |
| | | if (deps.tripStatus === 6 && viewportType === 'route' && tripStatus6ViewportLockedRef.current) return; |
| | |
| | | * 同步地图定位并按状态初始化路线。 |
| | | */ |
| | | const syncLocationAndInitRoute = (s: any, e: any, cachedTripStatus: number) => { |
| | | if (s && s.latitude && s.longitude) { |
| | | // 状态 7 直接以下车点为中心,避免 getLocationInfo 抢占视口中心 |
| | | if (cachedTripStatus === 7) { |
| | | const dropoffLat = Number(e?.latitude); |
| | | const dropoffLng = Number(e?.longitude); |
| | | if (Number.isFinite(dropoffLat) && Number.isFinite(dropoffLng)) { |
| | | deps.setLatitude(dropoffLat); |
| | | deps.setLongitude(dropoffLng); |
| | | } |
| | | } else if (s && s.latitude && s.longitude) { |
| | | deps.setLatitude(s.latitude); |
| | | deps.setLongitude(s.longitude); |
| | | } else { |
| | |
| | | orderRouteInitializedRef.current = false; |
| | | }; |
| | | |
| | | // 擦除已行驶路段 |
| | | const erasePassedRouteSegments = (newPoints: any[], servedPoints: any[] = []) => { |
| | | // 擦除已行驶路段(仅基于前后两次路线点差分,不依赖后端 served) |
| | | const erasePassedRouteSegments = (newPoints: any[], _servedPoints: any[] = []) => { |
| | | const oldPoints = currentFullRouteRef.current; |
| | | if (!oldPoints?.length || !newPoints?.length) return; |
| | | const servedLast = Array.isArray(servedPoints) && servedPoints.length > 0 |
| | | ? servedPoints[servedPoints.length - 1] |
| | | : null; |
| | | const hasServedBoundary = !!( |
| | | servedLast && |
| | | typeof servedLast.latitude === 'number' && |
| | | typeof servedLast.longitude === 'number' |
| | | ); |
| | | const boundaryPoint = hasServedBoundary ? servedLast : newPoints[0]; |
| | | const boundaryPoint = newPoints[0]; |
| | | if ( |
| | | !boundaryPoint || |
| | | typeof boundaryPoint.latitude !== 'number' || |
| | |
| | | } |
| | | if (dist > bestDistance * 3 && bestDistance < 100) break; |
| | | } |
| | | if (bestMatchIndex >= startIndex && bestDistance < 500) { |
| | | if (bestMatchIndex >= startIndex && bestDistance < 120) { |
| | | Taro.createMapContext('map').eraseLines({ |
| | | lines: [{ |
| | | id: 2001, |
| | |
| | | clear: true |
| | | }] |
| | | }); |
| | | if (hasServedBoundary) { |
| | | currentFullRouteRef.current = [...newPoints]; |
| | | lastErasedIndexRef.current = 0; |
| | | } else { |
| | | lastErasedIndexRef.current = bestMatchIndex; |
| | | } |
| | | // 同步 React 路由状态,避免仅原生擦线导致线和车不同步 |
| | | currentFullRouteRef.current = [...newPoints]; |
| | | lastErasedIndexRef.current = 0; |
| | | applyRoutePoints([...newPoints]); |
| | | return; |
| | | } |
| | | currentFullRouteRef.current = [...newPoints]; |
| | | lastErasedIndexRef.current = 0; |
| | | lastRoutePointRef.current = null; |
| | | lastRouteUpdateAtRef.current = 0; |
| | | setRoutePoints([...newPoints]); |
| | | applyRoutePoints([...newPoints]); |
| | | }; |
| | | |
| | | // 确保路线请求可用城市信息 |
| | |
| | | // 请求订单实时路线/轨迹 |
| | | const requestOrderRoute = (targetOrderId: string, status: number) => { |
| | | const routeType = status <= 5 ? 1 : 2; |
| | | const requestRoute = [7, 8, 9].includes(status) ? queryOrderTrajectory : queryOrderRoute; |
| | | const requestRoute = [8, 9].includes(status) ? queryOrderTrajectory : queryOrderRoute; |
| | | requestRoute({ orderId: targetOrderId, routeType }) |
| | | .then((res: any) => { |
| | | const rawPoints = Array.isArray(res?.polyline) ? res.polyline : []; |
| | |
| | | deps.updateVehicleLocationThrottled(last.latitude, last.longitude, true); |
| | | } else { |
| | | applyRoutePoints(points); |
| | | const first = points[0]; |
| | | deps.updateVehicleLocationThrottled(first.latitude, first.longitude, true); |
| | | const targetPoint = status === 7 |
| | | ? points[points.length - 1] |
| | | : points[0]; |
| | | deps.updateVehicleLocationThrottled(targetPoint.latitude, targetPoint.longitude, true); |
| | | if ([4, 6].includes(status)) { |
| | | currentFullRouteRef.current = [...points]; |
| | | lastErasedIndexRef.current = 0; |
| | | orderRouteInitializedRef.current = true; |
| | | } |
| | | } |
| | | } else if (status === 7) { |
| | | const cachedEndSite = Taro.getStorageSync('endSite') || {}; |
| | | const fallbackLat = Number(cachedEndSite?.latitude); |
| | | const fallbackLng = Number(cachedEndSite?.longitude); |
| | | if (Number.isFinite(fallbackLat) && Number.isFinite(fallbackLng)) { |
| | | deps.updateVehicleLocationThrottled(fallbackLat, fallbackLng, true); |
| | | } |
| | | } |
| | | const distanceKm = normalizeDistanceKm(Number(res?.distance)); |
| | | if (distanceKm !== null) { |
| | |
| | | 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 TRANSLATE_DURATION_MS = 100; |
| | | |
| | | // 更新车辆位置并维护最近位置引用 |
| | | 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; |
| | |
| | | if (!statusRule.translateCar) return; |
| | | if (!vehicleLocation) return; |
| | | const mapCtx = Taro.createMapContext('map'); |
| | | const timer = setTimeout(() => { |
| | | mapCtx.translateMarker({ |
| | | markerId: vehicleMarkerId, |
| | | destination: { |
| | | latitude: vehicleLocation.latitude, |
| | | longitude: vehicleLocation.longitude, |
| | | }, |
| | | autoRotate: false, |
| | | moveWithRotate: true, |
| | | rotate: typeof vehicleDirection === 'number' ? ((vehicleDirection % 360) + 360) % 360 : 0, |
| | | duration: translateDurationRef.current |
| | | }); |
| | | }, 100); |
| | | return () => clearTimeout(timer); |
| | | mapCtx.translateMarker({ |
| | | markerId: vehicleMarkerId, |
| | | destination: { |
| | | latitude: vehicleLocation.latitude, |
| | | longitude: vehicleLocation.longitude, |
| | | }, |
| | | autoRotate: false, |
| | | moveWithRotate: true, |
| | | rotate: typeof vehicleDirection === 'number' ? ((vehicleDirection % 360) + 360) % 360 : 0, |
| | | duration: TRANSLATE_DURATION_MS |
| | | }); |
| | | }, [statusRule.translateCar, vehicleLocation, vehicleDirection, vehicleMarkerId]); |
| | | |
| | | return { |
| | |
| | | isAndroid: boolean; |
| | | /** 行程状态 */ |
| | | tripStatus: number; |
| | | /** 地图缩放等级 */ |
| | | mapScale: number; |
| | | /** 地图 markers */ |
| | | markers: any[]; |
| | | /** 是否显示等待雷达 */ |
| | |
| | | </CoverView> |
| | | </CoverView> |
| | | )} |
| | | {(item.id === 2 && [7].includes(deps.tripStatus) && !deps.isAndroid) && ( |
| | | {(item.id === 2 && [7].includes(deps.tripStatus) && !deps.isAndroid && deps.mapScale >= 20) && ( |
| | | <CoverView className='custom-callout-content'> |
| | | 已到达 |
| | | </CoverView> |
| | |
| | | return null; |
| | | } |
| | | const currentTripStatus = Number(deps.tripStatusRef.current); |
| | | if (currentTripStatus > mappedTripStatus && currentTripStatus !== 10) { |
| | | return null; |
| | | // 行程进行关键态不允许被回退,避免 4/6 被延迟状态覆盖导致路线链路重置 |
| | | if ([4, 6].includes(currentTripStatus) && mappedTripStatus < currentTripStatus) { |
| | | return currentTripStatus; |
| | | } |
| | | if (currentTripStatus === mappedTripStatus) { |
| | | return mappedTripStatus; |
| | | } |
| | | deps.setTripStatus(mappedTripStatus); |
| | | deps.tripStatusRef.current = mappedTripStatus; |
| | |
| | | return null; |
| | | }; |
| | | |
| | | const resolveVehiclePointForErase = (points: any[], servedPoints: any[] = []) => { |
| | | const firstPoint = points?.[0]; |
| | | if (firstPoint && typeof firstPoint.latitude === 'number' && typeof firstPoint.longitude === 'number') { |
| | | return firstPoint; |
| | | } |
| | | return resolveVehiclePoint(points, servedPoints); |
| | | }; |
| | | |
| | | const syncVehiclePointWithRoute = (points: any[], deps: UseWebSocketEventsDeps, servedPoints: any[] = []) => { |
| | | const targetPoint = resolveVehiclePoint(points, servedPoints); |
| | | if (!targetPoint) { |
| | | return; |
| | | } |
| | | const currentTripStatus = Number(deps.tripStatusRef.current); |
| | | if (currentTripStatus === 7) { |
| | | const lastPoint = deps.lastVehiclePointRef.current; |
| | | const lastUpdateAt = Number(deps.lastVehicleUpdateAtRef.current || 0); |
| | | const now = Date.now(); |
| | | const latDiff = Math.abs(Number(lastPoint?.latitude || 0) - targetPoint.latitude); |
| | | const lngDiff = Math.abs(Number(lastPoint?.longitude || 0) - targetPoint.longitude); |
| | | const almostSamePoint = latDiff < 0.000003 && lngDiff < 0.000003; |
| | | if (almostSamePoint || (now - lastUpdateAt < 1200)) { |
| | | return; |
| | | } |
| | | } |
| | | deps.updateVehicleLocationThrottled(targetPoint.latitude, targetPoint.longitude, true); |
| | | }; |
| | | |
| | | const handleEraseRouteStatus = (points: any[], servedPoints: any[], deps: UseWebSocketEventsDeps) => { |
| | | const targetPoint = resolveVehiclePoint(points, servedPoints); |
| | | const targetPoint = resolveVehiclePointForErase(points, servedPoints); |
| | | if (targetPoint) { |
| | | deps.updateVehicleLocationThrottled(targetPoint.latitude, targetPoint.longitude, true); |
| | | } |
| | | if (deps.orderRouteInitializedRef.current && deps.currentFullRouteRef.current.length > 0) { |
| | | deps.erasePassedRouteSegments(points, servedPoints); |
| | | deps.erasePassedRouteSegments(points); |
| | | } else { |
| | | deps.orderRouteInitializedRef.current = true; |
| | | deps.currentFullRouteRef.current = [...points]; |
| | |
| | | deps.applyRoutePoints(points); |
| | | }); |
| | | } |
| | | if (targetPoint) { |
| | | setTimeout(() => { |
| | | deps.updateVehicleLocationThrottled(targetPoint.latitude, targetPoint.longitude, true); |
| | | }, 50); |
| | | } |
| | | }; |
| | | |
| | | 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; |
| | | if (![4, 5, 6, 7].includes(deps.tripStatusRef.current)) return; |
| | | syncVehiclePointWithRoute(points, deps, servedPoints); |
| | | }); |
| | | }; |
| | |
| | | deps.lastRouteUpdateAtRef.current = 0; |
| | | |
| | | Taro.nextTick(() => { |
| | | deps.orderRouteInitializedRef.current = true; |
| | | deps.orderRouteInitializedRef.current = points.length > 0; |
| | | deps.currentFullRouteRef.current = [...points]; |
| | | deps.lastErasedIndexRef.current = 0; |
| | | deps.applyRoutePoints(points); |
| | | syncVehiclePointWithRoute(points, deps, servedPoints); |
| | | if (points.length > 0) { |
| | | syncVehiclePointWithRoute(points, deps, servedPoints); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const handleOrderRoutePayload = (payload: any, deps: UseWebSocketEventsDeps) => { |
| | | if (deps.tripStatusRef.current === 5) return; |
| | | const points = payload?.points || []; |
| | | const servedPoints = Array.isArray(payload?.servedPoints) ? payload.servedPoints : []; |
| | | const forceFullRedraw = payload?.forceFullRedraw === true; |
| | | const currentTripStatus = Number(deps.tripStatusRef.current); |
| | | updateRouteSummary(payload, deps); |
| | | if ([4, 6].includes(deps.tripStatusRef.current)) { |
| | | if ([4, 6].includes(currentTripStatus)) { |
| | | deps.setVehicleMoveAlongPoints(servedPoints); |
| | | } |
| | | if (forceFullRedraw) { |
| | | handleForceFullRouteRedraw(points, deps, servedPoints); |
| | | return; |
| | | } |
| | | const isEraseStatus = [4, 6].includes(deps.tripStatusRef.current); |
| | | const isEraseStatus = ![7, 8, 9].includes(currentTripStatus); |
| | | if (isEraseStatus) { |
| | | handleEraseRouteStatus(points, servedPoints, deps); |
| | | return; |
| | |
| | | orderRouteHandlerRef.current = (payload) => { |
| | | handleOrderRoutePayload(payload, depsRef.current); |
| | | }; |
| | | // 处理重进页面时 useDidShow 先于 handler 初始化的场景,确保已连接状态下也能完成监听绑定 |
| | | if (wsManager.isConnectedStatus()) { |
| | | bindSocketListeners(); |
| | | } |
| | | |
| | | return () => { |
| | | if (authSuccessBound.current && authSuccessHandlerRef.current) { |
| | |
| | | const { renderMapOverlays, renderTripCard } = useViewDelegates({ |
| | | isAndroid, |
| | | tripStatus, |
| | | mapScale, |
| | | markers, |
| | | isRouteSelectExpanded, |
| | | onToggleRouteSelect: setIsRouteSelectExpanded, |
| | |
| | | getStorage, |
| | | objectSort, |
| | | } from '../utils/tools'; |
| | | import { _ROBOTAXI_HOST, _XP_SECRET, _UID } from '../constants/api'; |
| | | import { _XP_SECRET, _UID } from '../constants/api'; |
| | | import { jumpTo } from './jump'; |
| | | |
| | | const CODE_SUCCESS = 200 |
| | | const MINI_LOG_UPLOAD_PATH = '/operation/base/v1/mini-program/miniLog/uploadLog'; |
| | | const CODE_AUTH_EXPIRED_ARRAY = [12010301, 12010302, 12010303, 12010304, 12010305, 12010306, 12010320, 12010002]; |
| | | // 12010301, "登录状态已过期,请重新登录", "otp缓存已过期"), |
| | | // 12010302, "登录状态已过期,请重新登录", "otp已过期"), |
| | |
| | | header |
| | | }) |
| | | .then(async (res) => { |
| | | if (!isMiniLogUploadUrl(url)) { |
| | | uploadMiniLog( |
| | | { |
| | | data: JSON.stringify({ |
| | | type: 'http_error', |
| | | url, |
| | | request: payload, |
| | | response: res?.data, |
| | | timestamp: Date.now() |
| | | }) |
| | | } |
| | | ); |
| | | } |
| | | // res为包含cookies、header的经过小程序封装的数据 |
| | | // 第一层data为接口返回数据,包含接口状态码 |
| | | // 第二层data一般为业务数据 |
| | |
| | | return data |
| | | }) |
| | | .catch((err) => { |
| | | if (!isMiniLogUploadUrl(url)) { |
| | | uploadMiniLog( |
| | | { |
| | | data: JSON.stringify({ |
| | | type: 'http_error', |
| | | url, |
| | | request: payload, |
| | | response: err, |
| | | timestamp: Date.now() |
| | | }) |
| | | } |
| | | ); |
| | | } |
| | | console.log('request err:', url); |
| | | console.log(err); |
| | | |
| | |
| | | return Promise.reject(errData) |
| | | }); |
| | | } |
| | | |
| | | const isMiniLogUploadUrl = (url: string = '') => { |
| | | return typeof url === 'string' && url.includes(MINI_LOG_UPLOAD_PATH); |
| | | }; |
| | | |
| | | export const uploadMiniLog = async (logContent: any) => { |
| | | if (!logContent) return; |
| | | try { |
| | | const header = await buildHeader({ method: 'POST', payload: logContent }, false); |
| | | if (!header) return; |
| | | const uploadUrl = `${_ROBOTAXI_HOST}${MINI_LOG_UPLOAD_PATH}`; |
| | | Taro.request({ |
| | | url: uploadUrl, |
| | | method: 'POST', |
| | | data: logContent, |
| | | header: { |
| | | ...header, |
| | | 'Content-Type': 'application/json' |
| | | } |
| | | }).catch(() => { }); |
| | | } catch (_) { } |
| | | }; |
| | | |
| | | async function buildHeader(options, needLogin) { |
| | | const { method = 'POST', payload, extraHeader = {} } = options; |
| | |
| | | import { getStorage } from './tools'; |
| | | import { _UID } from '../constants/api'; |
| | | import { safeParse } from './Robotaxi-public-method'; |
| | | import { uploadMiniLog } from './request'; |
| | | |
| | | type MessageCallback = (data: any) => void; |
| | | |
| | |
| | | try { |
| | | data = safeParse(res.data as string, {}); |
| | | console.log('收到 WebSocket 消息:', res.data); |
| | | if (!this.isHeartbeatMessage(data)) { |
| | | const messageContent = typeof res.data === 'string' ? res.data : JSON.stringify(res.data); |
| | | uploadMiniLog({ data: messageContent }); |
| | | } |
| | | } catch (e) { |
| | | console.warn('解析 WebSocket data 失败:', res.data); |
| | | this.notifyListeners('message', res.data); |
| | |
| | | try { |
| | | data = safeParse(res.data as string, {}); |
| | | console.log('收到 WebSocket 消息:', res.data); |
| | | if (!this.isHeartbeatMessage(data)) { |
| | | const messageContent = typeof res.data === 'string' ? res.data : JSON.stringify(res.data); |
| | | uploadMiniLog(messageContent); |
| | | } |
| | | } catch (e) { |
| | | console.warn('解析 WebSocket data 失败:', res.data); |
| | | this.notifyListeners('message', res.data); |
| | |
| | | cached.latest = points; |
| | | } |
| | | Taro.setStorageSync('orderRoutePoints', cached); |
| | | this.notifyListeners('order_route', { |
| | | routeType, |
| | | direction, |
| | | points, |
| | | servedPoints, |
| | | data, |
| | | content, |
| | | forceFullRedraw: data?.type === 'ORDER_UPDATE_LINE' |
| | | }); |
| | | } |
| | | this.notifyListeners('order_route', { |
| | | routeType, |
| | | direction, |
| | | points, |
| | | servedPoints, |
| | | data, |
| | | content, |
| | | forceFullRedraw: data?.type === 'ORDER_UPDATE_LINE' |
| | | }); |
| | | } |
| | | if (data?.type === 'ORDER_UPDATE_PRICE') { |
| | | const orderId = content?.orderId ?? data?.orderId; |