diff --git a/apps/user/.env.template b/apps/user/.env.template index 8b81c94..8659c35 100644 --- a/apps/user/.env.template +++ b/apps/user/.env.template @@ -3,7 +3,7 @@ NEXT_PUBLIC_DEFAULT_LANGUAGE=en-US # Site URL and API URL NEXT_PUBLIC_SITE_URL=https://user.ppanel.dev -NEXT_PUBLIC_API_URL=https://api.ppanel.dev +NEXT_PUBLIC_API_URL=https://api.kxsw.us NEXT_PUBLIC_CDN_URL=https://cdn.jsdelivr.net # Home Page Settings diff --git a/apps/user/components/main/OfferDialog/index.tsx b/apps/user/components/main/OfferDialog/index.tsx index f5fb3d6..7cba533 100644 --- a/apps/user/components/main/OfferDialog/index.tsx +++ b/apps/user/components/main/OfferDialog/index.tsx @@ -2,10 +2,11 @@ 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 { Tabs, TabsContent, TabsList, TabsTrigger } from '@workspace/ui/components/tabs'; +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, useEffect, useImperativeHandle, useState } from 'react'; - // 定义数据类型 interface SubscriptionData { id: string; @@ -24,15 +25,27 @@ interface SubscriptionData { }; } +// 计算折扣价格的函数 +const calculateDiscountPrice = (unitPrice: number, discountPercent: number) => { + // 折扣百分比转换为小数 (80 -> 0.8) + const discountRate = discountPercent / 100; + // 计算折扣后的价格 + const discountedPrice = unitPrice * discountRate; + // 使用 unitConversion 避免浮点数精度问题 + return unitConversion('dollarsToCents', discountedPrice); +}; + +// 计算原价(未折扣价格) +const calculateOriginalPrice = (unitPrice: number, discountPercent: number) => { + // 原价就是 unitPrice + return unitConversion('dollarsToCents', unitPrice); +}; + // 套餐卡片组件 -const PlanCard = ({ plan, isSelected }: { plan: SubscriptionData; isSelected?: boolean }) => { +const PlanCard = ({ plan }: { plan: SubscriptionData }) => { return (
{/* 套餐名称 */}

{plan.name}

