import Taro from '@tarojs/taro';
|
import { View, Image, Text } from '@tarojs/components';
|
import { useEffect, useState } from 'react';
|
import { queryOrderQueueStatus } from '../../../../api/begin-route';
|
import { TripStatus } from '../../../../constants/trip-status';
|
|
type QueueStatus = {
|
currentPosition: number;
|
estimatedWaitTime: number | null;
|
status: number;
|
totalCount: number;
|
} | null;
|
|
type Props = {
|
orderId?: string;
|
tripStatus: TripStatus;
|
waitMinutes: number | null;
|
durationDisplay: { value: string | number; unit: string };
|
isArriveSoon: boolean;
|
isPickupCountdownSoon: boolean;
|
pickupCountdownSeconds: number | null;
|
doorUnlockedInCurrentPage: boolean;
|
finishCountdownEnabled: boolean;
|
finishCountdownSeconds: number | null;
|
limitMinutes: number | null;
|
routeDistance?: { value: number; unit: 'km' | 'm' } | null;
|
handleOpenCancelPopup?: (displayInfo: { durationDisplay: { value: string | number; unit: string }; waitMinutes: number | null }) => void;
|
queuePollingTimeSeconds: number;
|
};
|
|
export default function TripStatusHeader({
|
orderId,
|
tripStatus,
|
waitMinutes,
|
durationDisplay,
|
isArriveSoon,
|
isPickupCountdownSoon,
|
pickupCountdownSeconds,
|
doorUnlockedInCurrentPage,
|
finishCountdownEnabled,
|
finishCountdownSeconds,
|
limitMinutes,
|
routeDistance = null,
|
handleOpenCancelPopup,
|
queuePollingTimeSeconds
|
}: Props) {
|
const [queueStatus, setQueueStatus] = useState<QueueStatus>(null);
|
const pollingIntervalMs = Math.max(1000, Number(queuePollingTimeSeconds || 10) * 1000); // 排队位次轮询间隔
|
const normalizedDurationDisplay = durationDisplay.unit === '秒'
|
? { value: 1, unit: '分钟' as const }
|
: durationDisplay; // 剩余时间小于 1 分钟时按 1 分钟展示,不展示秒
|
const inServiceDurationDisplay = normalizedDurationDisplay; // 行程中沿用统一的归一化时长
|
// 排队接口返回实时预计等待分钟数;无有效值时回退下单时的初始预估。
|
const displayedWaitMinutes = queueStatus?.estimatedWaitTime ?? waitMinutes;
|
|
useEffect(() => {
|
if (tripStatus !== TripStatus.CallingCar || !orderId) {
|
setQueueStatus(null);
|
return;
|
}
|
|
let timer: ReturnType<typeof setInterval> | null = null;
|
let unmounted = false;
|
|
// 排队位次是动态变化的,状态为 3 时定时刷新
|
const fetchQueueStatus = async () => {
|
try {
|
const res = await queryOrderQueueStatus({ orderId });
|
if (unmounted) {
|
return;
|
}
|
const queueData = res?.data ?? res;
|
const rawEstimatedWaitTime = queueData?.estimatedWaitTime;
|
const estimatedWaitTime = rawEstimatedWaitTime === null || rawEstimatedWaitTime === undefined || rawEstimatedWaitTime === ''
|
? null
|
: Number(rawEstimatedWaitTime);
|
if (
|
Number(queueData?.currentPosition) > 0 &&
|
Number(queueData?.totalCount) > 0
|
) {
|
setQueueStatus({
|
currentPosition: Number(queueData.currentPosition),
|
estimatedWaitTime: typeof estimatedWaitTime === 'number' && Number.isFinite(estimatedWaitTime) && estimatedWaitTime >= 0 ? estimatedWaitTime : null,
|
status: Number(queueData.status) || 0,
|
totalCount: Number(queueData.totalCount)
|
});
|
return;
|
}
|
setQueueStatus(null);
|
} catch (_) {
|
if (!unmounted) {
|
setQueueStatus(null);
|
}
|
}
|
};
|
|
fetchQueueStatus();
|
timer = setInterval(fetchQueueStatus, pollingIntervalMs);
|
|
return () => {
|
unmounted = true;
|
if (timer) {
|
clearInterval(timer);
|
}
|
};
|
}, [tripStatus, orderId, pollingIntervalMs]);
|
|
// 标题行文案映射(已改为按状态直接渲染 DOM,保留注释供参考)
|
// const titleMap = {
|
// [TripStatus.CallingCar]: <>预计<View className='time'>{waitMinutes}</View>分钟内有车应答</>,
|
// [TripStatus.VehicleApproaching]: isArriveSoon
|
// ? <>车辆即将到达,请准备上车</>
|
// : <>车辆还有<View className='time'>{durationDisplay.value}</View>{durationDisplay.unit}到达</>,
|
// [TripStatus.VehicleArrivedPickup]: doorUnlockedInCurrentPage
|
// ? <>车辆已到达,请尽快上车</>
|
// : <>{isPickupCountdownSoon ? '车辆已到达,请尽快上车' : '车辆已到达上车点'}<View className='time'>{pickupCountdownSeconds}</View></>,
|
// [TripStatus.InService]: <>预计<View className='time'>{inServiceDurationDisplay.value}</View>{inServiceDurationDisplay.unit}抵达目的地</>,
|
// [TripStatus.ArrivedDestination]: (finishCountdownEnabled || finishCountdownSeconds !== null)
|
// ? <>已到达目的地<View className='time'>{finishCountdownSeconds}</View></>
|
// : <>已到达目的地</>,
|
// [TripStatus.TripFinished]: '行程已结束',
|
// [TripStatus.PaymentSuccess]: '支付成功'
|
// }
|
|
// 说明文案映射(已注释)
|
// const descMap = {
|
// [TripStatus.CallingCar]: { text: '正全力为您叫车中,请耐心等待...', className: 'calling-car-content-desc' },
|
// [TripStatus.VehicleApproaching]: limitMinutes ? { text: `此处限停${limitMinutes}分钟,请尽快前往上车点`, className: 'calling-car-content-warning' } : null,
|
// [TripStatus.VehicleArrivedPickup]: doorUnlockedInCurrentPage
|
// ? { text: '车门已解锁,请尽快上车', className: 'calling-car-content-desc' }
|
// : { text: isPickupCountdownSoon ? `车辆到达后最多等待${limitMinutes}分钟,超时自动取消` : '此处限停,请在倒计时结束前到达上车点', className: 'calling-car-content-desc' },
|
// [TripStatus.InService]: { text: '行程已开始,请全程系好安全带', className: 'calling-car-content-desc' },
|
// [TripStatus.ArrivedDestination]: { text: '倒计时结束时车辆将自动驶离,请带好物品安全下车', className: 'calling-car-content-desc' },
|
// [TripStatus.TripFinished]: { text: '订单待支付,请核对后完成支付', className: 'calling-car-content-desc' }
|
// }
|
|
// 站点信息(图二):与 cancel-popup 一致,优先取缓存的起终点
|
const cachedStartSite = Taro.getStorageSync('startSite') || {};
|
const cachedEndSite = Taro.getStorageSync('endSite') || {};
|
const startSiteName = cachedStartSite?.name || cachedStartSite?.address || '-';
|
const endSiteName = cachedEndSite?.name || cachedEndSite?.address || '-';
|
|
// 状态栏右侧的距离/时间文案
|
const distanceText = routeDistance ? `${routeDistance.value}${routeDistance.unit === 'm' ? 'M' : 'KM'}` : '';
|
const approachingTimeText = `${normalizedDurationDisplay.value}MIN`;
|
const inServiceTimeText = `${normalizedDurationDisplay.value}MIN`;
|
|
return (
|
<>
|
{/* 呼叫车中:DOM 结构与样式保持不变(图一 + 站点卡片) */}
|
{tripStatus === TripStatus.CallingCar && (
|
<>
|
<View className='calling-car-content'>
|
<View className='calling-car-content-main'>
|
<View className='calling-car-content-title calling-car-content-title--strong'>
|
预计{displayedWaitMinutes ?? '-'}分钟内有车应答
|
</View>
|
<View className='calling-car-content-desc'>
|
正全力为您叫车中...
|
{queueStatus && (
|
<>
|
<Text className='calling-car-content-desc-divider'>|</Text>
|
第{queueStatus.currentPosition}位/共{queueStatus.totalCount}位
|
</>
|
)}
|
</View>
|
</View>
|
<View
|
className='calling-car-cancel-btn'
|
onClick={() => handleOpenCancelPopup?.({ durationDisplay, waitMinutes: displayedWaitMinutes })}
|
>
|
取消行程
|
</View>
|
</View>
|
<View className='calling-car-site-box'>
|
<View className='calling-car-site-box-icon'>
|
<Image className='calling-car-site-check'src='https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/v2/route-state-icon-golden-20260702.png' ></Image>
|
<Image className='dotted-line' src='https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/dotted-line.png' />
|
<Image className='calling-car-site-check' src='https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/v2/route-state-icon-black-20260702.png'></Image>
|
</View>
|
<View className='calling-car-site-box-content'>
|
<View>{startSiteName}</View>
|
<View className='calling-car-site-box-divider'></View>
|
<View>{endSiteName}</View>
|
</View>
|
</View>
|
</>
|
)}
|
|
{/* 车辆即将到达:左右布局状态栏(图一) */}
|
{tripStatus === TripStatus.VehicleApproaching && (
|
<View className='calling-car-status-box'>
|
<Image className='calling-car-status-box-come-icon' mode='widthFix' src='https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/v2/come-icon-20260728.webp'></Image>
|
<View className='calling-car-status-box-left'>{isArriveSoon ? '即将抵达' : '正在赶来'}</View>
|
<View className='calling-car-status-box-right'>
|
{distanceText && <View className='distance'>{distanceText}</View>}
|
<View className='time'>{approachingTimeText}</View>
|
</View>
|
</View>
|
)}
|
|
{/* 车辆到达上车点:直接展示图片 */}
|
{tripStatus === TripStatus.VehicleArrivedPickup && (
|
<View className='calling-car-status-box calling-car-arrived-img'>
|
<View className='calling-car-status-box-left'>车辆已到达上车点,倒计时结束将自动取消订单</View>
|
</View>
|
)}
|
|
{/* 行程中:左右布局状态栏 */}
|
{tripStatus === TripStatus.InService && (
|
<View className='calling-car-status-box'>
|
<Image className='calling-car-status-box-come-icon' mode='widthFix' src='https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/v2/come-icon-20260728.webp'></Image>
|
<View className='calling-car-status-box-left'>正在前往目的地</View>
|
<View className='calling-car-status-box-right'>
|
{distanceText && <View className='distance'>{distanceText}</View>}
|
<View className='time'>{inServiceTimeText}</View>
|
</View>
|
</View>
|
)}
|
</>
|
);
|
}
|