import CloseSvg from '@/components/CustomIcon/icons/close.svg'; import { getSubscription } from '@/services/user/portal'; import { useQuery } from '@tanstack/react-query'; import { Dialog, DialogContent, DialogTitle } from '@workspace/ui/components/dialog'; import { ScrollArea } from '@workspace/ui/components/scroll-area'; import { Tabs, TabsList, TabsTrigger } from '@workspace/ui/components/tabs'; import { unitConversion } from '@workspace/ui/utils'; import Image from 'next/image'; import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react'; import { TabContent } from './TabContent'; import { ProcessedPlanData } from './types'; // 加载状态组件 const LoadingState = () => (

加载中...

); // 错误状态组件 const ErrorState = ({ onRetry }: { onRetry: () => void }) => (

加载失败,请重试

); // 空状态组件 const EmptyState = ({ message }: { message: string }) => (

{message}

); // 价格显示组件 const PriceDisplay = ({ plan }: { plan: ProcessedPlanData }) => (
{plan.origin_price && ( ${plan.origin_price} )} ${plan.discount_price} /年
{plan.origin_price && (

年付享受8折优惠

)}
); // 订阅按钮组件 const SubscribeButton = ({ onClick }: { onClick?: () => void }) => ( ); // 星级评分组件 const StarRating = ({ rating, maxRating = 5 }: { rating: number; maxRating?: number }) => (
{Array.from({ length: Math.min(rating, maxRating) }, (_, i) => ( ))}
); // 功能列表组件 const FeatureList = ({ plan }: { plan: ProcessedPlanData }) => { const features = [ { label: '可用流量', value: plan.features?.traffic || '1' }, { label: '套餐时长', value: plan.features?.duration || '1' }, { label: '在线IP', value: plan.features?.onlineIPs || '2' }, { label: '在线连接数', value: plan.features?.connections || '3' }, { label: '峰值带宽', value: plan.features?.bandwidth || '2' }, { label: '可用节点', value: plan.features?.nodes || '11' }, ]; return (
); }; // 套餐卡片组件 const PlanCard = forwardRef< HTMLDivElement, { plan: ProcessedPlanData; tabValue: string; onSubscribe?: (plan: ProcessedPlanData) => void; isFirstCard?: boolean; } >(({ plan, onSubscribe, isFirstCard = false }, ref) => { const handleSubscribe = () => { onSubscribe?.(plan); }; return (
{/* 套餐名称 */}

{plan.name}

{/* 价格区域 */} {/* 订阅按钮 */} {/* 功能列表 */}
); }); PlanCard.displayName = 'PlanCard'; // 套餐列表组件 export const PlanList = ({ plans, tabValue, isLoading, error, onRetry, emptyMessage, onSubscribe, firstPlanCardRef, // 新增参数 }: { plans: ProcessedPlanData[]; tabValue: string; isLoading: boolean; error: any; onRetry: () => void; emptyMessage: string; onSubscribe?: (plan: ProcessedPlanData) => void; firstPlanCardRef?: React.RefObject; }) => { if (isLoading) return ; if (error) return ; if (plans.length === 0) return ; return (
{plans.map((plan, index) => ( ))}
); }; export interface OfferDialogRef { show: () => void; hide: () => void; } const OfferDialog = forwardRef((props, ref) => { const [open, setOpen] = useState(false); const [tabValue, setTabValue] = useState('year'); const [selectedPlan, setSelectedPlan] = useState(null); const [scrollAreaHeight, setScrollAreaHeight] = useState(450); const [planCardHeight, setPlanCardHeight] = useState(600); const dialogRef = useRef(null); const scrollAreaRef = useRef(null); const firstPlanCardRef = useRef(null); // 获取PlanCard高度 const getPlanCardHeight = useCallback(() => { if (firstPlanCardRef.current) { return firstPlanCardRef.current.offsetHeight; } return 600; // 默认高度 }, []); // 计算 ScrollArea 高度 const calculateScrollAreaHeight = useCallback(() => { if (dialogRef.current && scrollAreaRef.current) { const isMobile = window.innerWidth < 768; if (isMobile) { // 移动端:使用动态计算 const dialogHeight = dialogRef.current.offsetHeight; const scrollAreaTop = scrollAreaRef.current.offsetTop; const calculatedHeight = dialogHeight - scrollAreaTop; setScrollAreaHeight(calculatedHeight); } else { // PC端:使用PlanCard第一项高度 const cardHeight = getPlanCardHeight(); setScrollAreaHeight(cardHeight); } } }, [getPlanCardHeight]); // 使用 useQuery 来管理请求 const { data = [], isLoading, error, refetch, } = useQuery({ queryKey: ['subscription'], queryFn: async () => { try { const response = await getSubscription({ skipErrorHandler: true }); // 确保返回有效的数组,避免 undefined const list = response.data?.data?.list || []; return list.filter((v) => v.unit_time === 'Month') as unknown as ProcessedPlanData[]; } catch (err) { // 自定义错误处理 console.error('获取订阅数据失败:', err); // 返回空数组而不是抛出错误,避免 queryFn 返回 undefined return [] as ProcessedPlanData[]; } }, enabled: false, // 初始不执行,手动控制 retry: 1, // 失败时重试1次 }); // 监听对话框打开 useEffect(() => { if (open) { // 等待 DOM 渲染完成 const timer = setTimeout(calculateScrollAreaHeight, 0); return () => clearTimeout(timer); } }, [open, calculateScrollAreaHeight]); // 监听窗口大小变化 useEffect(() => { if (open) { refetch(); // 对话框打开时重新获取数据 const handleResize = () => { calculateScrollAreaHeight(); }; window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); } }, [open, calculateScrollAreaHeight]); useImperativeHandle(ref, () => ({ show: () => setOpen(true), hide: () => setOpen(false), })); // 处理订阅点击 const handleSubscribe = (plan: ProcessedPlanData) => { setSelectedPlan(plan); console.log('用户选择了套餐:', plan); // 这里可以添加订阅逻辑,比如跳转到支付页面或显示确认对话框 }; // 处理套餐数据的工具函数 const processPlanData = (item: ProcessedPlanData, isYearly: boolean): ProcessedPlanData => { if (isYearly) { const discountItem = item.discount?.find((v) => v.quantity === 12); return { ...item, origin_price: unitConversion('centsToDollars', item.unit_price * 12).toString(), // 原价 discount_price: unitConversion( 'centsToDollars', item.unit_price * ((discountItem?.discount || 100) / 100) * 12, ).toString(), // 优惠价格 }; } else { return { ...item, origin_price: '', // 月付没有原价 discount_price: unitConversion('centsToDollars', item.unit_price).toString(), // 月付价格 }; } }; // 使用 useMemo 优化数据处理性能 const yearlyPlans: ProcessedPlanData[] = useMemo( () => data.map((item) => processPlanData(item, true)), [data], ); const monthlyPlans: ProcessedPlanData[] = useMemo( () => data.map((item) => processPlanData(item, false)), [data], ); return ( } closeClassName={ 'right-6 top-6 font-bold text-black opacity-100 focus:ring-0 focus:ring-offset-0' } >
选择套餐
选择最适合您的服务套餐
年付套餐 月付套餐
); }); export default OfferDialog;