| src/robotaxi/pages/begin-route/components/css-folder/passenger-notice.less | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/robotaxi/pages/begin-route/components/passenger-notice.tsx | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/robotaxi/pages/begin-route/components/release-route.tsx | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/robotaxi/pages/begin-route/index.tsx | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/robotaxi/pages/order/detail/index.tsx | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/robotaxi/pages/pricing-rules/index.tsx | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/robotaxi/pages/select-map-site/components/tip-popup.tsx | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/robotaxi/pages/select-map-site/index.tsx | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/utils/Robotaxi-public-method.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/robotaxi/pages/begin-route/components/css-folder/passenger-notice.less
@@ -39,8 +39,8 @@ line-height: 48px; letter-spacing: normal; color: rgba(0, 0, 0, 0.9); max-height: 342px; overflow: auto; height: 342px; overflow: hidden; } &-checkbox { @@ -70,4 +70,4 @@ color: #FFFFFF; } } } } src/robotaxi/pages/begin-route/components/passenger-notice.tsx
@@ -1,5 +1,5 @@ import Taro from '@tarojs/taro'; import { View, Text, Image, RichText } from '@tarojs/components'; import { View, Text, Image, RichText, ScrollView } from '@tarojs/components'; import { useEffect, useState } from 'react'; import './css-folder/passenger-notice.less' import { getPrivacyContent } from '../../../api/home'; @@ -50,13 +50,13 @@ if (!visible) return null; return ( <View className='passenger-popup' catchMove> <View className='passenger-mask'></View> <View className='passenger-popup'> <View className='passenger-mask' catchMove></View> <View className='passenger-content' animation={animationData}> <View className='passenger-content-title'>乘车需知</View> <View className='passenger-content-desc'> <ScrollView className='passenger-content-desc' scrollY enhanced lowerThreshold={30} upperThreshold={30} showScrollbar={false}> <RichText nodes={noticeContent} /> </View> </ScrollView> <View onClick={() => setChecked(!checked)} className='passenger-content-checkbox'> { checked ? src/robotaxi/pages/begin-route/components/release-route.tsx
@@ -18,7 +18,7 @@ const toSeleteSitePage = (type: string) => { Taro.navigateTo({ url: '/robotaxi/pages/site-search/index?pageType=' + type url: '/robotaxi/pages/select-map-site/index?pageType=' + type, }) } const toPriceDescription = () => { src/robotaxi/pages/begin-route/index.tsx
@@ -19,7 +19,7 @@ import suggest from '../../../robotaxi/assets/suggest.png' import originIcon from '../../../robotaxi/assets/origin-icon.png' import wsManager from '../../../utils/websocket'; import { getWalkingRoute, formatDurationToClock, formatDateTime, clearOrderTripStorage } from '../../../utils/Robotaxi-public-method'; import { getWalkingRoute, formatDurationToClock, formatDateTime, clearOrderTripStorage, preloadImageToTemp } from '../../../utils/Robotaxi-public-method'; import { saveOrder, queryRouteAndFare, @@ -35,6 +35,7 @@ export default function SelectMapSite() { const WAITING_TIMER_START_KEY = 'waitingTimerStartAt'; const WAITING_TIMER_ELAPSED_KEY = 'waitingTimerElapsed'; const REQUOTE_EXPIRE_SECONDS = 10 * 60; // 10分钟 const [showCustomerService, setShowCustomerService] = useState(false); // 客服弹窗是否显示 const [longitude, setLongitude] = useState<number | null>(null); // 经度 @@ -45,6 +46,7 @@ const [endSite, setEndSite] = useState<any>({}); // 下车点 const [tripStatus, setTripStatus] = useState<number>(Number(Taro.getStorageSync('tripStatus')) || 1); // 行程状态 1:发布行程 2:发布中 3:呼叫车中 4:车辆即将到达 5:车辆到达上车点 6:车辆行驶中 7:到达目的地 8:行程已结束 9:支付成功 const [elapsedSeconds, setElapsedSeconds] = useState(0); // 等待计时秒数 const requoteTriggeredRef = useRef(false); const [showCancelPopup, setShowCancelPopup] = useState(false); // 取消弹窗是否显示 const [showAnnouncementsPopup, setShowAnnouncementsPopup] = useState(false); // 安全注意事项动画弹窗是否显示 const [showOverRoutePopup, setShowOverRoutePopup] = useState(false); // 结束行程弹窗是否显示 @@ -62,8 +64,10 @@ const [routeDuration, setRouteDuration] = useState<number | null>(null); // 路线时间 const [vehicleInfo, setVehicleInfo] = useState<any>({}); // 车辆信息 const [orderId, setOrderId] = useState<string>(''); // 订单ID const customCalloutIconUrl = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/f9e285fc-4c09-404d-90f8-4bac178565d0.png'; const waitingCalloutBgUrl = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/f55ce277-68de-4615-9c7c-807f588afaac.png'; const waitingRadarUrl = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/63ff36fc-e84c-4078-a53b-467870645105.webp'; const [customCalloutIconSrc, setCustomCalloutIconSrc] = useState(customCalloutIconUrl); const [waitingCalloutBgSrc, setWaitingCalloutBgSrc] = useState(waitingCalloutBgUrl); const [waitingRadarSrc, setWaitingRadarSrc] = useState(waitingRadarUrl); const [waitingRadarStyle, setWaitingRadarStyle] = useState<any>({}); @@ -113,34 +117,28 @@ // 加载等待弹窗图片 useEffect(() => { if (![2, 3].includes(tripStatus)) return; if (Taro.getEnv?.() !== Taro.ENV_TYPE.WEAPP) { return; } let cancelled = false; const loadImage = async (url: string, setter: (value: string) => void) => { try { const res = await Taro.downloadFile({ url }); if (cancelled) { return; } if (res?.statusCode === 200 && res.tempFilePath) { setter(res.tempFilePath); return; } const info = await Taro.getImageInfo({ src: url }); if (!cancelled && info?.path) { setter(info.path); } } catch (error) { } }; loadImage(waitingCalloutBgUrl, setWaitingCalloutBgSrc); loadImage(waitingRadarUrl, setWaitingRadarSrc); const load = async (url: string, setter: (value: string) => void) => { const local = await preloadImageToTemp(url); if (!cancelled) setter(local); } load(waitingCalloutBgUrl, setWaitingCalloutBgSrc); load(waitingRadarUrl, setWaitingRadarSrc); return () => { cancelled = true; }; }, [tripStatus]); // 页面初始化预下载自定义气泡图标 useEffect(() => { let cancelled = false; const run = async () => { const local = await preloadImageToTemp(customCalloutIconUrl); if (!cancelled) setCustomCalloutIconSrc(local); }; run(); return () => { cancelled = true; }; }, []); // 更新等待雷达位置 const updateWaitingRadarPosition = () => { if (!shouldShowWaitingRadar) { @@ -501,6 +499,30 @@ Taro.setStorageSync('tripStatus', tripStatus); tripStatusRef.current = tripStatus; let timer: any = null; let requoteTimer: any = null; // tripStatus=1:开启发布行程停留计时,用于10分钟后提示需重新估价 if (tripStatus == 1) { requoteTriggeredRef.current = false; const startAt = Date.now(); const updateRequoteElapsed = () => { const nextElapsed = Math.max(0, Math.floor((Date.now() - startAt) / 1000)); if (nextElapsed >= REQUOTE_EXPIRE_SECONDS) { if (!requoteTriggeredRef.current) { requoteTriggeredRef.current = true; const s = Taro.getStorageSync('startSite') || {}; const e = Taro.getStorageSync('endSite') || {}; if (s?.latitude && s?.longitude && e?.latitude && e?.longitude) { requestRouteAndFare(s.latitude, s.longitude, e.latitude, e.longitude, true); } } } }; updateRequoteElapsed(); requoteTimer = setInterval(updateRequoteElapsed, 1000); } else { requoteTriggeredRef.current = false; } // tripStatus=2/3:等待计时 if (tripStatus == 2 || tripStatus == 3) { const s = Taro.getStorageSync('startSite'); if (s && s.latitude && s.longitude) { @@ -588,6 +610,7 @@ } return () => { if (timer) clearInterval(timer); if (requoteTimer) clearInterval(requoteTimer); }; }, [tripStatus]); @@ -677,6 +700,7 @@ points: routePoints, color: '#7B91FF', width: 10, dottedLine: false, arrowLine: true, }); } @@ -686,7 +710,7 @@ color: '#7B91FF', width: 6, dottedLine: true, arrowLine: true, arrowLine: false, }); } setPolyline(lines); @@ -1092,7 +1116,7 @@ <CoverView className="custom-callout-content"> {item.name} { tripStatus == 1 && <CoverImage className="custom-callout-icon" src='https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/f9e285fc-4c09-404d-90f8-4bac178565d0.png' /> tripStatus == 1 && <CoverImage className="custom-callout-icon" src={customCalloutIconSrc} /> } </CoverView> } src/robotaxi/pages/order/detail/index.tsx
@@ -155,10 +155,10 @@ <View className='trip-info'> <View className='trip-top'> <View className='price-card'> <Text className='price'>{orderData.payMoney || 0}</Text> <Text className='price'>{orderData.payMoney || '-'}元</Text> <Text className='unit'>元</Text> {orderData.orderMoney > orderData.payMoney && ( <Text className='old-price'>{orderData.orderMoney || 0}元</Text> <Text className='old-price'>{orderData.orderMoney || '-'}元</Text> )} </View> <View onClick={todescription} className='price-remark'> @@ -181,7 +181,7 @@ </View> {/* 行程信息 */} <View className='trip-line'> <View className='line-name'>全程{orderData.totalMileage || 0}公里|{orderData.orderTime || 0}分钟</View> <View className='line-name'>全程{orderData.totalMileage || '-'}公里|{orderData.orderTime || '-'}分钟</View> <View className='line-address'> <View className='line-icon first-icon'></View> <Text className='line-text'>{orderData.startAddress}</Text> src/robotaxi/pages/pricing-rules/index.tsx
@@ -5,10 +5,8 @@ import './index.less'; export default function PricingRulesPage() { const [pricingData, setPricingData] = useState<any>(null); const [loading, setLoading] = useState(true); const [pricingHtml, setPricingHtml] = useState<string>(''); const [pricingNodes, setPricingNodes] = useState<any[]>([]); useEffect(() => { const cachedCity = Taro.getStorageSync('selectedCity'); @@ -20,55 +18,11 @@ } }, []); const extractHtmlFromData = (data: any): string => { if (!data) return ''; if (typeof data === 'string') return data; const candidates = ['html', 'content', 'richText', 'rich_text', 'data']; for (const key of candidates) { const val = (data as any)?.[key]; if (typeof val === 'string') return val; } return ''; }; const parseHtmlToNodes = async (html: string) => { if (!html) { setPricingNodes([]); return; } try { const { parse } = await import('mini-html-parser2'); parse(html, (_err: any, nodes: any[]) => { const enhanceNodes = (ns: any[]): any[] => ns.map((n: any) => { const node = { ...n }; if (node.name === 'img') { node.attrs = { ...(node.attrs || {}), style: `${node.attrs?.style || ''};max-width:100%;height:auto;display:block;` }; } if (Array.isArray(node.children) && node.children.length > 0) { node.children = enhanceNodes(node.children); } return node; }); setPricingNodes(enhanceNodes(nodes || [])); }); } catch { setPricingNodes([]); } }; const fetchPricingRules = async (cityId: string) => { try { setLoading(true); const res: any = await getPricingRules(cityId); const data = res?.data ?? res; setPricingData(data); const html = extractHtmlFromData(data); setPricingHtml(html); await parseHtmlToNodes(html); setPricingHtml(res); } catch (error) { console.error('获取定价规则失败', error); Taro.showToast({ @@ -90,7 +44,7 @@ ); } if ((!pricingHtml || pricingHtml.trim().length === 0) && (!pricingNodes || pricingNodes.length === 0)) { if (!pricingHtml || pricingHtml.trim().length === 0) { return ( <View className='pricing-rules-page'> <View className='no-data'> @@ -103,7 +57,7 @@ return ( <View className='pricing-rules-page'> <View className='rich-text-wrapper'> <RichText nodes={pricingNodes && pricingNodes.length > 0 ? pricingNodes : pricingHtml} /> <RichText nodes={pricingHtml} /> </View> </View> ); src/robotaxi/pages/select-map-site/components/tip-popup.tsx
@@ -36,12 +36,18 @@ } }, [show]); const toHome = () => { Taro.reLaunch({ url: '/pages/robotaxi/home/index' }) } if (!visible) return null; return ( <View className='tip-popup' catchMove> <View className='tip-mask'></View> <View className='tip-content' animation={animationData}> <Image onClick={onClose} className='close-icon' src={require('../../../assets/close-icon.png')} /> <Image onClick={toHome} className='close-icon' src={require('../../../assets/close-icon.png')} /> <View className='tip-title'>{tipType === '1' ? '上车点与目的地距离较近,建议步行前往' : '当前位置距上车点较远,暂不支持叫车,请重新选择上车点'}</View> <View onClick={onClose} className='reselect-btn'>重新选点</View> </View> src/robotaxi/pages/select-map-site/index.tsx
@@ -270,9 +270,10 @@ }) return } // 校验当前位置与选择的上车点距离 if (longitude && latitude) { const distance = getDistance(latitude, longitude, selectedSite.latitude, selectedSite.longitude); if (userLatitude && userLongitude) { const distance = getDistance(userLatitude, userLongitude, selectedSite.latitude, selectedSite.longitude); if (distance > distanceConfig.maxDistance) { setTipType('2'); setShowTipPopup(true); @@ -313,8 +314,8 @@ // 关闭提示弹窗 const handleCloseTipPopup = () => { setTipType(''); setShowTipPopup(false); setTipType(''); } // 切换子站点 @@ -352,9 +353,7 @@ color: '#6D7FD9', width: 6, dottedLine: true, arrowLine: true, arrowIconPath: lineRight, borderColor: '#FFFFFF', arrowLine: false, }]; setPolyline(line); }).catch(() => { src/utils/Robotaxi-public-method.ts
@@ -198,6 +198,25 @@ } } // 预下载图片,返回本地临时路径(WeApp),失败或非WeApp环境返回原始URL export const preloadImageToTemp = async (url: string): Promise<string> => { try { if (typeof Taro.getEnv !== 'function' || Taro.getEnv() !== Taro.ENV_TYPE.WEAPP) { return url; } const res = await Taro.downloadFile({ url }); if (res?.statusCode === 200 && res.tempFilePath) { return res.tempFilePath; } const info = await Taro.getImageInfo({ src: url }); if (info?.path) { return info.path; } } catch (e) { } return url; } // 获取地图数据(围栏检查+附近站点) export const fetchMapData = async (lat: number, lng: number) => { try {