13404089107
2026-04-16 21683f94b00a8023a2fc564889460e00cbb06fb3
feat(robotaxi): 添加动态路线偏好配置支持

- 新增查询路线偏好配置的 API 接口
- 改造路线偏好弹窗组件,支持从服务端动态获取选项
- 偏好选项数据结构从字符串改为对象,包含 label 和 value
- 根据 openCityId 获取对应城市的路线偏好配置,失败时使用默认选项
3个文件已修改
84 ■■■■■ 已修改文件
src/robotaxi/api/begin-route.ts 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/release-route.tsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/route-preference-popup/index.tsx 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/api/begin-route.ts
@@ -10,6 +10,15 @@
    }, true);
}
// 导航-获取路线偏好配置
export const queryRoutePreferences = async (payload) => {
    return request({
        url: _ROBOTAXI_HOST + '/itinerary/base/v1/mini-program/navigation/route-preferences',
        method: 'GET',
        payload
    }, true);
}
// 保存订单
export const saveOrder = async (payload) => {
    return request({
src/robotaxi/pages/begin-route/components/release-route.tsx
@@ -7,7 +7,7 @@
import tipDefaultIcon from '../../../assets/tip-default-icon.png'
import selectLineIcon from '../../../assets/select-line.png'
import trafficSignalIcon from '../../../assets/traffic-signal.png'
import RoutePreferencePopup from './route-preference-popup';
import RoutePreferencePopup, { RoutePreferenceOption } from './route-preference-popup';
import { formatDurationDisplay, formatTripDistance } from '../../../../utils/Robotaxi-public-method';
type Props = {
@@ -36,7 +36,8 @@
    const pendingHeight = useRef<number | null>(null);
    const [showPreferencePopup, setShowPreferencePopup] = useState(false);
    const [preference, setPreference] = useState('智能推荐');
    const [preference, setPreference] = useState<RoutePreferenceOption>({ label: '智能推荐', value: '智能推荐' });
    const openCityId = Number(Taro.getStorageSync('selectedCity')?.id || 0);
    useEffect(() => {
        if (!isRouteSelectExpanded && boxHeight !== null && minHeight.current > 0) {
@@ -183,7 +184,7 @@
                            <View className="route-select-type">
                                <View className="route-select-title">路线选择:</View>
                                <View className="route-select-preference" onClick={() => setShowPreferencePopup(true)}>
                                    <View className="route-select-preference-text">{preference}</View>
                                    <View className="route-select-preference-text">{preference.label}</View>
                                    <Image src={selectLineIcon} />
                                </View>
                            </View>
@@ -284,9 +285,10 @@
            </View>
            <RoutePreferencePopup
                show={showPreferencePopup}
                value={preference}
                value={preference.value}
                openCityId={openCityId}
                onClose={() => setShowPreferencePopup(false)}
                onSelect={(val) => setPreference(val)}
                onSelect={(item) => setPreference(item)}
            />
        </View>
    )
src/robotaxi/pages/begin-route/components/route-preference-popup/index.tsx
@@ -4,23 +4,59 @@
import './index.less';
import closeIcon from '../../../../assets/close-icon.png';
import selectTypeLineIcon from '../../../../assets/select-type-line.png';
import { queryRoutePreferences } from '../../../../api/begin-route';
export type RoutePreferenceOption = {
  label: string;
  value: string;
};
type Props = {
  show: boolean;
  value: string;
  openCityId?: number;
  onClose: () => void;
  onSelect: (item: string) => void;
  onSelect: (item: RoutePreferenceOption) => void;
};
const OPTIONS = [
const DEFAULT_OPTIONS: RoutePreferenceOption[] = [
  { label: '智能推荐', value: '智能推荐' },
  { label: '时间优先', value: '时间优先' },
  { label: '低价优先', value: '低价优先' }
];
export default function RoutePreferencePopup({ show, value, onClose, onSelect }: Props) {
const normalizeOptions = (res: any): RoutePreferenceOption[] => {
  const list = Array.isArray(res)
    ? res
    : Array.isArray(res?.list)
      ? res.list
      : Array.isArray(res?.data)
        ? res.data
        : Array.isArray(res?.routePreferences)
          ? res.routePreferences
          : Array.isArray(res?.preferences)
            ? res.preferences
            : [];
  const normalized = list.map((item: any) => {
    const label = item?.label || item?.name || item?.displayName || item?.preferenceName || item?.value;
    const value = item?.value ?? item?.code ?? item?.preferenceCode ?? label;
    if (!label || value === undefined || value === null) {
      return null;
    }
    return {
      label: String(label),
      value: String(value)
    };
  }).filter(Boolean) as RoutePreferenceOption[];
  return normalized.length > 0 ? normalized : DEFAULT_OPTIONS;
};
export default function RoutePreferencePopup({ show, value, openCityId = 0, onClose, onSelect }: Props) {
  const [visible, setVisible] = useState(false);
  const [animationData, setAnimationData] = useState<any>();
  const [options, setOptions] = useState<RoutePreferenceOption[]>(DEFAULT_OPTIONS);
  useEffect(() => {
    if (show && !visible) {
@@ -45,6 +81,23 @@
    }
  }, [show]);
  useEffect(() => {
    if (!show) return;
    let cancelled = false;
    queryRoutePreferences({ openCityId }).then((res: any) => {
      if (cancelled) return;
      setOptions(normalizeOptions(res));
    }).catch(() => {
      if (cancelled) return;
      setOptions(DEFAULT_OPTIONS);
    });
    return () => {
      cancelled = true;
    };
  }, [show, openCityId]);
  if (!visible && !show) return null;
  return (
@@ -57,14 +110,14 @@
        </View>
        <View className='popup-list-wrap'>
            <View className='popup-list-inner'>
              {OPTIONS.map((item, index) => {
              {options.map((item, index) => {
                const isSelected = item.value === value;
                return (
                  <View 
                    key={item.value || index} 
                    className={`popup-item ${isSelected ? 'active' : ''}`} 
                    onClick={() => {
                      onSelect(item.value);
                      onSelect(item);
                      onClose();
                    }}
                  >