fuqj
2026-08-13 648a3199afcbaf8fb356c64ef9da862593199a30
fix(complaint): 移除投诉提交通用提示并简化评价弹窗逻辑
7个文件已修改
194 ■■■■■ 已修改文件
src/robotaxi/api/begin-route.ts 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/api/feedback.ts 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/api/order.ts 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/css-folder/evaluate-popup.less 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/evaluate-popup.tsx 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/expense-description/index.less 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/expense-description/index.tsx 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/api/begin-route.ts
@@ -286,7 +286,8 @@
    return request({
        url: _ROBOTAXI_HOST + `/order/api/v1/mini-program/order/comment`,
        method: 'POST',
        payload
        payload,
        showToast: false
    }, true);
}
src/robotaxi/api/feedback.ts
@@ -1,9 +1,21 @@
import request from '../../utils/request';
import { _ROBOTAXI_HOST } from '../../constants/api';
import type { SubmitComplaintPayload, SubmitFeedbackResponse } from './types/begin-route';
import type { SubmitComplaintPayload, SubmitFeedbackResponse, SubmitOrderCommentPayload } from './types/begin-route';
import type { FeedbackTypeItem } from './types/feedback';
// 提交订单投诉
export const submitOrderComplaint = async (
    payload: SubmitOrderCommentPayload
): Promise<SubmitFeedbackResponse> => {
    return request({
        url: _ROBOTAXI_HOST + `/operation/base/v1/mini-program/orderComplaint/submit`,
        method: 'POST',
        payload,
        showToast: false
    }, true);
}
// 提交独立反馈投诉
export const submitComplaint = async (
    payload: SubmitComplaintPayload
): Promise<SubmitFeedbackResponse> => {
src/robotaxi/api/order.ts
@@ -53,6 +53,7 @@
    start: FareItem[];
    time: number;
    payMoney?: number; // 实际支付金额,虽然detail.txt没写,但页面展示需要,可能包含在返回中或需计算
    hasComplaint: boolean; // 是否已反馈
}
export type FareBreakdownPayload = {
src/robotaxi/pages/begin-route/components/css-folder/evaluate-popup.less
@@ -25,6 +25,11 @@
        border-radius: 60px 60px 0 0;
        padding: 64px 0 0 0;
        &.is-fare-feedback {
            height: 812px;
            padding-top: 48px;
        }
        .evaluate-rating-switcher,
        .content-box {
            transition: opacity 180ms ease, transform 180ms ease;
@@ -84,6 +89,11 @@
                align-self: stretch;
                padding-left: 30px;
                box-sizing: border-box;
                &.is-centered {
                    text-align: center;
                    padding-left: 0;
                }
            }
            &-content {
src/robotaxi/pages/begin-route/components/evaluate-popup.tsx
@@ -4,7 +4,7 @@
import { useEffect, useRef, useState } from 'react';
import './css-folder/evaluate-popup.less'
import { getOrderCommentType, submitOrderComment } from '../../../api/begin-route';
import { submitComplaint } from '../../../api/feedback';
import { submitOrderComplaint } from '../../../api/feedback';
import { _ROBOTAXI_HOST } from '../../../../constants/api';
import useImageUpload from '../../../hooks/use-image-upload';
import { getOrderId } from '../../../utils/order';
@@ -16,7 +16,7 @@
    onConfirm?: () => void;
    orderId?: string;
    orderRating?: number;
    submitMode?: 'comment' | 'complaint';
    submitMode?: 'comment' | 'orderComplaint';
    /**
     * 是否隐藏问题类型选择
     */
@@ -25,6 +25,11 @@
     * 是否禁止切换满意度评分(点击图标/左右滑动均禁用),固定为传入的 orderRating
     */
    disableRatingSwitch?: boolean;
    /**
     * 是否为「订单车费反馈」入口(车费说明页 complaint-btn 触发):
     * 标题居中展示为「订单车费反馈」,隐藏满意度切换区(图标+文案)
     */
    isFareFeedback?: boolean;
}
export default function EvaluatePopup({
@@ -35,7 +40,8 @@
    orderRating,
    submitMode = 'comment',
    hideFeedbackType = false,
    disableRatingSwitch = false
    disableRatingSwitch = false,
    isFareFeedback = false
}: Props) {
    const bad = 'https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/bad.png';
    const normal = 'https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/normal.png';
@@ -67,6 +73,8 @@
        uploadUrl: _ROBOTAXI_HOST + '/operation/base/v1/mini-program/oss/upload'
    }); // 图片上传状态与操作
    const toastCommomText = submitMode === 'orderComplaint' ? '反馈' : '评价';
    const currentOrderRating = Number(selectedRating) || 1;
    // 根据当前选择的评分,动态展示评价弹窗的文案
    const popupDisplayConfig = {
@@ -97,7 +105,7 @@
    };
    const evaluateDimension = evaluateDimensionMap[currentOrderRating] || 3; // 接口维度:1 满意,2 一般,3 不满意
    const shouldRequireFeedbackType = !hideFeedbackType;
    const shouldHideFeedbackTextarea = submitMode === 'comment' && [2, 3].includes(currentOrderRating);
    const shouldHideFeedbackTextarea = [2, 3].includes(currentOrderRating);
    const hasFeedbackContent = !!feedbackContent.trim();
    const canSubmit = shouldRequireFeedbackType
        ? selectedTypeIds.length > 0 && (shouldHideFeedbackTextarea || hasFeedbackContent)
