| | |
| | | import CustomerServicePopup from '../../../components/customer-service'; |
| | | import TipPopup from '../../../components/tip-popup'; |
| | | import { formatTripDistance, formatTripDurationFromSeconds } from '../../../../utils/Robotaxi-public-method'; |
| | | import { SELECT_SITE_RANGE_STATUS, type SelectSiteRangeStatus } from '../hooks/use-select-map-site-state'; |
| | | |
| | | type Deps = { |
| | | longitude: number | null; |
| | |
| | | selectionMode: 'point' | 'station'; |
| | | selectedStation: any; |
| | | stationSiteList: any[]; |
| | | outOfServiceRange: boolean; |
| | | rangeStatus: SelectSiteRangeStatus; |
| | | tooltipBgSrc: string; |
| | | pageType: string; |
| | | bounce: boolean; |
| | |
| | | activeStar: string; |
| | | noStar: string; |
| | | confirmSite: () => void; |
| | | confirmButtonText: string; |
| | | confirmButtonDisabled: boolean; |
| | | crossOperatingAreaHintText: string; |
| | | showViewOperatingAreaButton: boolean; |
| | | handleViewOperatingArea: () => void; |
| | | showCustomerService: boolean; |
| | | handleCloseCustomerService: () => void; |
| | | showTipPopup: boolean; |
| | | handleCloseTipPopup: () => void; |
| | | tipType: string; |
| | | toPersonalCenter: () => void; |
| | | toSiteSearch: () => void; |
| | | hideSearchBox?: boolean; |
| | | }; |
| | | |
| | | /** |
| | | * 选点页视图组件:仅负责渲染地图与页面 UI,不包含业务状态编排。 |
| | | */ |
| | | export default function SelectMapSiteView(deps: Deps) { |
| | | const isOutOfOperatingArea = deps.rangeStatus === SELECT_SITE_RANGE_STATUS.outOfOperatingArea; |
| | | const isCrossOperatingArea = deps.rangeStatus === SELECT_SITE_RANGE_STATUS.crossOperatingArea; |
| | | const showRangeWarning = isOutOfOperatingArea || isCrossOperatingArea; |
| | | const shouldShowSelectedSiteEcho = !showRangeWarning && Boolean(deps.selectedSite.name); |
| | | const shouldShowStationSelection = deps.selectionMode === 'station' && !showRangeWarning; |
| | | const garyToolTipBg = 'https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/v2/tooltip-bg-gray-20260714.png'; |
| | | |
| | | return ( |
| | | <View className="home-container"> |
| | | <Map |
| | | id="map" |
| | | id="select-site-map" |
| | | longitude={deps.longitude} |
| | | latitude={deps.latitude} |
| | | scale={deps.mapScale} |
| | |
| | | <View onClick={deps.toBack} className="select-city"> |
| | | <Image className="select-city-icon" src={deps.backIcon} /> |
| | | </View> |
| | | {/* 地图浮层入口 */} |
| | | <View className="map-entry"> |
| | | <Image onClick={deps.toPersonalCenter} className="map-entry-icon" src={deps.personalCenter} /> |
| | | <View className="split-line"></View> |
| | | <Image onClick={deps.openService} className="map-entry-icon" src={deps.contactService} /> |
| | | <View className="split-line"></View> |
| | | <Image onClick={deps.toCoupon} className="map-entry-icon" src={deps.coupon} /> |
| | | </View> |
| | | {/* 搜索框 */} |
| | | {!deps.hideSearchBox && ( |
| | | <View onClick={deps.toSiteSearch} className="search-card"> |
| | | <View className={`search-icon ${deps.pageType == 'end' ? 'end-icon' : ''}`}></View> |
| | | <View className="search-input-box"> |
| | | <View className="search-input-placeholder">{deps.pageType == 'start' ? '请输入上车点' : '请输入目的地'}</View> |
| | | </View> |
| | | </View> |
| | | )} |
| | | {/* 地图浮层入口 - 选点页不展示 */} |
| | | {deps.nearbyLoading && deps.isAndroid && ( |
| | | <Image className="waiting-radar-img" src={deps.waitingRadarSrc} /> |
| | | )} |
| | |
| | | {deps.nearbyLoading && !deps.isAndroid && ( |
| | | <Image className="waiting-radar" src={deps.waitingRadarSrc} /> |
| | | )} |
| | | {((deps.showToolTip && deps.selectedSite.name) || deps.outOfServiceRange) && ( |
| | | {((deps.showToolTip && shouldShowSelectedSiteEcho) || showRangeWarning) && ( |
| | | <View className="toolTip"> |
| | | {(deps.outOfServiceRange || deps.selectedSite.time) && ( |
| | | {(showRangeWarning || deps.selectedSite.time) && ( |
| | | <View className="toolTip-bg"> |
| | | <Image className="toolTip-bg-img" src={deps.tooltipBgSrc} /> |
| | | <Image className="toolTip-bg-img" src={(isOutOfOperatingArea || isCrossOperatingArea) ? garyToolTipBg : deps.tooltipBgSrc } /> |
| | | {!showRangeWarning && ( |
| | | <Image className="toolTip-bg-icon" src="https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/v2/map-time-icon-20260708.png" /> |
| | | )} |
| | | <Text className="toolTip-bg-text"> |
| | | {deps.outOfServiceRange ? '不在运营区' : `限停${deps.selectedSite.time}分钟`} |
| | | {isOutOfOperatingArea ? '不在运营区' : isCrossOperatingArea ? '不在同一运营区' : `限停${deps.selectedSite.time}分钟`} |
| | | </Text> |
| | | </View> |
| | | )} |
| | | <View className="toolTip-txt"> |
| | | <View className="toolTip-txt-content"> |
| | | {deps.outOfServiceRange ? `请拖动至${deps.pageType == 'end' ? '目的地' : '上车点'}` : deps.selectedSite.name} |
| | | {isOutOfOperatingArea |
| | | ? `请拖动至${deps.pageType == 'end' ? '目的地' : '上车点'}` |
| | | : isCrossOperatingArea |
| | | ? '请在同一运营区内选择' |
| | | : deps.selectedSite.name} |
| | | </View> |
| | | <Image className="toolTip-diamond-icon" src="https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/v2/diamond-icon-20260708.png" /> |
| | | </View> |
| | | </View> |
| | | )} |
| | | <Image |
| | | className={`pointer-icon ${deps.bounce ? 'bounce' : ''}`} |
| | | src={deps.pointer} |
| | | /> |
| | | {/* 黑色站点名浮窗(toolTip)显示时隐藏中心大头针 */} |
| | | <Image className={`pointer-icon ${deps.bounce ? 'bounce' : ''} ${(deps.showToolTip && shouldShowSelectedSiteEcho) || showRangeWarning ? 'hidden-pointer' : ''}`} src={deps.pointer} /> |
| | | </View> |
| | | <View className="container"> |
| | | <View className="container-inner"> |
| | |
| | | <View className="origin-box"> |
| | | <Image onClick={deps.toOrigin} className="origin-icon" src={deps.originIcon} /> |
| | | </View> |
| | | <View catchMove onClick={(e) => e.stopPropagation()}> |
| | | <View className="content-box-wrap" catchMove onClick={(e) => e.stopPropagation()}> |
| | | {deps.showViewOperatingAreaButton && ( |
| | | <View onClick={deps.handleViewOperatingArea} className="select-operating-area-entry"> |
| | | 查看运营区域 |
| | | </View> |
| | | )} |
| | | {/* 确认站点 */} |
| | | <View className="content-box"> |
| | | <View className="content-box-item"> |
| | | <View className='content-box-item-title'> |
| | | <View className="content-title">{deps.selectionMode === 'station' ? deps.selectedStation?.name : (deps.pageType === 'start' ? '确认上车站点' : '确认目的地')}</View> |
| | | {deps.pageType === 'start' && deps.walkingDuration !== null && deps.walkingDistance !== null && ( |
| | | <View className="limit-tip"> |
| | | 从当前位置出发步行{formatTripDurationFromSeconds(deps.walkingDuration)}({formatTripDistance(deps.walkingDistance)})上车 |
| | | </View> |
| | | )} |
| | | {(deps.nearbySites.length > 0 && deps.pageType === 'end') && ( |
| | | <View className="limit-tip">点击紫色原点或拖动大头针,可修改{deps.pageType === 'start' ? '上车点' : '目的地'}</View> |
| | | )} |
| | | </View> |
| | | {deps.selectionMode === 'station' && ( |
| | | <Image |
| | | onClick={deps.handleCollect} |
| | | className='collect-icon' |
| | | src={deps.selectedStation?.isCollect ? deps.activeStar : deps.noStar} |
| | | /> |
| | | )} |
| | | </View> |
| | | <View className='site-list-wrap'> |
| | | <ScrollView |
| | | className="site-list" |
| | | scrollY |
| | | enhanced |
| | | showScrollbar={true} |
| | | > |
| | | <View className='site-list-inner'> |
| | | {deps.selectionMode === 'station' ? ( |
| | | deps.stationSiteList.length > 0 ? deps.stationSiteList.map((item) => ( |
| | | <View |
| | | key={item.id || item.pointId || `${item.latitude}_${item.longitude}`} |
| | | className={`site-item ${String(item.id || item.pointId || '') === String(deps.selectedSite?.id || deps.selectedSite?.pointId || '') ? 'site-active' : ''}`} |
| | | onClick={() => deps.changeStationSite(item)} |
| | | > |
| | | <View>{item.name}</View> |
| | | </View> |
| | | )) : <View className="no-service">当前场站暂无可选站点</View> |
| | | ) : deps.selectedSite.name ? ( |
| | | <View className='site-item site-active'> |
| | | <View>{deps.selectedSite.name}</View> |
| | | {deps.selectionMode === 'point' && ( |
| | | <Image onClick={deps.handleCollect} className='collect-icon' src={deps.selectedSite.isCollect === 1 ? deps.activeStar : deps.noStar} /> |
| | | )} |
| | | <Image className="content-box-top-bg" src='https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/v2/top-card-bg-20260722.png' /> |
| | | <View className="content-box-coantainer"> |
| | | <View className="content-box-item"> |
| | | <View className='content-box-item-title'> |
| | | <View className="content-title">{shouldShowStationSelection ? deps.selectedStation?.name : (deps.pageType === 'start' ? '确认上车点' : '确认目的地')}</View> |
| | | {deps.pageType === 'start' && deps.walkingDuration !== null && deps.walkingDistance !== null && ( |
| | | <View className="limit-tip"> |
| | | 从当前位置出发步行{formatTripDurationFromSeconds(deps.walkingDuration)}({formatTripDistance(deps.walkingDistance)})上车 |
| | | </View> |
| | | ) : ( |
| | | <View className="no-service">超出服务范围,请在运营区内选择</View> |
| | | )} |
| | | {(deps.nearbySites.length > 0 && deps.pageType === 'end') && ( |
| | | <View className="limit-tip">点击金色圆点或拖动大头针,可修改目的地</View> |
| | | )} |
| | | </View> |
| | | </ScrollView> |
| | | </View> |
| | | <View onClick={deps.confirmSite} className={`site-confirm ${deps.selectedSite.name ? '' : 'no-confirm'}`}> |
| | | {deps.pageType === 'start' ? '确认上车站点' : '确认目的地站点'} |
| | | {shouldShowStationSelection && ( |
| | | <Image |
| | | onClick={deps.handleCollect} |
| | | className='collect-icon' |
| | | src={deps.selectedStation?.isCollect ? deps.activeStar : deps.noStar} |
| | | /> |
| | | )} |
| | | </View> |
| | | <View className='site-list-wrap'> |
| | | <ScrollView |
| | | className="site-list" |
| | | scrollY |
| | | enhanced |
| | | showScrollbar={true} |
| | | > |
| | | <View className='site-list-inner'> |
| | | {shouldShowStationSelection ? ( |
| | | deps.stationSiteList.length > 0 ? deps.stationSiteList.map((item) => ( |
| | | <View |
| | | key={item.id || item.pointId || `${item.latitude}_${item.longitude}`} |
| | | className={`site-item ${String(item.id || item.pointId || '') === String(deps.selectedSite?.id || deps.selectedSite?.pointId || '') ? 'site-active' : ''}`} |
| | | onClick={() => deps.changeStationSite(item)} |
| | | > |
| | | <View>{item.name}</View> |
| | | </View> |
| | | )) : <View className="no-service">当前场站暂无可选站点</View> |
| | | ) : shouldShowSelectedSiteEcho ? ( |
| | | <View className='site-item site-active'> |
| | | <View>{deps.selectedSite.name}</View> |
| | | {deps.selectionMode === 'point' && ( |
| | | <Image onClick={deps.handleCollect} className='collect-icon' src={deps.selectedSite.isCollect === 1 ? deps.activeStar : deps.noStar} /> |
| | | )} |
| | | </View> |
| | | ) : showRangeWarning ? ( |
| | | <View className="no-service">{isCrossOperatingArea ? deps.crossOperatingAreaHintText : '超出服务范围,请在运营区内选择'}</View> |
| | | ) : <View className="no-service">附近无可选站点</View> |
| | | } |
| | | </View> |
| | | </ScrollView> |
| | | </View> |
| | | <View onClick={deps.confirmButtonDisabled ? undefined : deps.confirmSite} className={`site-confirm ${deps.confirmButtonDisabled ? 'no-confirm' : ''}`}> |
| | | {deps.confirmButtonText} |
| | | </View> |
| | | </View> |
| | | </View> |
| | | </View> |