| | |
| | | const isSubmittingRef = useRef(false); // 同步提交锁,防止快速重复点击导致的并发提交 |
| | | const ratingSwitchTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null); // 评分切换过渡计时器 |
| | | const ratingOptionsRequestIdRef = useRef(0); // 拉取问题类型请求序号,避免异步串台 |
| | | const ratingTouchStartRef = useRef<{ x: number; y: number } | null>(null); // 弹窗区域滑动起点 |
| | | const ratingTouchMoveRef = useRef<{ x: number; y: number } | null>(null); // 弹窗区域滑动过程点 |
| | | const { |
| | | images: pictures, |
| | | uploading, |
| | |
| | | 1: { |
| | | title: '“不满意,我要吐槽”', |
| | | summary: '不满意,我要吐槽', |
| | | placeholder: '请详描述您遇到的问题(可添加相关截图辅助说明)' |
| | | placeholder: '请描述您的建议或问题' |
| | | }, |
| | | 2: { |
| | | title: '“一般般,还需努力”', |
| | |
| | | }[currentOrderRating] || { |
| | | title: '“不满意,我要吐槽”', |
| | | summary: '不满意,我要吐槽', |
| | | placeholder: '请详描述您遇到的问题(可添加相关截图辅助说明)' |
| | | placeholder: '请描述您的建议或问题' |
| | | }; |
| | | const evaluateDimensionMap: Record<number, number> = { |
| | | 3: 1, |
| | |
| | | setSelectedRating(rating); |
| | | ratingSwitchTimerRef.current = null; |
| | | }, 120); |
| | | }; |
| | | |
| | | const getTouchPoint = (touch: any) => ({ |
| | | x: Number(touch?.pageX ?? touch?.clientX ?? touch?.x ?? 0), |
| | | y: Number(touch?.pageY ?? touch?.clientY ?? touch?.y ?? 0) |
| | | }); |
| | | |
| | | /** |
| | | * 评分区域:记录滑动起点。 |
| | | */ |
| | | const handleRatingTouchStart = (e: any) => { |
| | | const touch = e?.touches?.[0]; |
| | | if (!touch) { |
| | | return; |
| | | } |
| | | const point = getTouchPoint(touch); |
| | | ratingTouchStartRef.current = point; |
| | | ratingTouchMoveRef.current = point; |
| | | }; |
| | | |
| | | /** |
| | | * 弹窗区域:实时记录滑动坐标,兼容部分端 changedTouches 缺失。 |
| | | */ |
| | | const handleRatingTouchMove = (e: any) => { |
| | | const touch = e?.touches?.[0]; |
| | | if (!touch) { |
| | | return; |
| | | } |
| | | ratingTouchMoveRef.current = getTouchPoint(touch); |
| | | }; |
| | | |
| | | /** |
| | | * 评分区域:左右滑动切换满意度。 |
| | | */ |
| | | const handleRatingTouchEnd = (e: any) => { |
| | | const start = ratingTouchStartRef.current; |
| | | ratingTouchStartRef.current = null; |
| | | if (!start || isRatingSwitching) { |
| | | return; |
| | | } |
| | | const touch = e?.changedTouches?.[0]; |
| | | const point = touch ? getTouchPoint(touch) : ratingTouchMoveRef.current; |
| | | if (!point) { |
| | | return; |
| | | } |
| | | const endX = point.x; |
| | | const endY = point.y; |
| | | const deltaX = endX - start.x; |
| | | const deltaY = endY - start.y; |
| | | const minSwipeDistance = 24; |
| | | |
| | | // 只响应明显的水平滑动,避免与纵向滚动或点击冲突。 |
| | | if (Math.abs(deltaX) < minSwipeDistance || Math.abs(deltaX) <= Math.abs(deltaY)) { |
| | | return; |
| | | } |
| | | |
| | | const direction = deltaX < 0 ? 1 : -1; // 左滑=下一档,右滑=上一档 |
| | | const nextRating = Math.min(3, Math.max(1, selectedRating + direction)); |
| | | handleSelectRating(nextRating); |
| | | }; |
| | | |
| | | const toggleFeedbackType = (typeId: unknown) => { |
| | |
| | | return ( |
| | | <View className='evaluate-popup' catchMove onClick={(e) => e.stopPropagation()}> |
| | | <View className='evaluate-mask' onClick={onClose}></View> |
| | | <View className={`evaluate-content ${isRatingSwitching ? 'is-rating-switching' : ''}`} animation={animationData}> |
| | | <View |
| | | className={`evaluate-content ${isRatingSwitching ? 'is-rating-switching' : ''}`} |
| | | animation={animationData} |
| | | onTouchStart={handleRatingTouchStart} |
| | | onTouchMove={handleRatingTouchMove} |
| | | onTouchEnd={handleRatingTouchEnd} |
| | | > |
| | | <View className='evaluate-content-close'> |
| | | <Image onClick={onClose} src="https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/close-icon.png" /> |
| | | <Image onClick={onClose} src="https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/v2/close-fill-20260726.svg" /> |
| | | </View> |
| | | <View className='evaluate-rating-switcher'> |
| | | <View className='evaluate-rating-switcher-title'>您对本次行程满意吗?</View> |
| | |
| | | <View className='content-box'> |
| | | {!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 ${selectedTypeIds.includes(normalizeFeedbackTypeId(item?.id)) && 'active-tag'}`} onClick={() => toggleFeedbackType(item?.id)}> |
| | |
| | | { |
| | | pictures.length < 3 && ( |
| | | <View className='evaluate-problem-pic-box-upload' onClick={chooseAndUpload}> |
| | | <Image className='evaluate-problem-pic-box-upload-img' src="https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/upload-icon.png" /> |
| | | <View className='evaluate-problem-pic-box-upload-count'>{pictures.length}/3</View> |
| | | <Image className='evaluate-problem-pic-box-upload-img' src="https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/v2/add-icon-20260726.svg" /> |
| | | <View className='evaluate-problem-pic-box-upload-text'>上传图片/视频</View> |
| | | </View> |
| | | ) |
| | | } |