import Taro from "@tarojs/taro";
|
import { View, Image } from "@tarojs/components";
|
import { useState, useRef, useEffect } from "react";
|
import { unlockVehicle, queryVehicleTrunkOpenStatus } from '../../../../api/begin-route';
|
|
type Props = {
|
tripStatus: number;
|
orderId?: string;
|
orderTrunkStatus?: boolean;
|
handleOpenOverRoutePopup?: () => void;
|
};
|
|
export default function DoorTrunkControl({
|
tripStatus,
|
orderId,
|
orderTrunkStatus,
|
handleOpenOverRoutePopup
|
}: Props) {
|
const [trunkStatus, setTrunkStatus] = useState(orderTrunkStatus); // 后备箱开关状态
|
const [lockStatus, setLockStatus] = useState(false); // 车门解锁状态
|
const trunkPollTimerRef = useRef<any>(null); // 后备箱状态轮询定时器
|
|
// 外部后备箱状态变化时同步本地状态
|
useEffect(() => {
|
setTrunkStatus(orderTrunkStatus);
|
}, [orderTrunkStatus]);
|
|
// 组件卸载时清理轮询定时器
|
useEffect(() => {
|
return () => {
|
if (trunkPollTimerRef.current) {
|
clearTimeout(trunkPollTimerRef.current);
|
}
|
};
|
}, []);
|
|
// 获取解锁请求所需定位参数,失败时回退到缓存上车点
|
const getUnlockLocationPayload = async () => {
|
try {
|
Taro.showLoading({ title: '正在获取位置...', mask: true });
|
const location = await Taro.getLocation({ type: 'gcj02', isHighAccuracy: true });
|
Taro.hideLoading();
|
const longitude = Number(location?.longitude);
|
const latitude = Number(location?.latitude);
|
if (!Number.isNaN(longitude) && !Number.isNaN(latitude)) {
|
return { longitude, latitude };
|
}
|
} catch (_) {
|
Taro.hideLoading();
|
}
|
const startSite = Taro.getStorageSync('startSite') || {};
|
const longitude = Number(startSite?.longitude);
|
const latitude = Number(startSite?.latitude);
|
if (!Number.isNaN(longitude) && !Number.isNaN(latitude)) {
|
return { longitude, latitude };
|
}
|
return {};
|
};
|
|
// 解锁车门/后备箱,后备箱场景会轮询确认结果
|
const handleUnlock = async (doorType: 'door' | 'trunk', onSuccess?: () => void) => {
|
const targetOrderId = orderId || Taro.getStorageSync('orderId');
|
if (!targetOrderId) return;
|
|
const locationPayload = await getUnlockLocationPayload();
|
const isCloseAction = doorType === 'trunk' ? !!trunkStatus : false;
|
const actionLoadingText = doorType === 'trunk'
|
? (isCloseAction ? '正在关闭后备箱' : '正在开启后备箱')
|
: '正在解锁车门';
|
Taro.showLoading({ title: actionLoadingText, mask: true });
|
unlockVehicle({
|
orderId: targetOrderId,
|
doorType,
|
...locationPayload
|
}).then((res: any) => {
|
console.log('解锁结果:', res);
|
|
if (res?.code !== 200 || !res?.data) {
|
Taro.hideLoading();
|
Taro.showToast({ title: res?.msg || '解锁失败,请重试或联系客服', icon: 'none' });
|
return;
|
}
|
|
if (doorType === 'trunk') {
|
let pollCount = 0;
|
const maxPolls = 5;
|
const pollInterval = 2000;
|
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: failToastText,
|
icon: 'none'
|
});
|
}
|
};
|
|
const doPoll = () => {
|
queryVehicleTrunkOpenStatus({ orderId: targetOrderId }).then((pollRes: any) => {
|
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 = Number(rawValue);
|
if (Number.isNaN(value)) {
|
handlePollFail('invalid_value', rawValue);
|
return;
|
}
|
if (value === expectedTrunkState) {
|
stopPolling();
|
const isOpen = !isCloseAction;
|
setTrunkStatus(isOpen);
|
Taro.hideLoading();
|
Taro.showToast({
|
title: successToastText,
|
icon: 'none'
|
});
|
onSuccess?.();
|
} else {
|
handlePollFail('state_mismatch', value);
|
}
|
}).catch((err) => {
|
handlePollFail('api_error', err);
|
});
|
};
|
trunkPollTimerRef.current = setTimeout(doPoll, pollInterval);
|
}
|
|
if (doorType === 'door') {
|
Taro.hideLoading();
|
Taro.showToast({ title: '右侧车门已解锁', icon: 'none' });
|
}
|
}).catch(() => {
|
Taro.hideLoading();
|
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', () => 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-arrive-item" onClick={() => handleUnlock('door', () => setLockStatus(true))}>
|
<Image className="car-card-arrive-item-img" src={require('../../../../assets/lock-close.png')} />
|
<View className="car-card-arrive-item-text">解锁车门</View>
|
</View>
|
</View>
|
);
|
}
|
|
if (tripStatus === 7) {
|
return (
|
<View className="car-card-reach">
|
<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', () => 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>
|
<View className="car-card-reach-btn-item" onClick={handleOpenOverRoutePopup}>
|
<Image className="car-card-reach-btn-item-img" src={require('../../../../assets/over-gps-icon.png')} />
|
<View className="car-card-reach-btn-item-text">结束行程</View>
|
</View>
|
</View>
|
</View>
|
);
|
}
|
|
return null;
|
}
|