fix: 样式修改
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
import React from 'react';
|
||||
import { PlanList } from './index';
|
||||
import { ProcessedPlanData } from './types';
|
||||
|
||||
interface TabContentProps {
|
||||
tabValue: string;
|
||||
yearlyPlans: ProcessedPlanData[];
|
||||
monthlyPlans: ProcessedPlanData[];
|
||||
isLoading: boolean;
|
||||
error: Error | null;
|
||||
onRetry: () => void;
|
||||
onSubscribe: (plan: ProcessedPlanData) => void;
|
||||
firstPlanCardRef?: React.RefObject<HTMLDivElement | null>;
|
||||
}
|
||||
|
||||
export const TabContent: React.FC<TabContentProps> = ({
|
||||
tabValue,
|
||||
yearlyPlans,
|
||||
monthlyPlans,
|
||||
isLoading,
|
||||
error,
|
||||
onRetry,
|
||||
onSubscribe,
|
||||
firstPlanCardRef,
|
||||
}) => {
|
||||
return (
|
||||
<div>
|
||||
{tabValue === 'year' && (
|
||||
<PlanList
|
||||
plans={yearlyPlans}
|
||||
isLoading={isLoading}
|
||||
tabValue={tabValue}
|
||||
error={error}
|
||||
onRetry={onRetry}
|
||||
emptyMessage='暂无年付套餐'
|
||||
onSubscribe={onSubscribe}
|
||||
firstPlanCardRef={firstPlanCardRef}
|
||||
/>
|
||||
)}
|
||||
{tabValue === 'month' && (
|
||||
<PlanList
|
||||
plans={monthlyPlans}
|
||||
tabValue={tabValue}
|
||||
isLoading={isLoading}
|
||||
error={error}
|
||||
onRetry={onRetry}
|
||||
emptyMessage='暂无月付套餐'
|
||||
onSubscribe={onSubscribe}
|
||||
firstPlanCardRef={firstPlanCardRef}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -16,34 +16,8 @@ import {
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
// 定义数据类型
|
||||
interface SubscriptionData {
|
||||
id: string;
|
||||
name: string;
|
||||
price: number;
|
||||
originalPrice: number;
|
||||
duration: string;
|
||||
unit_price: number;
|
||||
discount: Array<{
|
||||
quantity: number;
|
||||
discount: number;
|
||||
}>;
|
||||
features: {
|
||||
traffic: string;
|
||||
duration: string;
|
||||
onlineIPs: string;
|
||||
connections: string;
|
||||
bandwidth: string;
|
||||
nodes: string;
|
||||
stability: number; // 星级 1-5
|
||||
};
|
||||
}
|
||||
|
||||
// 处理后的套餐数据类型
|
||||
interface ProcessedPlanData extends SubscriptionData {
|
||||
origin_price: string;
|
||||
discount_price: string;
|
||||
}
|
||||
import { TabContent } from './TabContent';
|
||||
import { ProcessedPlanData } from './types';
|
||||
|
||||
// 加载状态组件
|
||||
const LoadingState = () => (
|
||||
@@ -150,33 +124,22 @@ const FeatureList = ({ plan }: { plan: ProcessedPlanData }) => {
|
||||
};
|
||||
|
||||
// 套餐卡片组件
|
||||
const PlanCard = ({
|
||||
plan,
|
||||
onSubscribe,
|
||||
isFirstCard = false, // 新增参数标识是否为第一项
|
||||
}: {
|
||||
plan: ProcessedPlanData;
|
||||
tabValue: string;
|
||||
onSubscribe?: (plan: ProcessedPlanData) => void;
|
||||
isFirstCard?: boolean;
|
||||
}) => {
|
||||
const cardRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// 如果是第一项,将ref传递给父组件
|
||||
useEffect(() => {
|
||||
if (isFirstCard && cardRef.current) {
|
||||
// 可以通过回调函数将高度传递给父组件
|
||||
// 或者使用ref转发
|
||||
}
|
||||
}, [isFirstCard]);
|
||||
|
||||
const PlanCard = forwardRef<
|
||||
HTMLDivElement,
|
||||
{
|
||||
plan: ProcessedPlanData;
|
||||
tabValue: string;
|
||||
onSubscribe?: (plan: ProcessedPlanData) => void;
|
||||
isFirstCard?: boolean;
|
||||
}
|
||||
>(({ plan, onSubscribe, isFirstCard = false }, ref) => {
|
||||
const handleSubscribe = () => {
|
||||
onSubscribe?.(plan);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={isFirstCard ? cardRef : undefined}
|
||||
ref={ref}
|
||||
className='relative w-full max-w-[345px] cursor-pointer rounded-[20px] border border-[#D9D9D9] bg-white p-4 transition-all duration-300 hover:shadow-lg sm:p-6 md:p-8'
|
||||
>
|
||||
{/* 套餐名称 */}
|
||||
@@ -192,10 +155,12 @@ const PlanCard = ({
|
||||
<FeatureList plan={plan} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
PlanCard.displayName = 'PlanCard';
|
||||
|
||||
// 套餐列表组件
|
||||
const PlanList = ({
|
||||
export const PlanList = ({
|
||||
plans,
|
||||
tabValue,
|
||||
isLoading,
|
||||
@@ -212,7 +177,7 @@ const PlanList = ({
|
||||
onRetry: () => void;
|
||||
emptyMessage: string;
|
||||
onSubscribe?: (plan: ProcessedPlanData) => void;
|
||||
firstPlanCardRef?: React.RefObject<HTMLDivElement>;
|
||||
firstPlanCardRef?: React.RefObject<HTMLDivElement | null>;
|
||||
}) => {
|
||||
if (isLoading) return <LoadingState />;
|
||||
if (error) return <ErrorState onRetry={onRetry} />;
|
||||
@@ -289,12 +254,12 @@ const OfferDialog = forwardRef<OfferDialogRef>((props, ref) => {
|
||||
const response = await getSubscription({ skipErrorHandler: true });
|
||||
// 确保返回有效的数组,避免 undefined
|
||||
const list = response.data?.data?.list || [];
|
||||
return list.filter((v) => v.unit_time === 'Month') as unknown as SubscriptionData[];
|
||||
return list.filter((v) => v.unit_time === 'Month') as unknown as ProcessedPlanData[];
|
||||
} catch (err) {
|
||||
// 自定义错误处理
|
||||
console.error('获取订阅数据失败:', err);
|
||||
// 返回空数组而不是抛出错误,避免 queryFn 返回 undefined
|
||||
return [] as SubscriptionData[];
|
||||
return [] as ProcessedPlanData[];
|
||||
}
|
||||
},
|
||||
enabled: false, // 初始不执行,手动控制
|
||||
@@ -336,7 +301,7 @@ const OfferDialog = forwardRef<OfferDialogRef>((props, ref) => {
|
||||
};
|
||||
|
||||
// 处理套餐数据的工具函数
|
||||
const processPlanData = (item: SubscriptionData, isYearly: boolean): ProcessedPlanData => {
|
||||
const processPlanData = (item: ProcessedPlanData, isYearly: boolean): ProcessedPlanData => {
|
||||
if (isYearly) {
|
||||
const discountItem = item.discount?.find((v) => v.quantity === 12);
|
||||
return {
|
||||
@@ -377,14 +342,13 @@ const OfferDialog = forwardRef<OfferDialogRef>((props, ref) => {
|
||||
'right-6 top-6 font-bold text-black opacity-100 focus:ring-0 focus:ring-offset-0'
|
||||
}
|
||||
>
|
||||
<DialogTitle className={''}>
|
||||
<div className={'text-4xl font-bold text-[#0F2C53] md:mb-4 md:text-center md:text-5xl'}>
|
||||
选择套餐
|
||||
</div>
|
||||
<div className={'text-lg font-medium text-[#666666] md:text-center'}>
|
||||
选择最适合您的服务套餐
|
||||
</div>
|
||||
</DialogTitle>
|
||||
<DialogTitle className={'sr-only'}></DialogTitle>
|
||||
<div className={'text-4xl font-bold text-[#0F2C53] md:mb-4 md:text-center md:text-5xl'}>
|
||||
选择套餐
|
||||
</div>
|
||||
<div className={'text-lg font-medium text-[#666666] md:text-center'}>
|
||||
选择最适合您的服务套餐
|
||||
</div>
|
||||
<div>
|
||||
<Tabs
|
||||
defaultValue='year'
|
||||
@@ -416,32 +380,16 @@ const OfferDialog = forwardRef<OfferDialogRef>((props, ref) => {
|
||||
className='overflow-y-auto'
|
||||
style={{ height: `calc(${scrollAreaHeight}px - 32px)` }}
|
||||
>
|
||||
<div>
|
||||
{tabValue === 'year' && (
|
||||
<PlanList
|
||||
plans={yearlyPlans}
|
||||
isLoading={isLoading}
|
||||
tabValue={tabValue}
|
||||
error={error}
|
||||
onRetry={refetch}
|
||||
emptyMessage='暂无年付套餐'
|
||||
onSubscribe={handleSubscribe}
|
||||
firstPlanCardRef={firstPlanCardRef} // 传递ref给第一项
|
||||
/>
|
||||
)}
|
||||
{tabValue === 'month' && (
|
||||
<PlanList
|
||||
plans={monthlyPlans}
|
||||
tabValue={tabValue}
|
||||
isLoading={isLoading}
|
||||
error={error}
|
||||
onRetry={refetch}
|
||||
emptyMessage='暂无月付套餐'
|
||||
onSubscribe={handleSubscribe}
|
||||
firstPlanCardRef={firstPlanCardRef} // 传递ref给第一项
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<TabContent
|
||||
tabValue={tabValue}
|
||||
yearlyPlans={yearlyPlans}
|
||||
monthlyPlans={monthlyPlans}
|
||||
isLoading={isLoading}
|
||||
error={error}
|
||||
onRetry={refetch}
|
||||
onSubscribe={handleSubscribe}
|
||||
firstPlanCardRef={firstPlanCardRef}
|
||||
/>
|
||||
</ScrollArea>
|
||||
</div>
|
||||
</DialogContent>
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
export interface SubscriptionData {
|
||||
id: string;
|
||||
name: string;
|
||||
price: number;
|
||||
originalPrice: number;
|
||||
duration: string;
|
||||
unit_price: number;
|
||||
discount: Array<{
|
||||
quantity: number;
|
||||
discount: number;
|
||||
}>;
|
||||
features: {
|
||||
traffic: string;
|
||||
duration: string;
|
||||
onlineIPs: string;
|
||||
connections: string;
|
||||
bandwidth: string;
|
||||
nodes: string;
|
||||
stability: number; // 星级 1-5
|
||||
};
|
||||
}
|
||||
|
||||
export interface ProcessedPlanData extends SubscriptionData {
|
||||
origin_price: string;
|
||||
discount_price: string;
|
||||
}
|
||||
Reference in New Issue
Block a user