feat(begin-route, order-detail): 配置化优化评价弹窗,新增分享行程按钮配置

1. 重构评价相关API,新增evaluateDimension参数获取对应反馈类型
2. 新增全局状态管理当前选中的评价评分
3. 优化评价弹窗组件,根据评分动态切换图标、标题和输入占位符
4. 新增后端配置控制评价弹窗触发逻辑与分享行程按钮展示
5. 同步更新订单详情页评价流程,与行程页保持一致
6. 临时注释use-order-payment中的支付接口调用
12个文件已修改
156 ■■■■■ 已修改文件
src/robotaxi/api/begin-route.ts 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/begin-route-view-context.tsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/begin-route-view.tsx 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/calling-car-modules/evaluation-card.tsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/calling-car-modules/trip-action-bar.tsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/calling-car.tsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/evaluate-popup.tsx 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/hooks/use-order-distance-config.ts 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/hooks/use-order-payment.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/hooks/use-view-delegates.tsx 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/index.tsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/order/detail/index.tsx 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/api/begin-route.ts
@@ -254,9 +254,10 @@
}
// 获取订单评价类型
export const getOrderCommentType = async (): Promise<OrderCommentTypeItem[]> => {
export const getOrderCommentType = async (evaluateDimension: number): Promise<OrderCommentTypeItem[]> => {
    return request({
        url: _ROBOTAXI_HOST + `/operation/base/v1/mini-program/feedback-type/getList`,
        // url: _ROBOTAXI_HOST + `/operation/base/v1/mini-program/feedback-type/getList`,
        url: _ROBOTAXI_HOST + `/operation/base/v1/mini-program/evaluateTag/list?evaluateDimension=${evaluateDimension}`,
        method: 'GET'
    }, true);
}
src/robotaxi/pages/begin-route/components/begin-route-view-context.tsx
@@ -123,6 +123,8 @@
  showEvaluatePopup: boolean;
  /** 订单 ID。 */
  orderId: string;
  /** 当前评价弹窗对应的评分。 */
  evaluateOrderRating: number;
  /** 关闭评价弹窗。 */
  handleCloseEvaluatePopup: () => void;
  /** 确认评价。 */
src/robotaxi/pages/begin-route/components/begin-route-view.tsx
@@ -172,6 +172,7 @@
    changeCheckedEnter,
    showEvaluatePopup,
    orderId,
    evaluateOrderRating,
    handleCloseEvaluatePopup,
    handleConfirmEvaluate,
    showAuthBluetoothPopup = false,
@@ -226,7 +227,7 @@
      <EvaluatePopup
        show={showEvaluatePopup}
        orderId={orderId}
        orderRating={1}
        orderRating={evaluateOrderRating}
        onClose={handleCloseEvaluatePopup}
        onConfirm={handleConfirmEvaluate}
      />
src/robotaxi/pages/begin-route/components/calling-car-modules/evaluation-card.tsx
@@ -8,9 +8,10 @@
type Props = {
    tripStatus: TripStatus;
    orderId?: string;
    handleOpenEvaluatePopup?: () => void;
    handleOpenEvaluatePopup?: (orderRating: number) => void;
    evaluateSubmitVersion?: number;
    evaluateCloseVersion?: number;
    evaluatePopupStatus?: number;
};
export default function EvaluationCard({
@@ -18,7 +19,8 @@
    orderId,
    handleOpenEvaluatePopup,
    evaluateSubmitVersion,
    evaluateCloseVersion
    evaluateCloseVersion,
    evaluatePopupStatus = 0
}: Props) {
    const good = 'https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/good.png';
    const normal = 'https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/normal.png';
@@ -50,12 +52,12 @@
        }
    }, [evaluateCloseVersion]);
    // 点击评价项:不满意走弹窗,其余直接提交
    // 点击评价项:配置开启时任意评价都走弹窗,否则直接提交
    const changeEvaluate = (index: number) => {
        if (isEvaluated) return;
        setActiveIndex(index);
        if (index === 1) {
            handleOpenEvaluatePopup?.();
        if (evaluatePopupStatus === 1) {
            handleOpenEvaluatePopup?.(index);
            return;
        }
        const targetOrderId = getOrderId(orderId);
src/robotaxi/pages/begin-route/components/calling-car-modules/trip-action-bar.tsx
@@ -7,6 +7,7 @@
    handleModifyDestination?: () => void;
    handleShareTrip?: () => void;
    showModifyDestination?: boolean;
    showShareTrip?: boolean;
};
export default function TripActionBar({
@@ -14,7 +15,8 @@
    handleCancelTrip,
    handleModifyDestination,
    handleShareTrip,
    showModifyDestination = true
    showModifyDestination = true,
    showShareTrip = true
}: Props) {
    // 按行程状态控制按钮集合,避免在 JSX 中堆叠过多条件判断
    const actionList = [
@@ -36,7 +38,7 @@
            key: "share",
            label: "分享行程",
            icon: 'https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/share-trip.png',
            visible: [TripStatus.VehicleApproaching, TripStatus.VehicleArrivedPickup, TripStatus.InService].includes(tripStatus),
            visible: [TripStatus.VehicleApproaching, TripStatus.VehicleArrivedPickup, TripStatus.InService].includes(tripStatus) && showShareTrip,
            onClick: handleShareTrip
        }
    ].filter(item => item.visible);
src/robotaxi/pages/begin-route/components/calling-car.tsx
@@ -32,6 +32,8 @@
    evaluateSubmitVersion?: number;
    /** 外部触发“评价弹窗关闭”版本号 */
    evaluateCloseVersion?: number;
    /** 评价弹窗开关配置,0 不弹窗,1 点击任意评价都弹窗 */
    evaluatePopupStatus?: number;
    /** 打开结束行程弹窗 */
    handleOpenOverRoutePopup?: () => void;
    /** 费用明细展开/收起时同步地图视觉状态 */
@@ -39,13 +41,15 @@
    /** 立即支付回调 */
    handlePay?: () => void;
    /** 打开详细评价弹窗 */
    handleOpenEvaluatePopup?: () => void;
    handleOpenEvaluatePopup?: (orderRating: number) => void;
    /** 取消行程 */
    handleCancelTrip?: () => void;
    /** 修改目的地 */
    handleModifyDestination?: () => void;
    /** 是否展示修改目的地 */
    showModifyDestination?: boolean;
    /** 是否展示分享行程 */
    showShareTrip?: boolean;
    /** 分享行程 */
    handleShareTrip?: () => void;
    /** 预估等待分钟数 */
@@ -88,6 +92,7 @@
    priceUpdateVersion,
    evaluateSubmitVersion,
    evaluateCloseVersion,
    evaluatePopupStatus = 0,
    handleOpenOverRoutePopup,
    onToggleDetailFade,
    handlePay,
@@ -95,6 +100,7 @@
    handleCancelTrip,
    handleModifyDestination,
    showModifyDestination = true,
    showShareTrip = true,
    handleShareTrip,
    estimatedWaitMinutes,
    routeDurationSeconds,
@@ -219,6 +225,7 @@
                        handleCancelTrip={handleCancelTrip}
                        handleModifyDestination={handleModifyDestination}
                        showModifyDestination={showModifyDestination}
                        showShareTrip={showShareTrip}
                        handleShareTrip={handleShareTrip}
                    />
                </View>
@@ -239,6 +246,7 @@
                handleOpenEvaluatePopup={handleOpenEvaluatePopup}
                evaluateSubmitVersion={evaluateSubmitVersion}
                evaluateCloseVersion={evaluateCloseVersion}
                evaluatePopupStatus={evaluatePopupStatus}
            />
        </View>
    );
