feat(robotaxi): 优化多页面样式与交互功能
| | |
| | | |
| | | .activity-item { |
| | | margin-bottom: 24px; |
| | | border: 2px solid #fff; |
| | | border-radius: 24px; |
| | | height: 190px; |
| | | |
| | |
| | | const canAdjustTemperature = canToggleSwitch && acStatusLoaded && acSwitchOn && typeof tempStatus === 'number'; |
| | | // 温度展示文案:到达最高温显示 HI,到达最低温显示 LO,其余显示具体温度值 |
| | | const tempDisplayText = typeof tempStatus === 'number' |
| | | ? (tempStatus >= TEMP_MAX ? 'HI' : (tempStatus <= TEMP_MIN ? 'LO' : `${tempStatus.toFixed(1)}°C`)) |
| | | ? (tempStatus >= TEMP_MAX ? 'HI' : (tempStatus <= TEMP_MIN ? 'LO' : `${tempStatus.toFixed(1)}℃`)) |
| | | : '--'; |
| | | const isAtMinTemperature = typeof tempStatus === 'number' && tempStatus <= TEMP_MIN; |
| | | const isAtMaxTemperature = typeof tempStatus === 'number' && tempStatus >= TEMP_MAX; |
| | |
| | | <View> |
| | | <View className="car-card-detail-num">{vehicleInfo?.plateNumber}</View> |
| | | <View className="car-card-detail-color"> |
| | | {vehicleInfo?.vehicleColor} |
| | | {/* <View className="car-card-detail-color-line"></View> |
| | | 车身编码: {vehicleInfo?.vehicleCode} */} |
| | | <View className="car-card-detail-color-text">小鹏GX</View> |
| | | <View className="car-card-detail-color-line"></View> |
| | | <View className="car-card-detail-color-text">{vehicleInfo?.vehicleColor}</View> |
| | | {/* 车身编码: {vehicleInfo?.vehicleCode} */} |
| | | </View> |
| | | </View> |
| | | { |
| | |
| | | |
| | | .calling-car { |
| | | position: relative; |
| | | padding: 38px 42px 68px 34px; |
| | | padding: 40px 42px 68px 34px; |
| | | background: #f2f3f7; |
| | | border-top: 2px solid #fff; |
| | | border-radius: 40px 40px 0 0; |
| | |
| | | z-index: 1; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-bottom: 40px; |
| | | |
| | | &-title { |
| | | font-size: 32px; |
| | |
| | | margin-top: 4px; |
| | | display: flex; |
| | | align-items: center; |
| | | font-size: 24px; |
| | | letter-spacing: normal; |
| | | color: rgba(0, 0, 0, 0.6); |
| | | |
| | | &-text { |
| | | font-size: 24px; |
| | | line-height: 44px; |
| | | color: rgba(0, 0, 0, 0.6); |
| | | letter-spacing: normal; |
| | | } |
| | | |
| | | &-line { |
| | | width: 1.4px; |
| | |
| | | flex: 1; |
| | | border-radius: 16px; |
| | | background: #F5F6FA; |
| | | padding: 24px 0; |
| | | padding: 34px 0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | |
| | | &-btn { |
| | | flex-shrink: 0; |
| | | padding: 34px 24px; |
| | | padding: 24px; |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 20px; |
| | | gap: 16px; |
| | | |
| | | &-temp { |
| | | font-size: 52px; |
| | |
| | | } |
| | | |
| | | &-desc { |
| | | /* */ |
| | | font-size: 24px; |
| | | font-weight: normal; |
| | | line-height: 24px; |
| | |
| | | &-text { |
| | | font-size: 24px; |
| | | font-weight: normal; |
| | | line-height: 35px; |
| | | line-height: 40px; |
| | | letter-spacing: normal; |
| | | color: rgba(0, 0, 0, 0.9); |
| | | } |
| | |
| | | |
| | | &-item { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | box-sizing: border-box; |
| | | flex: 1; |
| | | |
| | | &-disabled { |
| | | opacity: 0.4; |
| | | } |
| | |
| | | margin-top: 28px; |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 16px; |
| | | gap: 30px; |
| | | height: 156px; |
| | | text-align: center; |
| | |
| | | .bluetooth-operate-card { |
| | | position: relative; |
| | | z-index: 1; |
| | | margin-top: 40px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | |
| | | height: 17.5px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | &-content { |
| | | margin-top: 24px; |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 24px; |
| | | display: grid; |
| | | grid-template-columns: 1fr 1fr; |
| | | gap: 20px 34px; |
| | | |
| | | &-item { |
| | | padding: 0 40px; |
| | | height: 60px; |
| | | padding: 0 16px; |
| | | height: 64px; |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | |
| | | box-sizing: border-box; |
| | | border: 2px solid rgba(0, 0, 0, 0.2); |
| | | font-size: 28px; |
| | | line-height: 44px; |
| | | letter-spacing: normal; |
| | | color: rgba(0, 0, 0, 0.6); |
| | | min-width: 0; |
| | | |
| | | &-text { |
| | | display: block; |
| | | max-width: 100%; |
| | | overflow: hidden; |
| | | white-space: nowrap; |
| | | text-overflow: ellipsis; |
| | | } |
| | | } |
| | | |
| | | .active-tag { |
| | |
| | | background: linear-gradient(97deg, #8475FF 0%, #7DD6FF 103%); |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | left: 0; |
| | | right: 0; |
| | | background: #ffffff; |
| | | border-radius: 16px 16px 0 0; |
| | | padding: 48px 45px 88px 45px; |
| | | border-radius: 40px 40px 0 0; |
| | | padding: 48px 18px 68px 48px; |
| | | height: 75vh; |
| | | overflow: hidden; |
| | | .passenger-content-bg { |
| | |
| | | top: 0; |
| | | width: 6px; |
| | | height: 100%; |
| | | background-color: rgba(0, 0, 0, 0.05); |
| | | background-color: rgba(0, 0, 0, 0.03); |
| | | border-radius: 4px; |
| | | z-index: 10; |
| | | } |
| | |
| | | right: 0; |
| | | top: 0; |
| | | width: 6px; |
| | | background-color: rgba(0, 0, 0, 0.25); |
| | | background-color: rgba(0, 0, 0, 0.05); |
| | | border-radius: 4px; |
| | | z-index: 11; |
| | | } |
| | |
| | | margin-top: 32px; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 4px; |
| | | gap: 8px; |
| | | font-size: 24px; |
| | | letter-spacing: normal; |
| | | color: rgba(0, 0, 0, 0.6); |
| | |
| | | |
| | | &-btn { |
| | | margin-top: 30px; |
| | | margin-right: 32px; |
| | | border-radius: 16px; |
| | | background: linear-gradient(96deg, #8475FF -1%, #7DD6FF 103%); |
| | | line-height: 96px; |
| | |
| | | border-radius: 6px; |
| | | background: rgba(245, 137, 0, 0.06); |
| | | box-sizing: border-box; |
| | | border: 1px solid rgba(245, 137, 0, 0.2); |
| | | border: 2px solid #F58900; |
| | | line-height: 30px; |
| | | text-align: center; |
| | | padding: 0px 6px; |
| | |
| | | line-height: 40px; |
| | | letter-spacing: normal; |
| | | color: rgba(0, 0, 0, 0.9); |
| | | margin-bottom: 2px; |
| | | margin-bottom: 10px; |
| | | font-weight: 500; |
| | | } |
| | | } |
| | |
| | | orderId?: string; |
| | | orderRating?: number; |
| | | submitMode?: 'comment' | 'complaint'; |
| | | /** |
| | | * 是否隐藏问题类型选择 |
| | | */ |
| | | hideFeedbackType?: boolean; |
| | | } |
| | | |
| | | export default function EvaluatePopup({ show = false, onClose, onConfirm, orderId, orderRating, submitMode = 'comment' }: Props) { |
| | | export default function EvaluatePopup({ |
| | | show = false, |
| | | onClose, |
| | | onConfirm, |
| | | orderId, |
| | | orderRating, |
| | | submitMode = 'comment', |
| | | hideFeedbackType = false |
| | | }: Props) { |
| | | const activeBad = 'https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/active-bad.png'; |
| | | const activeNormal = 'https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/active-normal.png'; |
| | | const activeGood = 'https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/active-good.png'; |
| | |
| | | 1: 3 |
| | | }; |
| | | const evaluateDimension = evaluateDimensionMap[currentOrderRating] || 3; // 接口维度:1 满意,2 一般,3 不满意 |
| | | const shouldRequireFeedbackType = !hideFeedbackType; |
| | | const canSubmit = shouldRequireFeedbackType ? !!selectedTypeId && !!feedbackContent.trim() : !!feedbackContent.trim(); |
| | | |
| | | // 控制弹窗开合动画 |
| | | useEffect(() => { |
| | |
| | | if (isSubmittingRef.current) { |
| | | return; |
| | | } |
| | | if (!selectedTypeId) { |
| | | if (shouldRequireFeedbackType && !selectedTypeId) { |
| | | Taro.showToast({ |
| | | title: '请选择问题类型', |
| | | icon: 'none' |
| | |
| | | .filter(p => p.status === 'success' && p.server && p.server.id && p.server.url) |
| | | .map(p => ({ id: p.server!.id, name: p.server!.name, url: p.server!.url })) |
| | | ); |
| | | submitter({ |
| | | const payload: any = { |
| | | orderRating: orderRating ?? 1, |
| | | feedbackTypeId: selectedTypeId, |
| | | feedbackContent, |
| | | feedbackPictures: picturePayload, |
| | | orderId: targetOrderId |
| | | }).then((res: any) => { |
| | | }; |
| | | if (!hideFeedbackType && selectedTypeId) { |
| | | payload.feedbackTypeId = selectedTypeId; |
| | | } |
| | | submitter(payload).then((res: any) => { |
| | | const isFailure = res?.success === false || (typeof res?.code === 'number' && res.code !== 0); |
| | | if (isFailure) { |
| | | Taro.showToast({ |
| | |
| | | <View>{popupDisplayConfig.title}</View> |
| | | </View> |
| | | <View className='content-box'> |
| | | <View className='evaluate-problem-type'> |
| | | <View className='evaluate-problem-type-title'>反馈的问题类型:</View> |
| | | <View className='evaluate-problem-type-content'> |
| | | {typeOptions.map((item) => ( |
| | | <View key={item?.id} className={`evaluate-problem-type-content-item ${selectedTypeId === item?.id && 'active-tag'}`} onClick={() => setSelectedTypeId(item?.id)}>{item?.tagContent}</View> |
| | | ))} |
| | | {!hideFeedbackType && ( |
| | | <View className='evaluate-problem-type'> |
| | | <View className='evaluate-problem-type-title'>反馈的问题类型:</View> |
| | | <View className='evaluate-problem-type-content'> |
| | | {typeOptions.map((item) => ( |
| | | <View key={item?.id} className={`evaluate-problem-type-content-item ${selectedTypeId === item?.id && 'active-tag'}`} onClick={() => setSelectedTypeId(item?.id)}> |
| | | <Text className='evaluate-problem-type-content-item-text'>{item?.tagContent}</Text> |
| | | </View> |
| | | ))} |
| | | </View> |
| | | </View> |
| | | </View> |
| | | )} |
| | | <View className='evaluate-problem-desc-box'> |
| | | <Textarea |
| | | className='evaluate-problem-desc' |
| | |
| | | </View> |
| | | </View> |
| | | <View className='evaluate-content-confirm'> |
| | | <View className={`evaluate-content-confirm-btn ${(selectedTypeId && feedbackContent) && 'ok-btn'}`} onClick={submit}>提交反馈</View> |
| | | <View className={`evaluate-content-confirm-btn ${canSubmit && 'ok-btn'}`} onClick={submit}>提交反馈</View> |
| | | </View> |
| | | </View> |
| | | </View> |
| | |
| | | {routeDistance?.unit === "m" ? "米" : "公里"} |
| | | </View> |
| | | <View |
| | | style={{ marginLeft: "2.5px", marginBottom: 0 }} |
| | | style={{ marginLeft: "2px", marginBottom: 0 }} |
| | | className="car-time-num" |
| | | > |
| | | {durationDisplay.value} |
| | |
| | | > |
| | | {item.isRouteSummaryBubble ? ( |
| | | routeSummaryText ? ( |
| | | // 路由摘要气泡 |
| | | <CoverView className="route-summary-callout"> |
| | | <CoverImage |
| | | className="route-summary-callout-bg" |
| | |
| | | }} |
| | | > |
| | | {item.name} |
| | | {!deps.isAndroid && ( |
| | | <CoverView style={{ color: "transparent" }}>占</CoverView> |
| | | {!deps.isAndroid && item.name.length > 16 && ( |
| | | <CoverView style={{ color: "transparent",width: "3px" }}>占</CoverView> |
| | | )} |
| | | </CoverView> |
| | | {deps.isAndroid && ( |
| | |
| | | {deps.routeDistance?.unit === "m" ? "米" : "公里"} |
| | | </CoverView> |
| | | <CoverView |
| | | style={{ marginLeft: "2.5px" }} |
| | | style={{ marginLeft: "2px" }} |
| | | className="car-time-num" |
| | | > |
| | | {vehicleMetricDurationDisplay.value} |
| | |
| | | /* 相对于父级(底部卡片容器)顶部 */ |
| | | margin-bottom: 24px; |
| | | /* 距离底部卡片24px */ |
| | | right: 24px; |
| | | right: 32px; |
| | | z-index: 1; |
| | | display: flex; |
| | | flex-direction: column; |
| | |
| | | } |
| | | |
| | | .car-time-num { |
| | | font-size: 36px; |
| | | font-size: 28px; |
| | | letter-spacing: normal; |
| | | color: #6D7FD9; |
| | | margin-bottom: -4px; |
| | | margin-right: 2px; |
| | | } |
| | | |
| | | .custom-callout-icon { |
| | |
| | | width: 1, |
| | | height: 1, |
| | | alpha: 0, |
| | | zIndex: 3, |
| | | zIndex: 0, |
| | | isRouteSummaryBubble: true, |
| | | customCallout: { anchorY: 22, anchorX: 42, display: 'ALWAYS' } |
| | | }; |
| | |
| | | orderId={orderId} |
| | | orderRating={1} |
| | | submitMode="complaint" |
| | | hideFeedbackType |
| | | onClose={() => setShowEvaluatePopup(false)} |
| | | onConfirm={() => { |
| | | setShowEvaluatePopup(false); |
| | |
| | | width: 8px; |
| | | height: 8px; |
| | | z-index: 0; |
| | | background: #65C3FC; |
| | | background: #8CB654; |
| | | border-radius: 50%; |
| | | margin-right: 16px; |
| | | flex-shrink: 0; |
| | |
| | | } |
| | | |
| | | .first-icon { |
| | | background: #768AFF; |
| | | background: #6D7FD9; |
| | | } |
| | | |
| | | } |
| | |
| | | <CoverView className={`custom-callout-content ${deps.isAndroid && 'txt-center '}`} style={{ zIndex: 1 }}> |
| | | <CoverView style={{ lineHeight: '22px', whiteSpace: 'nowrap', display: 'flex' }}> |
| | | {item.name} |
| | | {!deps.isAndroid && <CoverView style={{ color: 'transparent' }}>占</CoverView>} |
| | | {!deps.isAndroid && item.name.length > 16 && <CoverView style={{ color: "transparent",width: "3px" }}>占</CoverView>} |
| | | </CoverView> |
| | | {deps.isAndroid && <CoverView style={{ width: '2px' }}></CoverView>} |
| | | {deps.tripStatus === TripStatus.PublishRoute && ( |
| | |
| | | completeConfirmRideSelectionSession, |
| | | writeConfirmRideSiteSourceType |
| | | } from '../../constants/confirm-ride-report'; |
| | | import { hasActiveTripOrderInStorage } from '../../utils/order'; |
| | | import { withRobotaxiWhitelist } from '../../../utils/whitelist'; |
| | | |
| | | function SiteSearchPage() { |
| | |
| | | item: any, |
| | | sourceType = UNKNOWN_CONFIRM_RIDE_SOURCE_TYPE |
| | | ) => { |
| | | // 检查是否有行程订单 |
| | | const modifySession = Taro.getStorageSync(MODIFY_DESTINATION_SESSION_KEY); |
| | | if (!modifySession?.active && hasActiveTripOrderInStorage()) { |
| | | Taro.reLaunch({ |
| | | url: '/robotaxi/pages/begin-route/index?skipPageFlag=1', |
| | | }); |
| | | return; |
| | | } |
| | | // 检查起终点是否在同一运营区域 |
| | | const resolvedDistanceConfig = await ensureDistanceConfigReady(); |
| | | const startSiteCache = Taro.getStorageSync('startSite'); |
| | | if (startSiteCache?.electronicAreaId && item?.electronicAreaId && startSiteCache.electronicAreaId !== item.electronicAreaId) { |
| | |
| | | return; |
| | | } |
| | | } catch { } |
| | | const modifySession = Taro.getStorageSync(MODIFY_DESTINATION_SESSION_KEY); |
| | | // 检查是否与上一个选择的终点相同 |
| | | if (modifySession?.active && isSameModifyDestinationSite(modifySession?.previousEndSite, item)) { |
| | | Taro.setStorageSync(MODIFY_DESTINATION_PENDING_SAME_SITE_TOAST_KEY, 1); |
| | | } |