|
|
@@ -4,67 +4,31 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/cli
|
|
|
import { Badge } from '@/client/components/ui/badge';
|
|
|
import { Check, Star } from 'lucide-react';
|
|
|
import { useNavigate } from 'react-router-dom';
|
|
|
+import { useQuery } from '@tanstack/react-query';
|
|
|
+import { membershipPlanClient } from '@/client/api';
|
|
|
|
|
|
export default function PricingPage() {
|
|
|
const navigate = useNavigate();
|
|
|
- const [selectedPlan, setSelectedPlan] = useState<string>('standard');
|
|
|
-
|
|
|
- const plans = [
|
|
|
- {
|
|
|
- id: 'basic',
|
|
|
- name: '基础版',
|
|
|
- price: '9.9',
|
|
|
- period: '/月',
|
|
|
- description: '适合个人用户和小型团队',
|
|
|
- features: [
|
|
|
- '每月100份文档处理',
|
|
|
- '基础模板支持',
|
|
|
- '标准图片压缩',
|
|
|
- '邮件技术支持',
|
|
|
- '5天数据保留'
|
|
|
- ],
|
|
|
- popular: false,
|
|
|
- color: 'border-gray-200'
|
|
|
- },
|
|
|
- {
|
|
|
- id: 'standard',
|
|
|
- name: '标准版',
|
|
|
- price: '29.9',
|
|
|
- period: '/月',
|
|
|
- description: '适合中小企业和团队使用',
|
|
|
- features: [
|
|
|
- '每月500份文档处理',
|
|
|
- '高级模板库',
|
|
|
- '智能图片处理',
|
|
|
- '批量压缩打包',
|
|
|
- '优先技术支持',
|
|
|
- '30天数据保留',
|
|
|
- 'API接口调用'
|
|
|
- ],
|
|
|
- popular: true,
|
|
|
- color: 'border-blue-500'
|
|
|
+
|
|
|
+ const { data: membershipPlans } = useQuery({
|
|
|
+ queryKey: ['membership-plans-pricing'],
|
|
|
+ queryFn: async () => {
|
|
|
+ const response = await membershipPlanClient.$get();
|
|
|
+ if (!response.ok) throw new Error('获取套餐失败');
|
|
|
+ const data = await response.json();
|
|
|
+ return data.data.filter((plan: any) => plan.isActive === 1).sort((a: any, b: any) => a.sortOrder - b.sortOrder);
|
|
|
},
|
|
|
- {
|
|
|
- id: 'professional',
|
|
|
- name: '专业版',
|
|
|
- price: '99.9',
|
|
|
- period: '/月',
|
|
|
- description: '适合大型企业和专业用户',
|
|
|
- features: [
|
|
|
- '无限文档处理',
|
|
|
- '全部模板库',
|
|
|
- 'AI智能优化',
|
|
|
- '自定义模板制作',
|
|
|
- '专属技术支持',
|
|
|
- '永久数据保留',
|
|
|
- 'API无限制调用',
|
|
|
- '团队协作功能',
|
|
|
- '数据统计分析'
|
|
|
- ],
|
|
|
- popular: false,
|
|
|
- color: 'border-purple-500'
|
|
|
- }
|
|
|
- ];
|
|
|
+ });
|
|
|
+
|
|
|
+ const getTypeLabel = (type: string) => {
|
|
|
+ const labels = {
|
|
|
+ single: '单次',
|
|
|
+ monthly: '单月',
|
|
|
+ yearly: '年',
|
|
|
+ lifetime: '永久',
|
|
|
+ };
|
|
|
+ return labels[type as keyof typeof labels] || type;
|
|
|
+ };
|
|
|
|
|
|
return (
|
|
|
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-white to-blue-50">
|
|
|
@@ -128,40 +92,53 @@ export default function PricingPage() {
|
|
|
|
|
|
{/* Pricing Cards */}
|
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pb-20">
|
|
|
- <div className="grid md:grid-cols-3 gap-8">
|
|
|
- {plans.map((plan) => (
|
|
|
- <Card
|
|
|
- key={plan.id}
|
|
|
- className={`relative ${plan.color} ${plan.popular ? 'scale-105' : ''} transition-transform duration-300`}
|
|
|
+ <div className="grid md:grid-cols-2 lg:grid-cols-4 gap-8">
|
|
|
+ {membershipPlans?.map((plan) => (
|
|
|
+ <Card
|
|
|
+ key={plan.id}
|
|
|
+ className={`relative border-0 shadow-lg hover:shadow-xl transition-all duration-300 hover:-translate-y-1 ${
|
|
|
+ plan.type === 'yearly' ? 'ring-2 ring-blue-500' : ''
|
|
|
+ }`}
|
|
|
>
|
|
|
- {plan.popular && (
|
|
|
- <Badge className="absolute -top-3 left-1/2 transform -translate-x-1/2 bg-blue-500 text-white">
|
|
|
+ {plan.type === 'yearly' && (
|
|
|
+ <Badge className="absolute -top-3 left-1/2 transform -translate-x-1/2 bg-gradient-to-r from-blue-600 to-purple-600 text-white">
|
|
|
<Star className="h-4 w-4 mr-1" />
|
|
|
推荐
|
|
|
</Badge>
|
|
|
)}
|
|
|
|
|
|
<CardHeader>
|
|
|
- <CardTitle className="text-2xl">{plan.name}</CardTitle>
|
|
|
- <CardDescription>{plan.description}</CardDescription>
|
|
|
- <div className="mt-4">
|
|
|
- <span className="text-4xl font-bold text-gray-900">¥{plan.price}</span>
|
|
|
- <span className="text-gray-600">{plan.period}</span>
|
|
|
+ <div className="text-center">
|
|
|
+ <CardTitle className="text-2xl mb-2">{plan.name}</CardTitle>
|
|
|
+ <CardDescription className="text-sm">{plan.description}</CardDescription>
|
|
|
+ <div className="mt-4">
|
|
|
+ <span className="text-4xl font-bold text-gray-900">¥{plan.price}</span>
|
|
|
+ </div>
|
|
|
+ <p className="text-gray-600 text-sm mt-2">
|
|
|
+ {plan.durationDays === 0 ? '永久有效' :
|
|
|
+ plan.durationDays === 1 ? '24小时有效' :
|
|
|
+ `${plan.durationDays}天有效`}
|
|
|
+ </p>
|
|
|
</div>
|
|
|
</CardHeader>
|
|
|
|
|
|
<CardContent>
|
|
|
- <ul className="space-y-3">
|
|
|
- {plan.features.map((feature, index) => (
|
|
|
- <li key={index} className="flex items-center">
|
|
|
- <Check className="h-5 w-5 text-green-500 mr-2" />
|
|
|
- <span className="text-gray-700">{feature}</span>
|
|
|
+ <ul className="space-y-2">
|
|
|
+ {plan.features?.map((feature: string, index: number) => (
|
|
|
+ <li key={index} className="flex items-start">
|
|
|
+ <Check className="h-4 w-4 text-green-500 mr-2 flex-shrink-0 mt-0.5" />
|
|
|
+ <span className="text-gray-700 text-sm">{feature}</span>
|
|
|
+ </li>
|
|
|
+ )) || (
|
|
|
+ <li className="flex items-start">
|
|
|
+ <Check className="h-4 w-4 text-green-500 mr-2 flex-shrink-0 mt-0.5" />
|
|
|
+ <span className="text-gray-700 text-sm">基础功能</span>
|
|
|
</li>
|
|
|
- ))}
|
|
|
+ )}
|
|
|
</ul>
|
|
|
|
|
|
- <Button
|
|
|
- className={`w-full mt-6 ${plan.popular ? 'bg-blue-600 hover:bg-blue-700' : ''}`}
|
|
|
+ <Button
|
|
|
+ className="w-full mt-6 bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700"
|
|
|
onClick={() => navigate('/register')}
|
|
|
>
|
|
|
立即选择
|