src/robotaxi/pages/begin-route/components/evaluate-popup.tsx
@@ -18,6 +18,8 @@
export default function EvaluatePopup({ show = false, onClose, onConfirm, orderId, orderRating, submitMode = 'comment' }: 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';
    const [visible, setVisible] = useState(false); // 弹窗显示状态
    const [animationData, setAnimationData] = useState<any>(); // 弹窗进出场动画
    const [selectedTypeId, setSelectedTypeId] = useState<number | null>(null); // 当前选择的问题类型
@@ -36,6 +38,36 @@
        compress: true,
        uploadUrl: _ROBOTAXI_HOST + '/operation/base/v1/mini-program/oss/upload'
    }); // 图片上传状态与操作
    // 根据外部点击的评分,动态展示评价弹窗的 icon 和文案
    const currentOrderRating = Number(orderRating) || 1;
    const popupDisplayConfig = {
        1: {
            icon: activeBad,
            title: '“不满意,我要吐槽”',
            placeholder: '请详描述您遇到的问题(可添加相关截图辅助说明)'
        },
        2: {
            icon: activeNormal,
            title: '“一般般,还需努力”',
            placeholder: '告诉我们哪些方面还可以继续改进'
        },
        3: {
            icon: activeGood,
            title: '“很满意,表扬一下”',
            placeholder: '告诉我哪里做的不错,我们继续保持!'
        }
    }[currentOrderRating] || {
        icon: activeBad,
        title: '“不满意,我要吐槽”',
        placeholder: '请详描述您遇到的问题(可添加相关截图辅助说明)'
    };
    const evaluateDimensionMap: Record<number, number> = {
        3: 1,
        2: 2,
        1: 3
    };
    const evaluateDimension = evaluateDimensionMap[currentOrderRating] || 3; // 接口维度:1 满意,2 一般,3 不满意
    // 控制弹窗开合动画
    useEffect(() => {
@@ -141,7 +173,7 @@
        setSelectedTypeId(null);
        setFeedbackContent('');
        resetImages();
        getOrderCommentType().then((res: any) => {
        getOrderCommentType(evaluateDimension).then((res: any) => {
            const list = res;
            if (Array.isArray(list)) {
                setTypeOptions(list);
@@ -151,7 +183,7 @@
        }).catch(() => {
            setTypeOptions([]);
        });
    }, [resetImages, show]);
    }, [evaluateDimension, resetImages, show]);
    if (!visible) return null;
@@ -163,12 +195,12 @@
                    <Image onClick={onClose} src="https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/close-icon.png" />
                </View>
                <View className='evaluate-content-title'>
                    <Image src={activeBad} />
                    <View>“不满意,我要吐槽”</View>
                    <Image src={popupDisplayConfig.icon} />
                    <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-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?.feedbackType}</View>
