hejianhao
2026-06-02 9fd4436cdb7eb024c415c89992220d4f5f5ebcad
refactor(robotaxi): 迁移页面白名单校验至HOC封装

新增withRobotaxiWhitelist高阶组件统一处理页面的白名单权限校验,为所有相关页面添加该包装并移除全局应用层的白名单校验逻辑,改为在页面显示时自动触发校验。
22个文件已修改
145 ■■■■■ 已修改文件
src/app.tsx 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/robotaxi/home/index.tsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/agreement-page/index.tsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/index.tsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/coupon/index.tsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/demo/index.tsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/expense-description/index.tsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/expense-detail/index.tsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/operating-area/index.tsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/order/detail/index.tsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/order/index.tsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/passenger-notice/index.tsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/payment-setting-detail/index.tsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/payment-setting/index.tsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/personal-center/index.tsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/pricing-rules/index.tsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/ride-guide/index.tsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/select-city/index.tsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/select-map-site/index.tsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/share-trip/index.tsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/site-search/index.tsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/whitelist.ts 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/app.tsx
@@ -23,7 +23,6 @@
import { privicyShowManager } from './components/privacy-popup/utils';
import { initPrivacyPopupState } from './reducers/privacyPopup';
import { preloadLoginBgImageOnWx } from './utils/login-bg-utils';
import { checkWhitelistAccess, redirectToWhitelistBlockPage } from './utils/whitelist';
const store = configStore();
const ENV = process.env.TARO_ENV;
@@ -110,11 +109,6 @@
      return;
    }
    const whitelistAccessResult = await this.handleWhitelistGuard();
    if (whitelistAccessResult === 'deny') {
      return;
    }
    const { hasLogin } = router.query || {};
    // 预加载登录背景图
