| | |
| | | // 蓝牙车控连接与鉴权编排 |
| | | import useBluetoothCarControl from './hooks/use-bluetooth-car-control'; |
| | | import { toTripStatus, TripStatus } from './constants/trip-status'; |
| | | import { MODIFY_DESTINATION_SOCKET_STATUS_KEY } from './constants/modify-destination'; |
| | | import { getDistance } from '../../../utils/Robotaxi-public-method'; |
| | | |
| | | import backIcon from '../../../robotaxi/assets/back-icon.png' |
| | |
| | | durationSeconds: null, |
| | | speedKmh: null |
| | | }); |
| | | const [modifyDestinationUsedCount, setModifyDestinationUsedCount] = useState(0); // 本次行程已成功修改目的地次数 |
| | | const [lowSpeedDurationMs, setLowSpeedDurationMs] = useState(0); // 连续低速持续时长(毫秒) |
| | | const lowSpeedStartAtRef = useRef<number | null>(null); // 连续低速开始时间戳 |
| | | const [modifyDestinationSocketStatus, setModifyDestinationSocketStatus] = useState<number | null>(null); // 后端推送的修改目的地展示状态 |
| | | |
| | | const tripStatusRef = useRef(tripStatus); // 行程状态引用 |
| | | const lastTripStatusRef = useRef(tripStatus); // 上一次行程状态,用于检测状态变化 |
| | |
| | | Taro.setStorageSync('tripStatus', tripStatus); |
| | | }, [tripStatus]); |
| | | useEffect(() => { |
| | | setModifyDestinationUsedCount(0); |
| | | setOrderRouteMetrics({ |
| | | distanceMeters: null, |
| | | durationSeconds: null, |
| | | speedKmh: null |
| | | }); |
| | | lowSpeedStartAtRef.current = null; |
| | | setLowSpeedDurationMs(0); |
| | | const cachedSocketStatus = Taro.getStorageSync(MODIFY_DESTINATION_SOCKET_STATUS_KEY); |
| | | const cachedOrderId = String(cachedSocketStatus?.orderId || ''); |
| | | const nextOrderId = String(orderId || ''); |
| | | if (cachedOrderId && nextOrderId && cachedOrderId === nextOrderId) { |
| | | const cachedStatus = Number(cachedSocketStatus?.status); |
| | | setModifyDestinationSocketStatus(Number.isFinite(cachedStatus) ? cachedStatus : null); |
| | | return; |
| | | } |
| | | setModifyDestinationSocketStatus(null); |
| | | }, [orderId]); |
| | | // 行程状态显示规则配置:showPickup-显示上车点,showDropoff-显示下车点,showCar-显示车辆,showRoute-显示路线,showWalking-显示步行路线,viewport-视口类型,translateCar-车辆是否平移 |
| | | const STATUS_RULES: Record<TripStatus, StatusRule> = { |
| | |
| | | setEndSite, |
| | | toSelectSite, |
| | | onModifySuccess: () => { |
| | | setModifyDestinationUsedCount((prev) => prev + 1); |
| | | // 成功修改后触发路线重新获取 |
| | | // 下一次渲染时 isModifyDestinationReviewVisible 变为 false |
| | | // 我们需要强制让选路状态退出,同时获取后端的新行程路线 |
| | |
| | | : DEFAULT_REQUOTE_EXPIRE_SECONDS; // 重新报价有效期(秒) |
| | | const modifyDistanceLimitMeters = Number(distanceConfig?.xczSyDistance); // 修改目的地剩余里程限制(米) |
| | | const modifyDurationLimitMinutes = Number(distanceConfig?.xczSyTime); // 修改目的地剩余时间限制(分钟) |
| | | const modifyCountLimit = Number(distanceConfig?.xczCaCount); // 单次行程允许修改目的地次数上限 |
| | | const lowSpeedLimitKmh = Number(distanceConfig?.xczHmSpeedPerHour); // 低速豁免阈值(km/h) |
| | | const lowSpeedLimitMinutes = Number(distanceConfig?.xczHmDuration); // 低速豁免持续时间(分钟) |
| | | const isTripStatusAllowModifyEntry = [TripStatus.VehicleApproaching, TripStatus.VehicleArrivedPickup, TripStatus.InService].includes(tripStatus); |
| | | |
| | | useEffect(() => { |
| | | if (!isTripStatusAllowModifyEntry) { |
| | | lowSpeedStartAtRef.current = null; |
| | | setLowSpeedDurationMs(0); |
| | | return; |
| | | } |
| | | if (!Number.isFinite(lowSpeedLimitKmh) || lowSpeedLimitKmh <= 0) { |
| | | lowSpeedStartAtRef.current = null; |
| | | setLowSpeedDurationMs(0); |
| | | return; |
| | | } |
| | | const currentSpeed = Number(orderRouteMetrics?.speedKmh); |
| | | if (!Number.isFinite(currentSpeed) || currentSpeed >= lowSpeedLimitKmh) { |
| | | lowSpeedStartAtRef.current = null; |
| | | setLowSpeedDurationMs(0); |
| | | return; |
| | | } |
| | | const now = Date.now(); |
| | | if (!lowSpeedStartAtRef.current) { |
| | | lowSpeedStartAtRef.current = now; |
| | | setLowSpeedDurationMs(0); |
| | | return; |
| | | } |
| | | setLowSpeedDurationMs(now - lowSpeedStartAtRef.current); |
| | | }, [isTripStatusAllowModifyEntry, orderRouteMetrics?.speedKmh, lowSpeedLimitKmh]); |
| | | |
| | | const showModifyDestination = useMemo(() => { |
| | | if (!isTripStatusAllowModifyEntry) { |
| | |
| | | if (tripStatus !== TripStatus.InService) { |
| | | return true; |
| | | } |
| | | if (modifyDestinationSocketStatus === 0) { |
| | | return false; |
| | | } |
| | | if (modifyDestinationSocketStatus === 1) { |
| | | return true; |
| | | } |
| | | const hasDistanceLimit = Number.isFinite(modifyDistanceLimitMeters) && modifyDistanceLimitMeters > 0; |
| | | const hasDurationLimit = Number.isFinite(modifyDurationLimitMinutes) && modifyDurationLimitMinutes > 0; |
| | | const hasCountLimit = Number.isFinite(modifyCountLimit) && modifyCountLimit > 0; |
| | | const hasLowSpeedLimit = Number.isFinite(lowSpeedLimitKmh) && lowSpeedLimitKmh > 0; |
| | | const hasLowSpeedDurationLimit = Number.isFinite(lowSpeedLimitMinutes) && lowSpeedLimitMinutes > 0; |
| | | |
| | | const currentDistance = Number(orderRouteMetrics?.distanceMeters); |
| | | const currentDurationSeconds = Number(orderRouteMetrics?.durationSeconds); |
| | | const currentSpeed = Number(orderRouteMetrics?.speedKmh); |
| | | |
| | | const hitDistanceLimit = hasDistanceLimit && Number.isFinite(currentDistance) && currentDistance < modifyDistanceLimitMeters; |
| | | const hitDurationLimit = hasDurationLimit && Number.isFinite(currentDurationSeconds) && (currentDurationSeconds / 60) < modifyDurationLimitMinutes; |
| | | const hitCountLimit = hasCountLimit && modifyDestinationUsedCount >= modifyCountLimit; |
| | | const hitAnyLimit = hitDistanceLimit || hitDurationLimit || hitCountLimit; |
| | | |
| | | const hitLowSpeedExemption = hasLowSpeedLimit |
| | | && hasLowSpeedDurationLimit |
| | | && Number.isFinite(currentSpeed) |
| | | && currentSpeed < lowSpeedLimitKmh |
| | | && lowSpeedDurationMs >= lowSpeedLimitMinutes * 60 * 1000; |
| | | |
| | | if (hitLowSpeedExemption) { |
| | | return true; |
| | | } |
| | | return !hitAnyLimit; |
| | | return !(hitDistanceLimit || hitDurationLimit); |
| | | }, [ |
| | | isTripStatusAllowModifyEntry, |
| | | tripStatus, |
| | | modifyDestinationSocketStatus, |
| | | modifyDistanceLimitMeters, |
| | | modifyDurationLimitMinutes, |
| | | modifyCountLimit, |
| | | lowSpeedLimitKmh, |
| | | lowSpeedLimitMinutes, |
| | | orderRouteMetrics?.distanceMeters, |
| | | orderRouteMetrics?.durationSeconds, |
| | | orderRouteMetrics?.speedKmh, |
| | | modifyDestinationUsedCount, |
| | | lowSpeedDurationMs |
| | | orderRouteMetrics?.durationSeconds |
| | | ]); |
| | | const { |
| | | handleDidShow |
| | |
| | | setVehicleMoveAlongPoints, |
| | | setRouteDistance, |
| | | setRouteDuration, |
| | | setModifyDestinationSocketStatus, |
| | | setOrderRouteMetrics, |
| | | setBeforeUserEndSite, |
| | | erasePassedRouteSegments: routeErasePassedRouteSegments, |