@@ -180,7 +212,7 @@
                            className='evaluate-problem-desc'
                            maxlength={500}
                            placeholderClass='placeholder-class'
                            placeholder='请描述您的建议或问题(可添加相关截图)'
                            placeholder={popupDisplayConfig.placeholder}
                            value={feedbackContent}
                            onInput={(e) => setFeedbackContent(e.detail.value)} />
                        <View className='evaluate-problem-desc-count'>{feedbackContent.length}/500</View>
src/robotaxi/pages/begin-route/hooks/use-order-distance-config.ts
@@ -9,6 +9,8 @@
  minDistance?: number;
  adsorptionDistance?: number;
  queuePollingTime?: number;
  tripShareStatus?: number;
  evaluatePopupStatus?: number;
  walkingNavigationDistance?: number;
  maxStandingTiming?: number;
  xczSyDistance?: number;
@@ -47,6 +49,8 @@
          minDistance: Number(res.minDistance),
          adsorptionDistance: Number(res.adsorptionDistance),
          queuePollingTime: Number(res.queuePollingTime),
          tripShareStatus: Number(res.tripShareStatus),
          evaluatePopupStatus: Number(res.evaluatePopupStatus),
          walkingNavigationDistance: Number(res.walkingNavigationDistance),
          maxStandingTiming: Number(res.maxStandingTiming),
          xczSyDistance: Number(res.xczSyDistance),
