fix: 修复行程状态映射、优惠券切换和地图边距问题
- 修正行程状态映射逻辑,将状态1正确映射为2
- 修复优惠券切换逻辑,自动切换不满足条件的优惠券并显示提示
- 调整订单详情页地图边距,从40增加到80以改善显示效果
- 修复优惠券页面URL解码问题,避免显示乱码
- 优化行程结束倒计时逻辑,修复状态7的显示问题
- 修正价格显示条件,仅当originalFareStr大于0时显示原价
- 修复Android平台检测和行程状态判断逻辑
| | |
| | | |
| | | const mapActiveStatusToTripStatus = (status: number) => { |
| | | if (status === 0) return 1; |
| | | if (status === 1) return 3; |
| | | if (status === 1) return 2; |
| | | if (status === 3 || status === 2) return 4; |
| | | if (status === 4) return 5; |
| | | if (status === 5) return 6; |
| | |
| | | setMapScale(14); |
| | | const mapCtx = Taro.createMapContext('map'); |
| | | mapCtx.moveToLocation(); |
| | | try { |
| | | const loc = await Taro.getLocation({ type: 'gcj02' }); |
| | | const data = await getAddressByLocation(loc.longitude, loc.latitude); |
| | | const addressComponent = data?.regeocodeData?.addressComponent; |
| | | if (!addressComponent) { |
| | | return; |
| | | } |
| | | const { city, province, adcode } = addressComponent; |
| | | const cityName = (city && typeof city === 'string' && city.length > 0) ? city : province; |
| | | const cityCode = convertAdcodeToCityCode(adcode, cityName, province); |
| | | if (!cityCode) { |
| | | return; |
| | | } |
| | | const cachedCity = Taro.getStorageSync('selectedCity'); |
| | | if (cachedCity?.code === cityCode) { |
| | | return; |
| | | } |
| | | const cityInfo = await getCityInfoWithId(cityCode, cityName); |
| | | if (cityInfo?.code) { |
| | | setSelectedCity(cityInfo); |
| | | Taro.setStorageSync('selectedCity', cityInfo); |
| | | lastSelectedCityCodeRef.current = cityInfo.code; |
| | | } |
| | | } catch (error) { |
| | | } |
| | | } |
| | | |
| | | // 地图区域变化时触发,判断是否吸附到最近的站点停靠点 |
| | |
| | | [2, 3, 4, 5, 6, 7, 8].includes(tripStatus) && |
| | | <View className="order-status"> |
| | | { |
| | | [3].includes(tripStatus) && |
| | | [2].includes(tripStatus) && |
| | | <View className="order-status-left"> |
| | | <View className="order-status-left-item"> |
| | | <Image className="order-status-left-item-icon" src={require('../../../robotaxi/assets/pointer.png')} /> |
| | |
| | | const finishEndTimeRef = useRef<number | null>(null); // 到达目的地时间 |
| | | const lastFareOrderIdRef = useRef<string | null>(null); |
| | | const hasShownAnnouncementsRef = useRef(false); // 是否已展示过公告弹窗 |
| | | const skipEvaluateResetRef = useRef(false); |
| | | const PICKUP_END_TIME_KEY = 'pickupEndTime'; // 上车点限停结束时间缓存键 |
| | | const FINISH_END_TIME_KEY = 'finishEndTime'; // 到达目的地倒计时结束时间缓存键 |
| | | |
| | |
| | | 4: <>车辆还有<View className="time">{durationDisplay.value}</View>{durationDisplay.unit}到达</>, |
| | | 5: <>车辆已到达上车点<View className="time" style={isPickupCountdownSoon ? { color: '#E03434' } : undefined}>{pickupCountdownSeconds !== null ? formatCountdown(pickupCountdownSeconds) : '--:--'}</View></>, |
| | | 6: <>预计<View className="time">{durationDisplay.value}</View>{durationDisplay.unit}抵达目的地</>, |
| | | 7: finishCountdownEnabled |
| | | 7: (finishCountdownEnabled || finishCountdownSeconds !== null) |
| | | ? <>已到达目的地<View className="time">{finishCountdownSeconds !== null ? formatCountdown(finishCountdownSeconds) : '--:--'}</View></> |
| | | : <>已到达目的地</>, |
| | | 8: '行程已结束', |
| | |
| | | pickupEndTimeRef.current = null; |
| | | } |
| | | } else if (tripStatus === 7) { |
| | | if (!finishCountdownEnabled) { |
| | | const cachedEndTime = Taro.getStorageSync(FINISH_END_TIME_KEY); |
| | | const hasValidCached = typeof cachedEndTime === 'number' && cachedEndTime > Date.now(); |
| | | if (!finishCountdownEnabled && !hasValidCached) { |
| | | if (finishCountdownTimerRef.current) { |
| | | clearTimeout(finishCountdownTimerRef.current); |
| | | } |
| | |
| | | Taro.removeStorageSync(FINISH_END_TIME_KEY); |
| | | return; |
| | | } |
| | | const cachedEndTime = Taro.getStorageSync(FINISH_END_TIME_KEY); |
| | | const hasValidCached = typeof cachedEndTime === 'number' && cachedEndTime > Date.now(); |
| | | const initFinishCountdown = (endTimeMs: number | null) => { |
| | | finishEndTimeRef.current = endTimeMs; |
| | | if (typeof endTimeMs === 'number' && endTimeMs > Date.now()) { |
| | |
| | | } |
| | | return () => { |
| | | isActive = false; |
| | | if (tripStatus === 7 && finishCountdownEnabled && typeof finishEndTimeRef.current === 'number' && finishEndTimeRef.current > Date.now()) { |
| | | if (tripStatus === 7 && typeof finishEndTimeRef.current === 'number' && finishEndTimeRef.current > Date.now()) { |
| | | Taro.setStorageSync(FINISH_END_TIME_KEY, finishEndTimeRef.current); |
| | | } |
| | | if (countdownTimerRef.current) { |
| | |
| | | // 评价弹窗确认提交时,更新评价状态 |
| | | useEffect(() => { |
| | | if (typeof evaluateSubmitVersion === 'number' && evaluateSubmitVersion > 0) { |
| | | skipEvaluateResetRef.current = true; |
| | | setIsEvaluated(true); |
| | | setActiveIndex(1); |
| | | } |
| | |
| | | // 评价弹窗关闭时,重置评价索引 |
| | | useEffect(() => { |
| | | if (typeof evaluateCloseVersion === 'number' && evaluateCloseVersion > 0) { |
| | | if (skipEvaluateResetRef.current) { |
| | | skipEvaluateResetRef.current = false; |
| | | return; |
| | | } |
| | | setActiveIndex(0); |
| | | } |
| | | }, [evaluateCloseVersion]); |
| | |
| | | <View>远途费</View> |
| | | <View>{formatMoney(fareBreakdown.longDistance.reduce((sum: number, item: any) => sum + (Number(item?.money) || 0), 0))}元</View> |
| | | </View> |
| | | {fareBreakdown.longDistance.filter((item: any) => item?.money || item?.mileage).map((item: any, index: number) => ( |
| | | {/* {fareBreakdown.longDistance.filter((item: any) => item?.money || item?.mileage).map((item: any, index: number) => ( |
| | | <View key={`long-${index}`} className="particulars-detail-item-content"> |
| | | <View>{getTypeLabel(item?.type)}({formatTripDistance(item?.mileage)})</View> |
| | | <View>{formatMoney(item?.money)}元</View> |
| | | </View> |
| | | ))} |
| | | ))} */} |
| | | </View> |
| | | } |
| | | {Number(fareBreakdown?.redPacketMoney) > 0 && |
| | |
| | | |
| | | font-size: 28px; |
| | | font-weight: normal; |
| | | line-height: 40px; |
| | | line-height: 41px; |
| | | letter-spacing: normal; |
| | | text-decoration: line-through; |
| | | color: rgba(0, 0, 0, 0.4); |
| | |
| | | } |
| | | setIsSubmitting(true); |
| | | endOrder(orderId).then((res: any) => { |
| | | if (res) { |
| | | Taro.showToast({ |
| | | title: '当前选择优惠券不满足,已自动切换为满足条件优惠券', |
| | | icon: 'none', |
| | | duration: 3000 |
| | | }); |
| | | } |
| | | onConfirm?.(); |
| | | }).catch(() => { |
| | | Taro.showToast({ |
| | |
| | | <View>乘车须知</View> |
| | | </View> |
| | | <View className="route-content-bottom-right"> |
| | | {fareEstimate.discountAmount > 0 && <View className="discount-amount">已优惠{fareEstimate.discountAmount}元</View>} |
| | | <View className="original-fare">{fareEstimate.originalFareStr || '-'}元</View> |
| | | { |
| | | fareEstimate.discountAmount > 0 && |
| | | <View className="discount-amount">已优惠{fareEstimate.discountAmount}元</View> |
| | | } |
| | | { |
| | | fareEstimate.originalFareStr > 0 && |
| | | <View className="original-fare">{fareEstimate.originalFareStr || '-'}元</View> |
| | | } |
| | | </View> |
| | | </View> |
| | | </View> |
| | |
| | | const isAndroid = useMemo(() => { |
| | | try { |
| | | const info = Taro.getSystemInfoSync(); |
| | | console.log(info); |
| | | return info?.platform === 'android' || /android/i.test(info?.system || ''); |
| | | } catch (error) { |
| | | return false; |
| | |
| | | routeRequestKeyRef.current = requestKey; |
| | | const selectedCity = await ensureSelectedCityForRoute(originLng, originLat); |
| | | const openCityId = selectedCity ? selectedCity.id : 0; |
| | | const params = { |
| | | const cachedCouponId = Taro.getStorageSync('selectedCouponId'); |
| | | const params: any = { |
| | | destination: { |
| | | latitude: destLat, |
| | | longitude: destLng |
| | |
| | | longitude: originLng |
| | | }, |
| | | }; |
| | | if (cachedCouponId) { |
| | | params.userCouponId = cachedCouponId; |
| | | } |
| | | queryRouteAndFare(params).then((res: any) => { |
| | | setRouteAndFareError(false); |
| | | if (res?.fareEstimate) { |
| | |
| | | }) |
| | | .catch(() => { }); |
| | | } |
| | | if (cachedTripStatusStorage) { |
| | | if (cachedTripStatusStorage && cachedTripStatusStorage != 1) { |
| | | getOrderActive() |
| | | .then((res: any) => { |
| | | if (!res) { |
| | |
| | | const openCityId = selectedCity?.id || 0; |
| | | const waitingTime = Number(fareEstimate?.waitingTime || 0); |
| | | const estimatedTime = formatDateTime(new Date(Date.now() + waitingTime * 60 * 1000)); |
| | | const payload = { |
| | | const cachedCouponId = Taro.getStorageSync('selectedCouponId'); |
| | | const payload: any = { |
| | | endPointId: endSite.id, |
| | | openCityId: openCityId, |
| | | placementAddress: s?.name, |
| | |
| | | xpElectronicFenceAreaId: s?.electronicAreaId || endSite?.electronicAreaId || '', |
| | | estimatedTime: estimatedTime, |
| | | }; |
| | | if (cachedCouponId) { |
| | | payload.userCouponId = cachedCouponId; |
| | | } |
| | | try { |
| | | const res = await saveOrder(payload); |
| | | if (typeof res == 'string') { |
| | |
| | | }, 1500); |
| | | return |
| | | } |
| | | Taro.removeStorageSync('selectedCouponId'); |
| | | Taro.setStorageSync('orderId', res?.orderId || ''); |
| | | } catch (error) { |
| | | setCallSubmitting(false); |
| | |
| | | }; |
| | | // 打开取消弹窗 |
| | | const handleOpenCancelPopupByTripStatus = (status: number, durationDisplay?: any) => { |
| | | if (durationDisplay) { |
| | | if (durationDisplay && status != 5) { |
| | | setCancelType(2); |
| | | setShowCancelPopup(true); |
| | | return |
| | |
| | | import Taro, { useReachBottom } from '@tarojs/taro'; |
| | | import { useState, useEffect } from 'react'; |
| | | import { useState, useEffect, useMemo } from 'react'; |
| | | import { View, Text, Image, RichText } from '@tarojs/components'; |
| | | import './index.less'; |
| | | import icon from '../../assets/Subtract.png' |
| | |
| | | const [hasMore, setHasMore] = useState(true) |
| | | const [currentCoupon, setCurrentCoupon] = useState<CouponDetail | null>(null) |
| | | const pageSize = 10 |
| | | const decodedCouponDesc = useMemo(() => { |
| | | const raw = currentCoupon?.couponDesc; |
| | | if (!raw) return raw; |
| | | if (typeof raw !== 'string') return raw; |
| | | try { |
| | | return decodeURIComponent(raw); |
| | | } catch (e) { |
| | | return raw; |
| | | } |
| | | }, [currentCoupon?.couponDesc]); |
| | | |
| | | const getList = async (page: number, status: string | number, isRefresh = false) => { |
| | | try { |
| | |
| | | } |
| | | } |
| | | |
| | | const toHome = () => { |
| | | const toHome = (couponId?: string) => { |
| | | if (couponId) { |
| | | Taro.setStorageSync('selectedCouponId', couponId); |
| | | } |
| | | Taro.reLaunch({ |
| | | url: '/pages/robotaxi/home/index' |
| | | }) |
| | |
| | | // <View className='receive' onClick={(e) => handleReceive(e, item)}>领取</View> |
| | | // ) : |
| | | item.status === 1 ? ( |
| | | <View onClick={toHome} className='receive' style={{ backgroundColor: '#F58900' }}>去使用</View> |
| | | <View onClick={() => toHome(item.couponId)} className='receive' style={{ backgroundColor: '#F58900' }}>去使用</View> |
| | | ) : item.status === 2 ? ( |
| | | <Image className='status-img' src={require('../../assets/coupon-used.png')} /> |
| | | ) : item.status === 3 ? ( |
| | |
| | | </View> |
| | | <View className='remark-card'> |
| | | <Text className='remark-label'>使用说明</Text> |
| | | <Text className='remark-value'><RichText nodes={currentCoupon.couponDesc} /></Text> |
| | | <Text className='remark-value'><RichText nodes={decodedCouponDesc} /></Text> |
| | | </View> |
| | | |
| | | </View> |
| | |
| | | if (markerPoints.length > 0) { |
| | | mapCtx.includePoints({ |
| | | points: markerPoints, |
| | | padding: [40, 40, 40, 40] |
| | | padding: [80, 80, 80, 80] |
| | | }); |
| | | } |
| | | } |