PricingPage.tsx 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. import { useState } from 'react';
  2. import { Button } from '@/client/components/ui/button';
  3. import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/client/components/ui/card';
  4. import { Badge } from '@/client/components/ui/badge';
  5. import { Check, Star } from 'lucide-react';
  6. import { useNavigate } from 'react-router-dom';
  7. import { useQuery } from '@tanstack/react-query';
  8. import { membershipPlanClient } from '@/client/api';
  9. export default function PricingPage() {
  10. const navigate = useNavigate();
  11. const { data: membershipPlans } = useQuery({
  12. queryKey: ['membership-plans-pricing'],
  13. queryFn: async () => {
  14. const response = await membershipPlanClient.$get();
  15. if (!response.ok) throw new Error('获取套餐失败');
  16. const data = await response.json();
  17. return data.data.filter((plan: any) => plan.isActive === 1).sort((a: any, b: any) => a.sortOrder - b.sortOrder);
  18. },
  19. });
  20. const getTypeLabel = (type: string) => {
  21. const labels = {
  22. single: '单次',
  23. monthly: '单月',
  24. yearly: '年',
  25. lifetime: '永久',
  26. };
  27. return labels[type as keyof typeof labels] || type;
  28. };
  29. return (
  30. <div className="min-h-screen bg-gradient-to-br from-slate-50 via-white to-blue-50">
  31. {/* Header */}
  32. <header className="fixed top-0 left-0 right-0 z-50 bg-white/90 backdrop-blur-sm border-b">
  33. <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
  34. <div className="flex justify-between items-center h-16">
  35. <div className="flex items-center">
  36. <h1 className="text-xl font-bold text-gray-900">元亨Word - 收费标准</h1>
  37. </div>
  38. <nav className="hidden md:flex items-center space-x-8">
  39. <button
  40. onClick={() => navigate('/')}
  41. className="text-gray-700 hover:text-blue-600 transition-colors font-medium"
  42. >
  43. 首页
  44. </button>
  45. <button
  46. onClick={() => navigate('/templates')}
  47. className="text-gray-700 hover:text-blue-600 transition-colors font-medium"
  48. >
  49. 模板广场
  50. </button>
  51. <button
  52. onClick={() => navigate('/login')}
  53. className="text-gray-700 hover:text-blue-600 transition-colors font-medium"
  54. >
  55. 登录
  56. </button>
  57. <button
  58. onClick={() => navigate('/register')}
  59. className="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors font-medium"
  60. >
  61. {/* 注册 */}
  62. </button>
  63. </nav>
  64. </div>
  65. </div>
  66. </header>
  67. {/* Hero Section */}
  68. <div className="pt-32 pb-16">
  69. <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
  70. <div className="text-center">
  71. <h1 className="text-4xl md:text-5xl font-bold text-gray-900 mb-6">
  72. 选择适合您的套餐
  73. </h1>
  74. <p className="text-xl text-gray-600 max-w-2xl mx-auto mb-8">
  75. 灵活的价格方案,满足不同用户的需求。从个人用户到企业团队,总有一款适合您。
  76. </p>
  77. <div className="flex justify-center items-center space-x-4">
  78. <Badge variant="outline" className="text-lg px-4 py-2">
  79. 新用户专享:首月立减50%
  80. </Badge>
  81. </div>
  82. </div>
  83. </div>
  84. </div>
  85. {/* Pricing Cards */}
  86. <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pb-20">
  87. <div className="grid md:grid-cols-2 lg:grid-cols-4 gap-8">
  88. {membershipPlans?.map((plan) => (
  89. <Card
  90. key={plan.id}
  91. className={`relative border-0 shadow-lg hover:shadow-xl transition-all duration-300 hover:-translate-y-1 ${
  92. plan.type === 'yearly' ? 'ring-2 ring-blue-500' : ''
  93. }`}
  94. >
  95. {plan.type === 'yearly' && (
  96. <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">
  97. <Star className="h-4 w-4 mr-1" />
  98. 推荐
  99. </Badge>
  100. )}
  101. <CardHeader>
  102. <div className="text-center">
  103. <CardTitle className="text-2xl mb-2">{plan.name}</CardTitle>
  104. <CardDescription className="text-sm">{plan.description}</CardDescription>
  105. <div className="mt-4">
  106. <span className="text-4xl font-bold text-gray-900">¥{plan.price}</span>
  107. </div>
  108. <p className="text-gray-600 text-sm mt-2">
  109. {plan.durationDays === 0 ? '永久有效' :
  110. plan.durationDays === 1 ? '24小时有效' :
  111. `${plan.durationDays}天有效`}
  112. </p>
  113. </div>
  114. </CardHeader>
  115. <CardContent>
  116. <ul className="space-y-2">
  117. {plan.features?.map((feature: string, index: number) => (
  118. <li key={index} className="flex items-start">
  119. <Check className="h-4 w-4 text-green-500 mr-2 flex-shrink-0 mt-0.5" />
  120. <span className="text-gray-700 text-sm">{feature}</span>
  121. </li>
  122. )) || (
  123. <li className="flex items-start">
  124. <Check className="h-4 w-4 text-green-500 mr-2 flex-shrink-0 mt-0.5" />
  125. <span className="text-gray-700 text-sm">基础功能</span>
  126. </li>
  127. )}
  128. </ul>
  129. <Button
  130. className="w-full mt-6 bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700"
  131. onClick={() => navigate('/register')}
  132. >
  133. 立即选择
  134. </Button>
  135. </CardContent>
  136. </Card>
  137. ))}
  138. </div>
  139. </div>
  140. {/* FAQ Section */}
  141. <div className="bg-gray-50 py-20">
  142. <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
  143. <div className="text-center mb-16">
  144. <h2 className="text-3xl font-bold text-gray-900 mb-4">常见问题</h2>
  145. <p className="text-gray-600">关于收费标准的详细说明</p>
  146. </div>
  147. <div className="max-w-3xl mx-auto space-y-6">
  148. <div className="bg-white p-6 rounded-lg shadow-sm">
  149. <h3 className="font-semibold text-lg mb-2">如何计费?</h3>
  150. <p className="text-gray-600">按月订阅,从激活当天开始计算。</p>
  151. </div>
  152. <div className="bg-white p-6 rounded-lg shadow-sm">
  153. <h3 className="font-semibold text-lg mb-2">可以升级套餐吗?</h3>
  154. <p className="text-gray-600">随时可以升级套餐,差价按剩余天数折算。</p>
  155. </div>
  156. <div className="bg-white p-6 rounded-lg shadow-sm">
  157. <h3 className="font-semibold text-lg mb-2">有免费试用吗?</h3>
  158. <p className="text-gray-600">可以跟管理员获取体验账号,体验全部功能。</p>
  159. </div>
  160. <div className="bg-white p-6 rounded-lg shadow-sm">
  161. <h3 className="font-semibold text-lg mb-2">如何付款?</h3>
  162. <p className="text-gray-600 mb-4">扫描下方二维码完成付款后,将付款截图发送给管理员确认:</p>
  163. <div className="flex flex-col items-center">
  164. <div className="grid grid-cols-2 gap-8 mb-6">
  165. <div className="bg-green-50 p-4 rounded-lg">
  166. <p className="text-center text-sm mb-2">付款二维码</p>
  167. <img src="/二维收款码.jpg" alt="微信支付二维码" className="w-48 h-48 object-contain mx-auto" />
  168. </div>
  169. <div className="bg-blue-50 p-4 rounded-lg">
  170. <p className="text-center text-sm mb-2">管理员微信</p>
  171. <img src="/管理员微信.jpg" alt="管理员微信二维码" className="w-48 h-48 object-contain mx-auto" />
  172. </div>
  173. </div>
  174. <p className="text-gray-600 mb-2">管理员微信:<span className="font-medium">andree123654</span></p>
  175. <p className="text-gray-500 text-sm">请在工作日9:00-18:00联系管理员进行确认,通常10分钟内可完成处理</p>
  176. </div>
  177. </div>
  178. </div>
  179. </div>
  180. </div>
  181. {/* Footer */}
  182. <footer className="bg-gray-900 text-white py-12">
  183. <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
  184. <div className="text-center">
  185. <h3 className="text-2xl font-bold mb-4">元亨Word批量处理工具</h3>
  186. <p className="text-gray-400 mb-6">
  187. 让每一份文档都充满个性,让批量处理变得简单
  188. </p>
  189. <div className="flex justify-center space-x-6">
  190. <Button
  191. variant="ghost"
  192. className="text-white hover:text-blue-400"
  193. onClick={() => navigate('/')}
  194. >
  195. 返回首页
  196. </Button>
  197. </div>
  198. </div>
  199. </div>
  200. </footer>
  201. </div>
  202. );
  203. }