src/robotaxi/pages/begin-route/hooks/use-order-payment.ts
@@ -185,7 +185,7 @@
    }
    paySubmittingRef.current = true;
    try {
      await getOrderPayment({ orderId: targetOrderId });
      // await getOrderPayment({ orderId: targetOrderId });
      syncPaymentSuccessStatus();
src/robotaxi/pages/begin-route/hooks/use-view-delegates.tsx
@@ -93,18 +93,22 @@
  evaluateSubmitVersion: number;
  /** 评价关闭版本 */
  evaluateCloseVersion: number;
  /** 评价弹窗开关配置 */
  evaluatePopupStatus: number;
  /** 打开结束弹窗 */
  handleOpenOverRoutePopup: () => void;
  /** 支付 */
  handlePay: () => void;
  /** 打开评价 */
  handleOpenEvaluatePopup: () => void;
  handleOpenEvaluatePopup: (orderRating: number) => void;
  /** 详情展开回调 */
  handleToggleDetailFade: (expanded: boolean, hasFare: boolean) => void;
  /** 修改目的地 */
  handleModifyDestination: () => void;
  /** 是否展示修改目的地 */
  showModifyDestination: boolean;
  /** 是否展示分享行程 */
  showShareTrip: boolean;
  /** 分享行程 */
  handleShareTrip: () => void;
  /** 路线选择展开状态 */
@@ -436,6 +440,7 @@
          handleCancelTrip={() => deps.handleOpenCancelPopupByTripStatus(deps.tripStatus, true)}
          handleModifyDestination={deps.handleModifyDestination}
          showModifyDestination={deps.showModifyDestination}
          showShareTrip={deps.showShareTrip}
          handleShareTrip={deps.handleShareTrip}
          handleCancelTimeout={deps.handlePickupTimeoutAutoCancel}
          handleFinishTimeout={deps.handleFinishCountdownTimeout}
@@ -443,6 +448,7 @@
          priceUpdateVersion={deps.priceUpdateVersion}
          evaluateSubmitVersion={deps.evaluateSubmitVersion}
          evaluateCloseVersion={deps.evaluateCloseVersion}
          evaluatePopupStatus={deps.evaluatePopupStatus}
          handleOpenOverRoutePopup={deps.handleOpenOverRoutePopup}
          handlePay={deps.handlePay}
          onOpenCouponSelect={deps.handleOpenCouponSelect}
src/robotaxi/pages/begin-route/index.tsx
@@ -168,7 +168,7 @@
    handleOpenPassengerNotice,
    showEvaluatePopup,
    setShowEvaluatePopup,
    handleOpenEvaluatePopup,
    handleOpenEvaluatePopup: _handleOpenEvaluatePopup,
    showTipPopup,
    setShowTipPopup,
    handleCloseTipPopup,
@@ -199,6 +199,7 @@
  const [priceUpdateVersion, setPriceUpdateVersion] = useState(0); // 价格更新版本号
  const [evaluateSubmitVersion, setEvaluateSubmitVersion] = useState(0); // 评价提交版本号
  const [evaluateCloseVersion, setEvaluateCloseVersion] = useState(0); // 评价关闭版本号
  const [evaluateOrderRating, setEvaluateOrderRating] = useState(1); // 当前评价弹窗对应评分
  const [showCouponSelectPopup, setShowCouponSelectPopup] = useState(false); // 优惠券选择弹窗展示状态
  const [showModifyDestinationFailPopup, setShowModifyDestinationFailPopup] = useState(false); // 修改目的地失败弹窗
  const [modifyDestinationFailMessage, setModifyDestinationFailMessage] = useState(''); // 修改目的地失败文案(默认空,避免闪文案)
@@ -694,6 +695,8 @@
  const queuePollingTimeSeconds = Number.isFinite(Number(distanceConfig?.queuePollingTime)) && Number(distanceConfig?.queuePollingTime) > 0
    ? Number(distanceConfig?.queuePollingTime)
    : DEFAULT_QUEUE_POLLING_TIME; // 排队位次轮询频率(秒)
  const showShareTrip = Number(distanceConfig?.tripShareStatus) === 1; // 分享行程入口展示开关
  const evaluatePopupStatus = Number(distanceConfig?.evaluatePopupStatus) === 1 ? 1 : 0; // 评价弹窗开关
  const walkingNavigationDistance = Number.isFinite(Number(distanceConfig?.walkingNavigationDistance))
    ? Number(distanceConfig?.walkingNavigationDistance)
    : 0; // 步行导航按钮展示阈值(米)
@@ -1147,7 +1150,12 @@
    vehicleLocation
  ]);
  // 打开评价弹窗
  // 打开评价弹窗,并记录当前点击的评分
  const handleOpenEvaluatePopup = (orderRating: number) => {
    setEvaluateOrderRating(orderRating);
    setShowEvaluatePopup(true);
  };
  const handleCloseEvaluatePopup = () => {
    setEvaluateCloseVersion(v => v + 1);
    setShowEvaluatePopup(false);
@@ -1441,12 +1449,14 @@
    priceUpdateVersion,
    evaluateSubmitVersion,
    evaluateCloseVersion,
    evaluatePopupStatus,
    handleOpenOverRoutePopup,
    handlePay,
    handleOpenEvaluatePopup,
    handleToggleDetailFade,
    handleModifyDestination,
    showModifyDestination,
    showShareTrip,
    handleShareTrip,
    trunkStatus,
    routeOptions,
@@ -1564,6 +1574,7 @@
    changeCheckedEnter,
    showEvaluatePopup,
    orderId,
    evaluateOrderRating,
    handleCloseEvaluatePopup,
    handleConfirmEvaluate
  };