@@ -210,7 +218,7 @@
        const targetOrderId = getOrderId(orderId);
        if (!targetOrderId) {
            showToast({
                title: '订单信息缺失,无法提交评价',
                title: `订单信息缺失,无法提交${toastCommomText}`,
                icon: 'none'
            });
            return;
@@ -230,7 +238,7 @@
            return;
        }
        isSubmittingRef.current = true;
        const submitter = submitMode === 'complaint' ? submitComplaint : submitOrderComment;
        const submitter = submitMode === 'orderComplaint' ? submitOrderComplaint : submitOrderComment;
        const picturePayload = JSON.stringify(
            pictures
                .filter(p => p.status === 'success' && p.server && p.server.id && p.server.url)
@@ -249,20 +257,19 @@
            const isFailure = res?.success === false || (typeof res?.code === 'number' && res.code !== 0);
            if (isFailure) {
                showToast({
                    title: '评价提交失败,请稍后重试',
                    title: `${toastCommomText}提交失败,请稍后重试`,
                    icon: 'none'
                });
                return;
            }
            const successTitle = submitMode === 'complaint' ? '投诉已提交' : '评价已提交';
            showToast({
                title: successTitle,
                title: `${toastCommomText}已提交`,
                icon: 'none'
            });
            onConfirm?.();
        }).catch(() => {
            showToast({
                title: '评价提交失败,请稍后重试',
                title: `${toastCommomText}提交失败,请稍后重试`,
                icon: 'none'
            });
        }).finally(() => {
@@ -330,7 +337,7 @@
        <View className='evaluate-popup' catchMove onClick={(e) => e.stopPropagation()}>
            <View className='evaluate-mask' onClick={onClose}></View>
            <View
                className={`evaluate-content ${isRatingSwitching ? 'is-rating-switching' : ''}`}
                className={`evaluate-content ${isRatingSwitching ? 'is-rating-switching' : ''} ${isFareFeedback ? 'is-fare-feedback' : ''}`}
                animation={animationData}
                onTouchStart={handleRatingTouchStart}
                onTouchMove={handleRatingTouchMove}
@@ -340,33 +347,37 @@
                    <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={`evaluate-rating-switcher-content ${disableRatingSwitch ? 'is-single' : ''}`}>
                        {(!disableRatingSwitch || selectedRating === 1) && (
                            <View className={`evaluate-rating-switcher-content-item ${disableRatingSwitch ? 'is-disabled' : ''}`} onClick={() => handleSelectRating(1)}>
                                <Image src={selectedRating === 1 ? activeBad : bad} className='evaluate-rating-switcher-content-item-img' />
                                <Text className={`evaluate-rating-switcher-content-item-text ${selectedRating === 1 ? 'active-text' : ''}`}>不满意</Text>
                    <View className={`evaluate-rating-switcher-title ${isFareFeedback ? 'is-centered' : ''}`}>{isFareFeedback ? '订单车费反馈' : '您对本次行程满意吗?'}</View>
                    {!isFareFeedback && (
                        <>
                            <View className={`evaluate-rating-switcher-content ${disableRatingSwitch ? 'is-single' : ''}`}>
                                {(!disableRatingSwitch || selectedRating === 1) && (
                                    <View className={`evaluate-rating-switcher-content-item ${disableRatingSwitch ? 'is-disabled' : ''}`} onClick={() => handleSelectRating(1)}>
                                        <Image src={selectedRating === 1 ? activeBad : bad} className='evaluate-rating-switcher-content-item-img' />
                                        <Text className={`evaluate-rating-switcher-content-item-text ${selectedRating === 1 ? 'active-text' : ''}`}>不满意</Text>
                                    </View>
                                )}
                                {(!disableRatingSwitch || selectedRating === 2) && (
                                    <View className={`evaluate-rating-switcher-content-item ${disableRatingSwitch ? 'is-disabled' : ''}`} onClick={() => handleSelectRating(2)}>
                                        <Image src={selectedRating === 2 ? activeNormal : normal} className='evaluate-rating-switcher-content-item-img' />
                                        <Text className={`evaluate-rating-switcher-content-item-text ${selectedRating === 2 ? 'active-text' : ''}`}>一般般</Text>
                                    </View>
                                )}
                                {(!disableRatingSwitch || selectedRating === 3) && (
                                    <View className={`evaluate-rating-switcher-content-item ${disableRatingSwitch ? 'is-disabled' : ''}`} onClick={() => handleSelectRating(3)}>
                                        <Image src={selectedRating === 3 ? activeGood : good} className='evaluate-rating-switcher-content-item-img' />
                                        <Text className={`evaluate-rating-switcher-content-item-text ${selectedRating === 3 ? 'active-text' : ''}`}>很满意</Text>
                                    </View>
                                )}
                            </View>
                        )}
                        {(!disableRatingSwitch || selectedRating === 2) && (
                            <View className={`evaluate-rating-switcher-content-item ${disableRatingSwitch ? 'is-disabled' : ''}`} onClick={() => handleSelectRating(2)}>
                                <Image src={selectedRating === 2 ? activeNormal : normal} className='evaluate-rating-switcher-content-item-img' />
                                <Text className={`evaluate-rating-switcher-content-item-text ${selectedRating === 2 ? 'active-text' : ''}`}>一般般</Text>
                            </View>
                        )}
                        {(!disableRatingSwitch || selectedRating === 3) && (
                            <View className={`evaluate-rating-switcher-content-item ${disableRatingSwitch ? 'is-disabled' : ''}`} onClick={() => handleSelectRating(3)}>
                                <Image src={selectedRating === 3 ? activeGood : good} className='evaluate-rating-switcher-content-item-img' />
                                <Text className={`evaluate-rating-switcher-content-item-text ${selectedRating === 3 ? 'active-text' : ''}`}>很满意</Text>
                            </View>
                        )}
                    </View>
                    <View className='evaluate-rating-switcher-summary'>{popupDisplayConfig.summary}</View>
                            <View className='evaluate-rating-switcher-summary'>{popupDisplayConfig.summary}</View>
                        </>
                    )}
                </View>
                <View className='content-box'>
                    {!hideFeedbackType && (
                        <View className='evaluate-problem-type'>
                            <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)}>
src/robotaxi/pages/expense-description/index.less
@@ -1,12 +1,14 @@
@import '../../style/ui-variables.less';
.expense-detail-page {
  background: #F2F3F7;
  background: @gary-theme;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  padding: 32px 24px;
  .order-info {
    border-radius: 24px;
    border-radius: 60px;
    background: #FFFFFF;
    padding: 32px 28px 30px 28px;
@@ -16,7 +18,7 @@
      font-weight: 500;
      line-height: 48px;
      font-variation-settings: "opsz" auto;
      color: rgba(0, 0, 0, 0.9);
      color: @black-text-main;
      margin-left: 4px;
    }
@@ -31,7 +33,7 @@
        font-weight: normal;
        line-height: 36px;
        text-align: right;
        color: rgba(0, 0, 0, 0.4);
        color: @black-text-04;
      }
      .arrow-icon {
@@ -46,8 +48,8 @@
  .price-card {
    margin-top: 24px;
    border-radius: 16px;
    background: #F5F6FA;
    border-radius: 40px;
    background: @gary-theme;
    padding: 24px 32px;
    .mb-16 {
@@ -60,7 +62,7 @@
      font-weight: normal;
      line-height: 40px;
      /* 文字色/黑色/重要字 90% */
      color: rgba(0, 0, 0, 0.9);
      color: @black-text-main;
    }
@@ -72,7 +74,7 @@
      text-align: right;
      font-variation-settings: "opsz" auto;
      /* 文字色/黑色/重要字 90% */
      color: rgba(0, 0, 0, 0.9);
      color: @black-text-main;
    }
    .price-notice-label {
@@ -84,7 +86,7 @@
      font-variation-settings: "opsz" auto;
      /* 文字色/黑色/辅助文字 40% */
      color: rgba(0, 0, 0, 0.4);
      color: @black-text-04;
    }
@@ -96,13 +98,14 @@
      text-align: right;
      font-variation-settings: "opsz" auto;
      /* 文字色/黑色/辅助文字 40% */
      color: rgba(0, 0, 0, 0.4);
      color: @black-text-04;
    }
  }
  .total {
    margin-top: 32px;
    justify-content: flex-end;
    align-items: first baseline;
    .total-text {
      font-family: PingFang SC;
@@ -110,16 +113,15 @@
      font-weight: normal;
      line-height: 40px;
      font-variation-settings: "opsz" auto;
      color: rgba(0, 0, 0, 0.9);
      color: @black-text-main;
    }
    .num {
      font-size: 48px;
      line-height: 40px;
      font-variation-settings: "opsz" auto;
      color: rgba(0, 0, 0, 0.9);
      margin: 0 4px;
      color: @black-text-main;
      margin: 0  4px;
    }
    .unit {
@@ -128,12 +130,12 @@
      font-weight: normal;
      line-height: 40px;
      font-variation-settings: "opsz" auto;
      color: rgba(0, 0, 0, 0.9);
      color: @black-text-main;
    }
  }
  .faq {
    border-radius: 24px;
    border-radius: 60px;
    background: #FFFFFF;
    padding: 32px;
    margin-top: 24px;
@@ -143,7 +145,7 @@
      font-size: 32px;
      font-weight: 500;
      line-height: 48px;
      color: rgba(0, 0, 0, 0.9);
      color: @black-text-main;
    }
@@ -164,7 +166,7 @@
          line-height: 40px;
          font-variation-settings: "opsz" auto;
          /* 文字色/黑色/重要字 90% */
          color: rgba(0, 0, 0, 0.9);
          color: @black-text-main;
        }
        .arrow-icon {
@@ -199,13 +201,14 @@
        font-size: 24px;
        font-weight: normal;
        line-height: 36px;
        color: rgba(0, 0, 0, 0.4);
        color: @black-text-04;
      }
      .arrow-icon {
        width: 20px;
        height: 13.6px;
        margin-left: 14px;
        margin-top: 2px;
        transition: transform 0.3s ease;
        &.rotated {
@@ -216,10 +219,25 @@
  }
  .complaint {
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0 auto;
    margin-top: 30px;
    width: 549px;
    height: 92px;
    margin-top: 42px;
    width: 654px;
    height: 102px;
    border-radius: 2000px;
    box-sizing: border-box;
    border: 4px solid @black-text-main;
    font-size: 32px;
    font-weight: 500;
    line-height: normal;
    text-align: center;
    color: @black-text-main;
    &.disabled {
      border: 4px solid @black-text-04;
      color: @black-text-04;
    }
  }
}
@@ -237,6 +255,10 @@
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 4px;
  &.flex-between-card:nth-last-of-type(1) {
    margin-bottom: 0;
  }
}
.color-red {
@@ -245,4 +267,4 @@
.mt-16 {
  margin-top: 16px;
}
}
src/robotaxi/pages/expense-description/index.tsx
@@ -20,6 +20,7 @@
  const [faqData, setFaqData] = useState<FAQItem[]>([]);
  const [showEvaluatePopup, setShowEvaluatePopup] = useState(false);
  const [orderId, setOrderId] = useState('');
  const [disabledComplaint, setDisabledComplaint] = useState(false);
  useEffect(() => {
    setOrderId(router.params?.orderId || '');
@@ -36,6 +37,7 @@
      }
      const res = await getFareBreakdown(payload);
      setFareData(res);
      setDisabledComplaint(res && res.hasComplaint || false);
    } catch (error) {
      console.error('获取费用明细失败', error);
      showToast({ title: '获取费用明细失败', icon: 'none' });
@@ -98,6 +100,17 @@
  const toRulePage = () => {
    Taro.navigateTo({ url: '/robotaxi/pages/pricing-rules/index' });
  };
  const handleClickComplaint = () => {
    if (disabledComplaint) {
      showToast({
        title: '订单已有车费反馈记录,无需重复操作',
        icon: 'none'
      });
      return;
    }
    setShowEvaluatePopup(true);
  }
  if (!fareData) return null;
@@ -258,18 +271,22 @@
        </View>
      )}
      {/* 去投诉 */}
      <Image className='complaint' onClick={() => setShowEvaluatePopup(true)} src='https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/complaint-btn.png' />
      <View className={`complaint ${disabledComplaint ? 'disabled': ''} `} onClick={handleClickComplaint}>
        不认可车费,去投诉
      </View>
      {/* 评价弹窗 */}
      <EvaluatePopup
        show={showEvaluatePopup}
        orderId={orderId}
        orderRating={1}
        submitMode="complaint"
        submitMode="orderComplaint"
        hideFeedbackType
        disableRatingSwitch
        isFareFeedback
        onClose={() => setShowEvaluatePopup(false)}
        onConfirm={() => {
          setDisabledComplaint(true);
          setShowEvaluatePopup(false);
        }}
      />