@@ -40,14 +53,16 @@ const PlanCard = ({ plan, isSelected }: { plan: SubscriptionData; isSelected?: b {/* 价格区域 */}
- - ¥{plan.originalPrice} - + {plan.origin_price && ( + + ${plan.origin_price} + + )} - ${plan.price} + ${plan.discount_price} - /月 + /年

年付享受8折优惠

@@ -67,7 +82,7 @@ const PlanCard = ({ plan, isSelected }: { plan: SubscriptionData; isSelected?: b 可用流量: - {plan.features.traffic} + 1
@@ -75,7 +90,7 @@ const PlanCard = ({ plan, isSelected }: { plan: SubscriptionData; isSelected?: b 套餐时长: - {plan.features.duration} + 1
@@ -83,7 +98,7 @@ const PlanCard = ({ plan, isSelected }: { plan: SubscriptionData; isSelected?: b 在线IP: - {plan.features.onlineIPs} + 2
@@ -91,7 +106,7 @@ const PlanCard = ({ plan, isSelected }: { plan: SubscriptionData; isSelected?: b 在线连接数: - {plan.features.connections} + 3
@@ -99,7 +114,7 @@ const PlanCard = ({ plan, isSelected }: { plan: SubscriptionData; isSelected?: b 峰值带宽: - {plan.features.bandwidth} + 2
@@ -107,7 +122,7 @@ const PlanCard = ({ plan, isSelected }: { plan: SubscriptionData; isSelected?: b 可用节点: - {plan.features.nodes} + 11
@@ -115,7 +130,7 @@ const PlanCard = ({ plan, isSelected }: { plan: SubscriptionData; isSelected?: b 网络稳定指数:
- {Array.from({ length: plan.features.stability }, (_, i) => ( + {Array.from({ length: 4 }, (_, i) => ( @@ -136,14 +151,19 @@ const OfferDialog = forwardRef((props, ref) => { const [open, setOpen] = useState(false); // 使用 useQuery 来管理请求 - const { data, isLoading, error, refetch } = 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 as unknown as SubscriptionData[]; + return list.filter((v) => v.unit_time === 'Month') as unknown as SubscriptionData[]; } catch (err) { // 自定义错误处理 console.error('获取订阅数据失败:', err); @@ -167,73 +187,27 @@ const OfferDialog = forwardRef((props, ref) => { hide: () => setOpen(false), })); - // 处理数据 - const processedData = - data?.map((item) => ({ - ...item, - displayPrice: `¥${item.price}`, - displayDuration: item.duration === 'year' ? '年付' : '月付', - })) || []; - - // 如果没有数据,使用模拟数据 - const mockData: SubscriptionData[] = [ - { - id: '1', - name: 'Basic Plan', - price: 8, - originalPrice: 10, - duration: 'year', - features: { - traffic: '140G', - duration: '30天', - onlineIPs: '3个', - connections: '300', - bandwidth: '200Mbps', - nodes: '15个', - stability: 3, - }, - }, - { - id: '2', - name: 'Standard Plan', - price: 24, - originalPrice: 30, - duration: 'year', - features: { - traffic: '160G', - duration: '30天', - onlineIPs: '3个', - connections: '300', - bandwidth: '300Mbps', - nodes: '15个', - stability: 4, - }, - }, - { - id: '3', - name: 'Pro Plan', - price: 48, - originalPrice: 60, - duration: 'year', - features: { - traffic: '180G', - duration: '30天', - onlineIPs: '3个', - connections: '300', - bandwidth: '500Mbps', - nodes: '29个', - stability: 5, - }, - }, - ]; - - // 使用真实数据或模拟数据 - const displayData = mockData; - // 按类型分组数据 - const yearlyPlans = displayData.filter((item) => item.duration === 'year'); - const monthlyPlans = displayData.filter((item) => item.duration === 'month'); - console.log(processedData); + const yearlyPlans = data.map((item) => { + const discountItem = item.discount.find((v) => v.quantity === 12); + return { + ...item, + origin_price: unitConversion('centsToDollars', item.unit_price * 12), // 原价 + discount_price: unitConversion( + 'centsToDollars', + item.unit_price * (discountItem.discount / 100) * 12, + ), // 优惠价格 + }; + }); + const monthlyPlans = data.map((item) => { + return { + ...item, + origin_price: '', // 原价 + discount_price: unitConversion('centsToDollars', item.unit_price), // 优惠价格 + }; + }); + const [tabValue, setTabValue] = useState('year'); + return ( ((props, ref) => { 'right-6 top-6 font-bold text-black opacity-100 focus:ring-0 focus:ring-offset-0' } > - - 选择套餐 - -
+ +
+ 选择套餐 +
选择最适合您的服务套餐
+
+
- + ((props, ref) => { 月付套餐 - - + +
+ + {tabValue === 'year' && ( +
{isLoading ? (
@@ -290,9 +274,9 @@ const OfferDialog = forwardRef((props, ref) => {
) : yearlyPlans.length > 0 ? ( -
+
{/* 卡片容器 */} -
+
{yearlyPlans.map((plan, index) => ( ))} @@ -303,9 +287,10 @@ const OfferDialog = forwardRef((props, ref) => {

暂无年付套餐

)} - - - +
+ )} + {tabValue === 'month' && ( +
{isLoading ? (
@@ -323,9 +308,6 @@ const OfferDialog = forwardRef((props, ref) => {
) : monthlyPlans.length > 0 ? (
- {/* 连接线 */} -
- {/* 卡片容器 */}
{monthlyPlans.map((plan, index) => ( @@ -338,9 +320,9 @@ const OfferDialog = forwardRef((props, ref) => {

暂无月付套餐

)} - - -
+
+ )} +