src/robotaxi/pages/order/detail/index.tsx
@@ -5,6 +5,7 @@
import { getOrderDetail } from '../../../api/order';
import EvaluatePopup from '../../begin-route/components/evaluate-popup';
import { submitOrderComment } from '../../../api/begin-route';
import { getOrderDistance } from '../../../api/select-map-site';
import { formatTripDistance, formatTripDurationFromSeconds, safeParse } from '../../../../utils/Robotaxi-public-method';
import { getOrderId } from '../../../utils/order';
import { withRobotaxiWhitelist } from '../../../../utils/whitelist';
@@ -23,6 +24,8 @@
  const [activeIndex, setActiveIndex] = useState<number | null>(null) // 默认选中"非常满意"
  const [orderData, setOrderData] = useState<any>(null);
  const [showEvaluatePopup, setShowEvaluatePopup] = useState(false);
  const [selectedOrderRating, setSelectedOrderRating] = useState(1); // 当前准备提交的评价分值
  const [evaluatePopupStatus, setEvaluatePopupStatus] = useState(0); // 0 不弹评价弹窗,1 点击任意评价都弹窗
  const showEvaluatePopupRef = useRef(false);
  // 地图相关状态
@@ -63,6 +66,19 @@
      fetchOrderDetail(orderId);
    }
  }, [orderId]);
  useEffect(() => {
    const fetchEvaluatePopupConfig = async () => {
      try {
        const res: any = await getOrderDistance();
        // setEvaluatePopupStatus(Number(res?.evaluatePopupStatus) === 1 ? 1 : 0);
        setEvaluatePopupStatus(1);
      } catch (error) {
        setEvaluatePopupStatus(0);
      }
    };
    fetchEvaluatePopupConfig();
  }, []);
  useEffect(() => {
    showEvaluatePopupRef.current = showEvaluatePopup;
@@ -221,32 +237,43 @@
    setActiveIndex(null);
  }
  const handleConfirmEvaluate = () => {
    setActiveIndex(1);
    setActiveIndex(selectedOrderRating);
    setShowEvaluatePopup(false);
  }
  const changeEvaluate = (index: number) => {
    if (activeIndex !== null) return;
    if (index === 1) {
      handleOpenEvaluatePopup();
      return;
    }
  const submitSimpleEvaluate = (index: number) => {
    const targetOrderId = getOrderId(orderId);
    if (!targetOrderId) {
      Taro.showToast({ title: '订单信息缺失,无法提交评价', icon: 'none' });
      return;
    }
    const successToastMap: Record<number, string> = {
      1: '收到您的评价,我们将努力提升体验',
      2: '收到您的评价,我们将努力提升体验',
      3: '感谢您的反馈,欢迎下次乘坐'
    };
    submitOrderComment({ orderRating: index, orderId: targetOrderId })
      .then(() => {
        setActiveIndex(index);
        Taro.showToast({
          title: ['收到您的评价,我们将努力提升体验', '感谢您的反馈,欢迎下次乘坐'][index - 2],
          title: successToastMap[index] || '评价提交成功',
          icon: 'none'
        });
      })
      .catch(() => {
        Taro.showToast({ title: '评价提交失败,请稍后重试', icon: 'none' });
      });
  }
  const changeEvaluate = (index: number) => {
    if (activeIndex !== null) return;
    if (evaluatePopupStatus === 1) {
      // 配置开启时,任意评价项都走弹窗反馈链路。
      setSelectedOrderRating(index);
      handleOpenEvaluatePopup();
      return;
    }
    submitSimpleEvaluate(index);
  }
  if (!orderData) return null;
@@ -345,7 +372,7 @@
      <EvaluatePopup
        show={showEvaluatePopup}
        orderId={orderId}
        orderRating={1}
        orderRating={selectedOrderRating}
        onClose={handleCloseEvaluatePopup}
        onConfirm={handleConfirmEvaluate}
      />