@@ -131,17 +125,6 @@
        .catch(console.error);
    }
  }
  /**
   * 执行全局白名单守卫。
   */
  handleWhitelistGuard = async () => {
    const whitelistAccessResult = await checkWhitelistAccess();
    if (whitelistAccessResult === 'deny') {
      await redirectToWhitelistBlockPage();
    }
    return whitelistAccessResult;
  }
  componentDidHide() {
src/pages/robotaxi/home/index.tsx
@@ -39,6 +39,7 @@
import { subscribeOperationCouponGroup } from '../../../utils/subscribe';
import { checkOtp, toH5 } from '../../../utils/tools';
import { getCityLocation, reportEvent } from '../../../utils/Robotaxi-public-method';
import { withRobotaxiWhitelist } from '../../../utils/whitelist';
import {
  HOME_MAP_ID,
  HOME_ORDER_STATUS,
@@ -76,7 +77,7 @@
/**
 * Robotaxi 首页页面容器:仅负责组合领域 hook 与布局组件。
 */
export default function Home() {
function Home() {
  const [showPrivacy, setShowPrivacy] = useState(false); // 隐私协议弹窗是否显示
  const [showCustomerService, setShowCustomerService] = useState(false); // 客服弹窗是否显示
  const [tripStatus, setTripStatus] = useState<HomeTripStatus>(0); // 当前行程状态
@@ -586,3 +587,5 @@
    </View>
  );
}
export default withRobotaxiWhitelist(Home);
src/robotaxi/pages/agreement-page/index.tsx
@@ -3,8 +3,9 @@
import { View, Image } from '@tarojs/components';
import './index.less';
import { getNormalizedLoginAgreementList, type LoginAgreementItem } from '../../utils/login-agreement';
import { withRobotaxiWhitelist } from '../../../utils/whitelist';
export default function AgreementPage() {
function AgreementPage() {
  const [agreementList, setAgreementList] = useState<LoginAgreementItem[]>([]);
  useEffect(() => {
@@ -37,3 +38,5 @@
    </View>
  )
}
export default withRobotaxiWhitelist(AgreementPage);
src/robotaxi/pages/begin-route/index.tsx
@@ -78,6 +78,7 @@
  createWaitingForPickupReportPayload,
  resetConfirmRideSelectionContext
} from './constants/confirm-ride-report';
import { withRobotaxiWhitelist } from '../../../utils/whitelist';
const ROUTE_SUMMARY_MARKER_ID = 999001;
const MODIFY_DESTINATION_PICKUP_STATUS_GUARD_MS = 5000;
@@ -137,7 +138,7 @@
  reportEvent(params.eventId, createConfirmRideEventPayload(params));
}
export default function BeginRoute() {
function BeginRoute() {
  const WAITING_TIMER_START_KEY = 'waitingTimerStartAt'; // 等待计时开始时间
  const WAITING_TIMER_ELAPSED_KEY = 'waitingTimerElapsed'; // 等待计时已过秒数
  const DEFAULT_QUEUE_POLLING_TIME = 10; // 排队位次默认轮询秒数
@@ -1587,3 +1588,5 @@
    </>
  )
}
export default withRobotaxiWhitelist(BeginRoute);
src/robotaxi/pages/coupon/index.tsx
@@ -9,8 +9,9 @@
  CouponItem,
  CouponDetail
} from "../../../robotaxi/api/coupon";
import { withRobotaxiWhitelist } from "../../../utils/whitelist";
export default function CouponPage() {
function CouponPage() {
  const [couponStatus] = useState([
    // { label: '全部', value: '' },
    // { label: "可领取", value: 0 },
@@ -295,3 +296,5 @@
    </View>
  );
}
export default withRobotaxiWhitelist(CouponPage);
src/robotaxi/pages/demo/index.tsx
@@ -6,9 +6,11 @@
import DemoCom from '../../components/demo';
import { checkOtp } from '../../../utils/tools';
import { withRobotaxiWhitelist } from '../../../utils/whitelist';
// @ts-ignore
@createPage()
export default class Toolbox extends Component {
class ToolboxBase extends Component {
  $app: any = Taro.getApp().$app;
  componentDidShow() {
@@ -40,3 +42,5 @@
    )
  }
}
export default withRobotaxiWhitelist(ToolboxBase as any);
src/robotaxi/pages/expense-description/index.tsx
@@ -7,9 +7,10 @@
  formatTripDurationFromSeconds
} from '../../../utils/Robotaxi-public-method';
import EvaluatePopup from '../begin-route/components/evaluate-popup';
import { withRobotaxiWhitelist } from '../../../utils/whitelist';
import './index.less';
export default function OrderPage() {
function OrderPage() {
  const router = useRouter();
  const [showAllFaq, setShowAllFaq] = useState(false); // 是否显示全部FAQ
  const [expandedItems, setExpandedItems] = useState<string[]>([]);
@@ -271,3 +272,5 @@
    </View>
  )
}
export default withRobotaxiWhitelist(OrderPage);
src/robotaxi/pages/expense-detail/index.tsx
@@ -6,6 +6,7 @@
  formatTripDistance,
  formatTripDurationFromSeconds
} from '../../../utils/Robotaxi-public-method';
import { withRobotaxiWhitelist } from '../../../utils/whitelist';
/** 城市缓存 key */
const SELECTED_CITY_STORAGE_KEY = 'selectedCity';
@@ -31,7 +32,7 @@
  }
}
export default function OrderPage() {
function OrderPage() {
  const [pricingCard, setPricingCard] = useState<any>(null);
  const [startSite, setStartSite] = useState<any>(null);
  const [endSite, setEndSite] = useState<any>(null);
@@ -168,8 +169,8 @@
        <Text className='look-rule-txt'>查看计价规则</Text>
        <Image className='arrow-icon' src="https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/Subtract.png"></Image>
      </View>
    </View>
  )
}
export default withRobotaxiWhitelist(OrderPage);
src/robotaxi/pages/operating-area/index.tsx
@@ -6,8 +6,9 @@
import { getOpenCity } from '../../api/select-city';
import { getGeofence } from '../../api/home';
import { extractPointsFromPolygons, findMatchedPolygon, getDistance } from '../../../utils/Robotaxi-public-method';
import { withRobotaxiWhitelist } from '../../../utils/whitelist';
export default function OperatingArea() {
function OperatingArea() {
  const [longitude, setLongitude] = useState<number | null>(null);
  const [latitude, setLatitude] = useState<number | null>(null);
  const [polygons, setPolygons] = useState<any[]>([]);
@@ -357,3 +358,5 @@
    </View>
  );
}
export default withRobotaxiWhitelist(OperatingArea);
src/robotaxi/pages/order/detail/index.tsx
@@ -7,8 +7,9 @@
import { submitOrderComment } from '../../../api/begin-route';
import { formatTripDistance, formatTripDurationFromSeconds, safeParse } from '../../../../utils/Robotaxi-public-method';
import { getOrderId } from '../../../utils/order';
import { withRobotaxiWhitelist } from '../../../../utils/whitelist';
export default function orderDetailPage() {
function OrderDetailPage() {
  const router = useRouter();
  const { orderId } = router.params;
@@ -351,3 +352,5 @@
    </View>
  )
}
export default withRobotaxiWhitelist(OrderDetailPage);
src/robotaxi/pages/order/index.tsx
@@ -23,7 +23,9 @@
const XP_INVOICE_APP_ID = 'xp_invoice';
export default function OrderPage() {
import { withRobotaxiWhitelist } from '../../../utils/whitelist';
function OrderPage() {
  const router = useRouter();
  const { filter } = router.params as { filter: OrderFilterKey };
  const [groups, setGroups] = useState<OrderHistoryGroup[]>([])
@@ -221,3 +223,5 @@
    </View>
  )
}
export default withRobotaxiWhitelist(OrderPage);
src/robotaxi/pages/passenger-notice/index.tsx
@@ -3,6 +3,7 @@
import { useEffect, useState } from 'react';
import './index.less'
import { getLoginAgreementContentInfo, getPrivacyContent } from '../../api/home';
import { withRobotaxiWhitelist } from '../../../utils/whitelist';
type AgreementItem = {
  id: number | string;
@@ -11,7 +12,7 @@
  version?: string | number;
};
export default function PassengerNotice() {
function PassengerNotice() {
  const [content, setContent] = useState('');
  const [title, setTitle] = useState('乘车须知');
  const RIDE_NOTICE_TYPE = 5; // 乘车须知协议类型
@@ -62,3 +63,5 @@
    </View>
  )
}
export default withRobotaxiWhitelist(PassengerNotice);
src/robotaxi/pages/payment-setting-detail/index.tsx
@@ -2,10 +2,11 @@
import { View, Text, Image } from '@tarojs/components';
import { useCallback, useState } from 'react';
import { getPayPwd, RobotaxiPaySettingStatus, setPayPwd } from '../../api/payment';
import { withRobotaxiWhitelist } from '../../../utils/whitelist';
import './index.less';
export default function PaymentSettingDetail() {
function PaymentSettingDetail() {
  const [isPayEnabled, setIsPayEnabled] = useState(true); // 当前免密支付状态
  const [isOperating, setIsOperating] = useState(false); // 当前是否正在关闭
@@ -107,3 +108,5 @@
    </View>
  );
}
export default withRobotaxiWhitelist(PaymentSettingDetail);
src/robotaxi/pages/payment-setting/index.tsx
@@ -2,6 +2,7 @@
import { View, Text, Image } from '@tarojs/components';
import { useCallback, useEffect, useRef, useState } from 'react';
import { getPayPwd, RobotaxiPaySettingStatus, setPayPwd } from '../../api/payment';
import { withRobotaxiWhitelist } from '../../../utils/whitelist';
import './index.less';
@@ -17,7 +18,7 @@
/** AppShow 监听函数类型。 */
type AppShowHandler = (payload: any) => void;
export default function PaymentSetting() {
function PaymentSetting() {
  const [isPayEnabled, setIsPayEnabled] = useState(false); // 当前是否已开通支付分
  const [isOperating, setIsOperating] = useState(false); // 当前是否正在执行操作
  const appShowListenerRef = useRef<AppShowHandler | null>(null); // 支付分回跳监听器
@@ -210,3 +211,5 @@
    </View>
  );
}
export default withRobotaxiWhitelist(PaymentSetting);
src/robotaxi/pages/personal-center/index.tsx
@@ -37,7 +37,9 @@
  { key: "favorite", label: "收藏站点" }
];
export default function PersonalCenter() {
import { withRobotaxiWhitelist } from '../../../utils/whitelist';
function PersonalCenter() {
  const nickname = useSelector((state: any) => state.user?.userInfo?.nickName) || "小鹏艺术家";
  const [showFavoritePopup, setShowFavoritePopup] = useState(false);
@@ -195,3 +197,5 @@
    </View>
  );
}
export default withRobotaxiWhitelist(PersonalCenter);
src/robotaxi/pages/pricing-rules/index.tsx
@@ -2,6 +2,7 @@
import { useState, useEffect } from 'react';
import { View, Text } from '@tarojs/components';
import { getPricingRules } from '../../api/pricing';
import { withRobotaxiWhitelist } from '../../../utils/whitelist';
import './index.less';
type AnyRecord = Record<string, any>;
@@ -60,7 +61,7 @@
  return val !== null && val !== undefined && val !== '';
}
export default function PricingRulesPage() {
function PricingRulesPage() {
  const [loading, setLoading] = useState(true);
  const [mockJson, setMockJson] = useState<AnyRecord>({});
@@ -433,3 +434,5 @@
  );
}
export default withRobotaxiWhitelist(PricingRulesPage);
src/robotaxi/pages/ride-guide/index.tsx
@@ -2,6 +2,7 @@
import { useEffect, useState } from 'react';
import './index.less'
import { getRideGuideList } from '../../api/home';
import { withRobotaxiWhitelist } from '../../../utils/whitelist';
/** 默认图片地址 */
const DEFAULT_IMAGE_URL = '';
@@ -20,7 +21,7 @@
  }
}
export default function PassengerNotice() {
function PassengerNotice() {
  const [content, setContent] = useState('');
  useEffect(() => {
@@ -36,3 +37,5 @@
    </View>
  )
}
export default withRobotaxiWhitelist(PassengerNotice);
src/robotaxi/pages/select-city/index.tsx
@@ -3,10 +3,11 @@
import { View, Image, Input, ScrollView } from '@tarojs/components';
import './index.less';
import { getOpenCity, getCityList } from '../../api/select-city';
import { withRobotaxiWhitelist } from '../../../utils/whitelist';
export default function SelectCityPage() {
function SelectCityPage() {
  const [scrollIntoView, setScrollIntoView] = useState(''); // 滚动到的城市字母
  const [searchValue, setSearchValue] = useState(''); // 搜索值
  const [selectedCity, setSelectedCity] = useState<any>({}); // 选中的城市
@@ -293,3 +294,5 @@
    </View>
  )
}
export default withRobotaxiWhitelist(SelectCityPage);
src/robotaxi/pages/select-map-site/index.tsx
@@ -7,11 +7,12 @@
  MAP_SELECT_DROPOFF_PAGE_VIEW_EVENT_ID,
  PIN_PICKUP_LOCATION_PAGE_VIEW_EVENT_ID
} from '../begin-route/constants/report-events';
import { withRobotaxiWhitelist } from '../../../utils/whitelist';
/**
 * 地图选点页入口:负责 hook 编排与视图组装。
 */
export default function SelectMapSite() {
function SelectMapSite() {
  const selectMapSite = useSelectMapSite();
  const hasReportedPickupPageViewRef = useRef(false);
  const hasReportedDropoffPageViewRef = useRef(false);
@@ -77,3 +78,5 @@
    />
  );
}
export default withRobotaxiWhitelist(SelectMapSite);
src/robotaxi/pages/share-trip/index.tsx
@@ -14,6 +14,7 @@
import { checkOtp } from '../../../utils/tools';
import { jumpToHome } from '../../../utils/jump';
import { safeMakePhoneCall } from '../../../utils/Robotaxi-public-method';
import { withRobotaxiWhitelist } from '../../../utils/whitelist';
type StatusRule = {
  showPickup: boolean;
@@ -25,7 +26,7 @@
  translateCar: boolean;
};
export default function ShareTrip() {
function ShareTrip() {
  const router = useRouter();
  const { orderId = '' } = router.params || {}; // 分享订单 ID
  const [tripData, setTripData] = useState<any>(null); // 行程详情数据
@@ -226,3 +227,5 @@
    />
  );
}
export default withRobotaxiWhitelist(ShareTrip);
src/robotaxi/pages/site-search/index.tsx
@@ -49,6 +49,7 @@
  completeConfirmRideSelectionSession,
  writeConfirmRideSiteSourceType
} from '../begin-route/constants/confirm-ride-report';
import { withRobotaxiWhitelist } from '../../../utils/whitelist';
/**
 * 安全解析路由关键字,兼容已编码和未编码两种入参。
@@ -65,7 +66,7 @@
  }
};
export default function SiteSearchPage() {
function SiteSearchPage() {
  const [searchValue, setSearchValue] = useState('') //搜索值
  const [showAllHistory, setShowAllHistory] = useState(false) // 是否展示全部历史记录
  const [showAllRecommend, setShowAllRecommend] = useState(false) // 是否展示全部推荐站点
@@ -642,3 +643,5 @@
    </View>
  )
}
export default withRobotaxiWhitelist(SiteSearchPage);
src/utils/whitelist.ts
@@ -1,6 +1,8 @@
import Taro from '@tarojs/taro';
import Taro, { useDidShow } from '@tarojs/taro';
import { isWhiteList } from '../robotaxi/api/home';
import { checkOtp } from './tools';
import React, { ComponentType } from 'react';
/** 白名单拦截页路由。 */
export const WHITELIST_BLOCK_PAGE_URL = '/pages/not-on-whitelist/index';
@@ -132,3 +134,22 @@
  }
  return whitelistAccessResult;
}
/**
 * Robotaxi 页面专用白名单拦截高阶组件 (HOC)。
 * 包装页面组件,在页面的 useDidShow 阶段自动检查。
 */
export function withRobotaxiWhitelist<P extends object>(WrappedComponent: ComponentType<P>): ComponentType<P> {
  return function WithRobotaxiWhitelist(props: P) {
    useDidShow(() => {
      checkWhitelistAccess().then((whitelistAccessResult) => {
        if (whitelistAccessResult === 'deny') {
          redirectToWhitelistBlockPage();
        }
      });
    });
    return React.createElement(WrappedComponent, props);
  };
}