| | |
| | | convertAdcodeToCityCode, |
| | | getCityInfoWithId, |
| | | getDistance, |
| | | getProjectedPoint, |
| | | mapOrderStatusToTripStatus, |
| | | reportEvent |
| | | } from '../../../utils/Robotaxi-public-method'; |
| | |
| | | const orderRouteBound = useRef(false); // 订单路线是否绑定 |
| | | const openTrunkBound = useRef(false); // 打开后备箱事件是否绑定 |
| | | const orderUpdatePriceBound = useRef(false); // 订单价格更新事件是否绑定 |
| | | const orderReassignBound = useRef(false); // 订单重新指派事件是否绑定 |
| | | const authSuccessHandlerRef = useRef<(data: any) => void>(); // 认证成功处理函数 |
| | | const messageHandlerRef = useRef<(data: any) => void>(); // 消息处理函数 |
| | | const orderStatusHandlerRef = useRef<(data: any) => void>(); // 订单状态处理函数 |
| | | const orderRouteHandlerRef = useRef<(data: any) => void>(); // 订单路线处理函数 |
| | | const openTrunkHandlerRef = useRef<(data: any) => void>(); // 打开后备箱事件处理函数 |
| | | const orderUpdatePriceHandlerRef = useRef<(data: any) => void>(); // 订单价格更新事件处理函数 |
| | | const orderReassignHandlerRef = useRef<(data: any) => void>(); // 订单重新指派事件处理函数 |
| | | const socketOpenHandlerRef = useRef<(() => void) | null>(null); // WebSocket连接打开处理函数 |
| | | // 记录已为某订单拉取过车辆信息,避免重复 |
| | | const lastFetchedVehicleOrderIdRef = useRef<string | null>(null); |
| | |
| | | }; |
| | | |
| | | // 使用 eraseLines 擦除已行驶路段(状态4/6专用) |
| | | const erasePassedRouteSegments = (newPoints: any[]) => { |
| | | const erasePassedRouteSegments = (newPoints: any[], served?: number) => { |
| | | const oldPoints = currentFullRouteRef.current; |
| | | if (!oldPoints?.length || !newPoints?.length) return; |
| | | if (!oldPoints?.length || !newPoints?.length) return newPoints?.[0]; |
| | | |
| | | const newFirst = newPoints[0]; |
| | | let bestMatchIndex = -1; |
| | | let bestDistance = Infinity; |
| | | const startIndex = lastErasedIndexRef.current; |
| | | |
| | | // 如果后端提供了明确的已行驶点数 served (作为增量:这次少了几个点) |
| | | if (typeof served === 'number' && !Number.isNaN(served) && served >= 0) { |
| | | bestMatchIndex = startIndex + served; |
| | | bestMatchIndex = Math.min(bestMatchIndex, oldPoints.length - 1); |
| | | } else { |
| | | let bestDistance = Infinity; |
| | | // 降级使用距离匹配逻辑,移除不合理的退出条件,使匹配更加敏感 |
| | | for (let i = startIndex; i < oldPoints.length; i++) { |
| | | const dist = getDistance( |
| | | oldPoints[i].latitude, oldPoints[i].longitude, |
| | |
| | | bestDistance = dist; |
| | | bestMatchIndex = i; |
| | | } |
| | | // 已找到足够近的匹配点且距离开始增大,提前退出 |
| | | if (dist > bestDistance * 3 && bestDistance < 100) break; |
| | | // 如果找到了非常近的点(例如10米内),就可以认为这就是车辆当前位置所在的索引,提前结束查找 |
| | | if (bestDistance < 10) break; |
| | | } |
| | | } |
| | | |
| | | if (bestMatchIndex >= startIndex && bestDistance < 500) { |
| | | if (bestMatchIndex < startIndex) { |
| | | // 路线发生较大变化,回退为全量重绘 |
| | | currentFullRouteRef.current = [...newPoints]; |
| | | lastErasedIndexRef.current = 0; |
| | | lastRoutePointRef.current = null; |
| | | lastRouteUpdateAtRef.current = 0; |
| | | setRoutePoints([...newPoints]); |
| | | return newPoints[0]; |
| | | } |
| | | |
| | | // 只要找到了比之前更大的索引,就进行擦除(无论距离多远,只要是往后走就应该擦除) |
| | | if (bestMatchIndex > startIndex) { |
| | | const mapCtx = Taro.createMapContext('map'); |
| | | |
| | | const eraseIndex = Math.max(0, bestMatchIndex - 1); |
| | |
| | | }); |
| | | |
| | | lastErasedIndexRef.current = bestMatchIndex; |
| | | } else { |
| | | // 路线发生较大变化,回退为全量重绘 |
| | | currentFullRouteRef.current = [...newPoints]; |
| | | lastErasedIndexRef.current = 0; |
| | | lastRoutePointRef.current = null; |
| | | lastRouteUpdateAtRef.current = 0; |
| | | setRoutePoints([...newPoints]); |
| | | } |
| | | |
| | | const nextIndex = Math.min(bestMatchIndex + 1, oldPoints.length - 1); |
| | | const pointA = oldPoints[bestMatchIndex]; |
| | | const pointB = oldPoints[nextIndex]; |
| | | |
| | | return getProjectedPoint(newFirst, pointA, pointB); |
| | | }; |
| | | |
| | | // 更新车辆位置(移除节流,实时更新) |
| | |
| | | } |
| | | setPriceUpdateVersion((v) => v + 1); |
| | | }; |
| | | |
| | | orderReassignHandlerRef.current = (payload) => { |
| | | const incomingOrderId = payload?.orderId || payload?.content?.orderId || Taro.getStorageSync('orderId'); |
| | | const currentOrderId = orderId || Taro.getStorageSync('orderId'); |
| | | if (incomingOrderId && currentOrderId && String(incomingOrderId) !== String(currentOrderId)) { |
| | | return; |
| | | } |
| | | // 收到重新指派消息,清除上次记录的订单号,触发重新获取车辆信息 |
| | | lastFetchedVehicleOrderIdRef.current = null; |
| | | queryVehicleByOrderId({ orderId: currentOrderId }) |
| | | .then((res: any) => { |
| | | setVehicleInfo(res); |
| | | }) |
| | | .catch(() => { }); |
| | | }; |
| | | |
| | | // 优化订单状态回调中的车辆信息拉取逻辑 |
| | | orderStatusHandlerRef.current = (payload) => { |
| | | const changeStatusOld = tripStatusRef.current; |
| | |
| | | }; |
| | | |
| | | orderRouteHandlerRef.current = (payload) => { |
| | | if (tripStatusRef.current === 5) { |
| | | if ([5, 8, 9].includes(tripStatusRef.current)) { |
| | | return; |
| | | } |
| | | const points = payload?.points || []; |
| | |
| | | // 状态4/6:使用 eraseLines 擦除已行驶路段,不再全量重绘 |
| | | const isEraseStatus = [4, 6].includes(tripStatusRef.current); |
| | | if (isEraseStatus) { |
| | | const firstPoint = points?.[0]; |
| | | let vehiclePoint = points?.[0]; |
| | | if (orderRouteInitializedRef.current && currentFullRouteRef.current.length > 0) { |
| | | // 后续更新:擦除已行驶路段 |
| | | erasePassedRouteSegments(points); |
| | | let servedCount = 0; |
| | | try { |
| | | const servedData = JSON.parse(payload?.content?.route || '{}')?.served; |
| | | // 尝试将 served 解析为数组,获取其长度,否则如果是数字则直接使用,或者是字符串数组再解析 |
| | | if (Array.isArray(servedData)) { |
| | | servedCount = servedData.length; |
| | | } else if (typeof servedData === 'string') { |
| | | const parsedServed = JSON.parse(servedData); |
| | | if (Array.isArray(parsedServed)) { |
| | | servedCount = parsedServed.length; |
| | | } |
| | | } else if (typeof servedData === 'number') { |
| | | servedCount = servedData; |
| | | } |
| | | } catch (e) { |
| | | console.error('解析 served 数据失败', e); |
| | | } |
| | | vehiclePoint = erasePassedRouteSegments(points, servedCount) || points?.[0]; |
| | | } else { |
| | | // 首次绘制:全量渲染并存储完整路线 |
| | | orderRouteInitializedRef.current = true; |
| | |
| | | applyRoutePoints(points); |
| | | }); |
| | | } |
| | | if (firstPoint && typeof firstPoint.latitude === 'number' && typeof firstPoint.longitude === 'number') { |
| | | updateVehicleLocationThrottled(firstPoint.latitude, firstPoint.longitude, true); |
| | | if (vehiclePoint && typeof vehiclePoint.latitude === 'number' && typeof vehiclePoint.longitude === 'number') { |
| | | updateVehicleLocationThrottled(vehiclePoint.latitude, vehiclePoint.longitude, true); |
| | | } |
| | | return; |
| | | } |
| | |
| | | if (orderUpdatePriceBound.current && orderUpdatePriceHandlerRef.current) { |
| | | wsManager.off('order_update_price', orderUpdatePriceHandlerRef.current); |
| | | orderUpdatePriceBound.current = false; |
| | | } |
| | | if (orderReassignBound.current && orderReassignHandlerRef.current) { |
| | | wsManager.off('order_reassign', orderReassignHandlerRef.current); |
| | | orderReassignBound.current = false; |
| | | } |
| | | }; |
| | | }, []); |
| | |
| | | wsManager.on('order_update_price', orderUpdatePriceHandlerRef.current); |
| | | orderUpdatePriceBound.current = true; |
| | | } |
| | | if (!orderReassignBound.current && orderReassignHandlerRef.current) { |
| | | wsManager.on('order_reassign', orderReassignHandlerRef.current); |
| | | orderReassignBound.current = true; |
| | | } |
| | | }; |
| | | |
| | | const ensureSocketListeners = () => { |