import React, { useState, useEffect } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { Box, Button, Flex, Text, Badge, VStack, HStack, useToast, Modal, ModalOverlay, ModalContent, ModalHeader, ModalBody, ModalCloseButton, useDisclosure, Image, Progress, Divider, Input, Icon, Container, useBreakpointValue, Checkbox, Link as ChakraLink, } from '@chakra-ui/react'; import { FaWeixin, FaGem, FaCheck, FaQrcode, FaClock, FaRedo, FaCrown, FaStar, FaTimes, FaChevronDown, FaChevronUp, FaExternalLinkAlt, } from 'react-icons/fa'; import { AlipayCircleOutlined } from '@ant-design/icons'; import { logger } from '../../utils/logger'; import { useAuth } from '../../contexts/AuthContext'; import { useSubscriptionEvents } from '../../hooks/useSubscriptionEvents'; import { subscriptionConfig, themeColors } from '../../views/Pages/Account/subscription-content'; import { getApiBase } from '../../utils/apiConfig'; // 会员协议 URL 配置 const AGREEMENT_URLS = { pro: 'https://valuefrontier.cn/htmls/pro-member-agreement.html', max: 'https://valuefrontier.cn/htmls/max-member-agreement.html', }; // 计费周期选择器组件 - 移动端垂直布局(年付在上),桌面端水平布局 interface CycleSelectorProps { options: any[]; selectedCycle: string; onSelectCycle: (cycle: string) => void; } function CycleSelector({ options, selectedCycle, onSelectCycle }: CycleSelectorProps) { // 使用 useBreakpointValue 动态获取是否是移动端 const isMobile = useBreakpointValue({ base: true, md: false }); // 移动端倒序显示(年付在上),桌面端正常顺序 const displayOptions = isMobile ? [...options].reverse() : options; return ( {displayOptions.map((option: any) => ( {option.discountPercent > 0 && ( 省{option.discountPercent}% )} ))} ); } export default function SubscriptionContentNew() { const { user } = useAuth(); const subscriptionEvents = useSubscriptionEvents({ currentSubscription: { plan: user?.subscription_plan || 'free', status: user?.subscription_status || 'inactive', }, }); const [selectedCycle, setSelectedCycle] = useState('monthly'); const [selectedPlan, setSelectedPlan] = useState(null); const [subscriptionPlans, setSubscriptionPlans] = useState([]); const [priceInfo, setPriceInfo] = useState(null); const [loading, setLoading] = useState(false); const [promoCode, setPromoCode] = useState(''); const [promoCodeApplied, setPromoCodeApplied] = useState(false); const [promoCodeError, setPromoCodeError] = useState(''); const [validatingPromo, setValidatingPromo] = useState(false); const [paymentOrder, setPaymentOrder] = useState(null); const [paymentCountdown, setPaymentCountdown] = useState(300); const [autoCheckInterval, setAutoCheckInterval] = useState(null); const [forceUpdating, setForceUpdating] = useState(false); const [paymentMethod, setPaymentMethod] = useState<'wechat' | 'alipay'>('wechat'); // 支付方式 const [openFaqIndex, setOpenFaqIndex] = useState(null); // 会员协议确认状态 const [agreementChecked, setAgreementChecked] = useState(false); const { isOpen, onOpen, onClose } = useDisclosure(); const toast = useToast(); // 倒计时更新 useEffect(() => { let timer: any; if (paymentCountdown > 0) { timer = setInterval(() => { setPaymentCountdown((prev) => { if (prev <= 1) { handlePaymentExpire(); return 0; } return prev - 1; }); }, 1000); } return () => clearInterval(timer); }, [paymentCountdown]); // 组件卸载时清理定时器 useEffect(() => { return () => { stopAutoPaymentCheck(); }; }, []); // 组件加载时获取套餐数据 useEffect(() => { fetchSubscriptionPlans(); }, []); // 检查是否从支付宝支付返回(手机端支付完成后会跳转回来) useEffect(() => { const checkAlipayReturn = async () => { // 检查 URL 参数是否包含支付宝返回标记 const urlParams = new URLSearchParams(window.location.search); const paymentReturn = urlParams.get('payment_return'); // 支付宝返回的参数是 out_trade_no,后端重定向时会转成 order_no const orderNo = urlParams.get('order_no') || urlParams.get('out_trade_no'); if (paymentReturn === 'alipay' && orderNo) { // 从支付宝返回,检查支付状态 toast({ title: '正在确认支付结果...', status: 'info', duration: 2000, isClosable: true, }); try { // 优先使用 sessionStorage 中的 orderId,否则使用 order_no 查询 const orderId = sessionStorage.getItem('alipay_order_id'); const statusUrl = orderId ? `${getApiBase()}/api/payment/alipay/order/${orderId}/status` : `${getApiBase()}/api/payment/alipay/order-by-no/${orderNo}/status`; const response = await fetch(statusUrl, { credentials: 'include', }); if (response.ok) { const data = await response.json(); if (data.success && (data.data?.status === 'paid' || data.payment_success)) { toast({ title: '支付成功!', description: '您的订阅已激活', status: 'success', duration: 5000, isClosable: true, }); // 清理 sessionStorage sessionStorage.removeItem('alipay_order_id'); sessionStorage.removeItem('alipay_order_no'); // 清除 URL 参数并刷新页面 window.history.replaceState({}, document.title, window.location.pathname); setTimeout(() => window.location.reload(), 2000); } else { toast({ title: '支付状态待确认', description: '如已完成支付,请稍候或刷新页面', status: 'warning', duration: 5000, isClosable: true, }); // 清除 URL 参数 window.history.replaceState({}, document.title, window.location.pathname); } } else { // 清除 URL 参数 window.history.replaceState({}, document.title, window.location.pathname); } } catch (error) { logger.error('SubscriptionContentNew', 'checkAlipayReturn', error); // 清除 URL 参数 window.history.replaceState({}, document.title, window.location.pathname); } } }; checkAlipayReturn(); }, [toast]); const fetchSubscriptionPlans = async () => { try { logger.debug('SubscriptionContentNew', '正在获取订阅套餐'); const response = await fetch(`${getApiBase()}/api/subscription/plans`); if (response.ok) { const data = await response.json(); if (data.success && Array.isArray(data.data)) { const validPlans = data.data.filter( (plan: any) => plan && plan.name && typeof plan.monthly_price === 'number' && typeof plan.yearly_price === 'number' ); logger.debug('SubscriptionContentNew', '套餐加载成功', { status: response.status, validPlansCount: validPlans.length, }); setSubscriptionPlans(validPlans); } else { logger.warn('SubscriptionContentNew', '套餐数据格式异常', { data }); setSubscriptionPlans([]); } } else { logger.error('SubscriptionContentNew', 'fetchSubscriptionPlans', new Error(`HTTP ${response.status}`)); setSubscriptionPlans([]); } } catch (error) { logger.error('SubscriptionContentNew', 'fetchSubscriptionPlans', error); setSubscriptionPlans([]); } }; const handlePaymentExpire = () => { stopAutoPaymentCheck(); toast({ title: '支付二维码已过期', description: '请重新创建订单', status: 'warning', duration: 3000, isClosable: true, }); }; const stopAutoPaymentCheck = () => { if (autoCheckInterval) { clearInterval(autoCheckInterval); setAutoCheckInterval(null); } }; const formatTime = (seconds: number) => { const minutes = Math.floor(seconds / 60); const remainingSeconds = seconds % 60; return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`; }; // 计算价格 const calculatePrice = async (plan: any, cycle: string, promoCodeValue: any = null) => { try { const validPromoCode = promoCodeValue && typeof promoCodeValue === 'string' && promoCodeValue.trim() ? promoCodeValue.trim() : null; const response = await fetch(`${getApiBase()}/api/subscription/calculate-price`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, credentials: 'include', body: JSON.stringify({ to_plan: plan.name, to_cycle: cycle, promo_code: validPromoCode, }), }); if (response.ok) { const data = await response.json(); if (data.success) { setPriceInfo(data.data); return data.data; } } return null; } catch (error) { logger.error('SubscriptionContent', 'calculatePrice', error); return null; } }; // 验证优惠码 const handleValidatePromoCode = async () => { const trimmedCode = promoCode.trim(); if (!trimmedCode) { setPromoCodeError('请输入优惠码'); return; } if (!selectedPlan) { setPromoCodeError('请先选择套餐'); return; } setValidatingPromo(true); setPromoCodeError(''); try { const result = await calculatePrice(selectedPlan, selectedCycle, trimmedCode); if (result && !result.promo_error) { setPromoCodeApplied(true); toast({ title: '优惠码已应用', description: `节省 ¥${result.discount_amount.toFixed(2)}`, status: 'success', duration: 3000, isClosable: true, }); } else { setPromoCodeError(result?.promo_error || '优惠码无效'); setPromoCodeApplied(false); } } catch (error) { setPromoCodeError('验证失败,请重试'); setPromoCodeApplied(false); } finally { setValidatingPromo(false); } }; const handleRemovePromoCode = async () => { setPromoCode(''); setPromoCodeApplied(false); setPromoCodeError(''); if (selectedPlan) { await calculatePrice(selectedPlan, selectedCycle, null); } }; const handleSubscribe = async (plan: any) => { if (!user) { toast({ title: '请先登录', description: '登录后即可订阅', status: 'warning', duration: 3000, isClosable: true, }); return; } subscriptionEvents.trackPricingPlanSelected( plan.name, selectedCycle, getCurrentPrice(plan) ); setSelectedPlan(plan); // 切换套餐时重置协议勾选状态 setAgreementChecked(false); await calculatePrice(plan, selectedCycle, promoCodeApplied ? promoCode : null); onOpen(); }; const handleCreatePaymentOrder = async () => { if (!selectedPlan || !user) return; setLoading(true); try { const price = priceInfo?.final_amount || getCurrentPrice(selectedPlan); // 检查是否为免费升级(剩余价值足够抵扣新套餐价格) if (price === 0 && priceInfo?.is_upgrade) { const response = await fetch(`${getApiBase()}/api/subscription/free-upgrade`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, credentials: 'include', body: JSON.stringify({ plan_name: selectedPlan.name, billing_cycle: selectedCycle, }), }); const data = await response.json(); if (data.success) { subscriptionEvents.trackPaymentSuccessful({ planName: selectedPlan.name, paymentMethod: 'free_upgrade', amount: 0, orderId: 'free_upgrade', transactionId: 'free_upgrade', }); toast({ title: '升级成功!', description: data.message, status: 'success', duration: 5000, isClosable: true, }); onClose(); setTimeout(() => window.location.reload(), 2000); return; } else { throw new Error(data.error || '免费升级失败'); } } const paymentMethodName = paymentMethod === 'alipay' ? 'alipay' : 'wechat_pay'; subscriptionEvents.trackPaymentInitiated({ planName: selectedPlan.name, paymentMethod: paymentMethodName, amount: price, billingCycle: selectedCycle, }); // 根据支付方式选择不同的 API const apiUrl = paymentMethod === 'alipay' ? `${getApiBase()}/api/payment/alipay/create-order` : `${getApiBase()}/api/payment/create-order`; // 检测是否为移动端设备(多重检测,确保 Safari 兼容性) const userAgent = navigator.userAgent; // 方式1:User Agent 检测 const uaCheck = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent); // 方式2:触摸屏检测(Safari 兼容) const touchCheck = 'ontouchstart' in window || navigator.maxTouchPoints > 0; // 方式3:屏幕宽度检测 const screenCheck = window.innerWidth <= 768; // 方式4:Safari 移动端特定检测(iOS Safari 有 standalone 属性) const isSafariMobile = /Safari/i.test(userAgent) && /Apple/i.test(navigator.vendor) && touchCheck; // 综合判断:UA 匹配 或 (触摸屏 + 小屏幕) 或 Safari 移动端 const isMobileDevice = uaCheck || (touchCheck && screenCheck) || isSafariMobile; // 调试日志 console.log('[支付] User-Agent:', userAgent); console.log('[支付] 移动端检测 - UA:', uaCheck, 'Touch:', touchCheck, 'Screen:', screenCheck, 'SafariMobile:', isSafariMobile); console.log('[支付] 最终判断为移动端:', isMobileDevice); console.log('[支付] 支付方式:', paymentMethod); const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', }, credentials: 'include', body: JSON.stringify({ plan_name: selectedPlan.name, billing_cycle: selectedCycle, promo_code: promoCodeApplied ? promoCode : null, is_mobile: isMobileDevice, // 传递设备类型,用于支付宝选择 page/wap 支付 }), }); if (response.ok) { const data = await response.json(); if (data.success) { if (paymentMethod === 'alipay') { // 支付宝:跳转到支付页面 if (data.data.pay_url) { // 使用与上面相同的移动端检测结果(已在上面计算过) console.log('[支付宝] 订单创建成功'); console.log('[支付宝] pay_url:', data.data.pay_url.substring(0, 100) + '...'); console.log('[支付宝] 是否移动端跳转:', isMobileDevice); if (isMobileDevice) { // 手机端:尝试自动跳转到支付宝 // 保存订单信息到 sessionStorage,支付完成后返回时可以用来检查状态 sessionStorage.setItem('alipay_order_id', data.data.id); sessionStorage.setItem('alipay_order_no', data.data.order_no); // 检测是否在微信内置浏览器中 const isWechatBrowser = /MicroMessenger/i.test(navigator.userAgent); // 设置订单状态(用于支付完成后返回时显示) setPaymentOrder({ ...data.data, payment_method: 'alipay', is_mobile: true, is_wechat_browser: isWechatBrowser, }); setPaymentCountdown(30 * 60); startAutoPaymentCheck(data.data.id, 'alipay'); if (isWechatBrowser) { // 微信内置浏览器:无法直接跳转支付宝,需要引导用户在外部浏览器打开 toast({ title: '订单创建成功', description: '微信内无法直接打开支付宝,请点击按钮复制链接后在浏览器中打开', status: 'warning', duration: 5000, isClosable: true, }); } else { // 非微信浏览器(Safari、Chrome 等):直接跳转 toast({ title: '正在跳转支付宝', description: '如未自动跳转,请点击下方按钮', status: 'success', duration: 3000, isClosable: true, }); // 延迟 300ms 后自动跳转,让 toast 显示出来 setTimeout(() => { window.location.href = data.data.pay_url; }, 300); } } else { // PC端:新窗口打开 setPaymentOrder(data.data); setPaymentCountdown(30 * 60); startAutoPaymentCheck(data.data.id, 'alipay'); toast({ title: '订单创建成功', description: '正在跳转到支付宝支付页面...', status: 'success', duration: 3000, isClosable: true, }); // 延迟跳转,让用户看到提示 setTimeout(() => { window.open(data.data.pay_url, '_blank'); }, 500); } } else { throw new Error('支付链接获取失败'); } } else { // 微信:显示二维码 setPaymentOrder(data.data); setPaymentCountdown(30 * 60); startAutoPaymentCheck(data.data.id, 'wechat'); toast({ title: '订单创建成功', description: '请使用微信扫描二维码完成支付', status: 'success', duration: 3000, isClosable: true, }); } } else { throw new Error(data.error || data.message || '创建订单失败'); } } else { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.error || '网络请求失败'); } } catch (error: any) { subscriptionEvents.trackPaymentFailed( { planName: selectedPlan.name, paymentMethod: paymentMethod === 'alipay' ? 'alipay' : 'wechat_pay', amount: getCurrentPrice(selectedPlan), }, error.message ); toast({ title: '创建订单失败', description: error.message, status: 'error', duration: 3000, isClosable: true, }); } finally { setLoading(false); } }; const startAutoPaymentCheck = (orderId: string, method: 'wechat' | 'alipay' = 'wechat') => { // 根据支付方式选择不同的状态查询 API const statusApiUrl = method === 'alipay' ? `${getApiBase()}/api/payment/alipay/order/${orderId}/status` : `${getApiBase()}/api/payment/order/${orderId}/status`; const checkInterval = setInterval(async () => { try { const response = await fetch(statusApiUrl, { credentials: 'include', }); if (response.ok) { const data = await response.json(); if (data.success && (data.data.status === 'paid' || data.payment_success)) { clearInterval(checkInterval); setAutoCheckInterval(null); subscriptionEvents.trackPaymentSuccessful({ planName: selectedPlan?.name, paymentMethod: method === 'alipay' ? 'alipay' : 'wechat_pay', amount: paymentOrder?.amount, orderId: orderId, transactionId: data.data.transaction_id || data.data.alipay_trade_no, }); toast({ title: '支付成功!', description: '您的订阅已激活', status: 'success', duration: 5000, isClosable: true, }); onClose(); setTimeout(() => window.location.reload(), 2000); } } } catch (error) { logger.error('SubscriptionContent', 'checkPaymentStatus', error); } }, 3000); setAutoCheckInterval(checkInterval as any); }; const handleForceUpdate = async () => { if (!paymentOrder) return; setForceUpdating(true); try { // 根据订单的支付方式选择不同的查询 API const orderPaymentMethod = (paymentOrder as any).payment_method || paymentMethod; const statusApiUrl = orderPaymentMethod === 'alipay' ? `${getApiBase()}/api/payment/alipay/order/${(paymentOrder as any).id}/status` : `${getApiBase()}/api/payment/order/${(paymentOrder as any).id}/status`; const response = await fetch(statusApiUrl, { credentials: 'include', }); if (response.ok) { const data = await response.json(); if (data.success && (data.data.status === 'paid' || data.payment_success)) { toast({ title: '支付成功!', description: '您的订阅已激活', status: 'success', duration: 5000, isClosable: true, }); onClose(); setTimeout(() => window.location.reload(), 2000); } else { toast({ title: '未检测到支付', description: '请确认已完成支付后重试', status: 'info', duration: 3000, isClosable: true, }); } } } catch (error: any) { toast({ title: '查询失败', description: error.message, status: 'error', duration: 3000, isClosable: true, }); } finally { setForceUpdating(false); } }; // 重新打开支付宝支付页面 const handleReopenAlipay = () => { if (paymentOrder && (paymentOrder as any).pay_url) { window.open((paymentOrder as any).pay_url, '_blank'); } }; // 合并数据库数据和前端配置 const getMergedPlans = () => { // 如果数据库还没有加载数据,使用静态配置 if (subscriptionPlans.length === 0) { return subscriptionConfig.plans; } // 合并数据库价格和前端UI配置 return subscriptionConfig.plans.map((configPlan: any) => { const dbPlan = subscriptionPlans.find((p: any) => p.name === configPlan.name); if (!dbPlan) { return configPlan; // 如果数据库中没有,使用前端配置 } // 解析数据库中的 pricing_options JSON let pricingOptions = configPlan.pricingOptions; if (dbPlan.pricing_options) { try { const parsedOptions = typeof dbPlan.pricing_options === 'string' ? JSON.parse(dbPlan.pricing_options) : dbPlan.pricing_options; if (Array.isArray(parsedOptions) && parsedOptions.length > 0) { pricingOptions = parsedOptions.map((opt: any) => ({ cycleKey: opt.cycle_key, label: opt.label, months: opt.months, price: parseFloat(opt.price), originalPrice: opt.original_price ? parseFloat(opt.original_price) : null, discountPercent: opt.discount_percent || 0, })); } } catch (error) { logger.error('SubscriptionContentNew', '解析pricing_options失败', error); } } // 合并数据,数据库价格优先 return { ...configPlan, monthly_price: dbPlan.monthly_price, yearly_price: dbPlan.yearly_price, pricingOptions: pricingOptions, displayName: dbPlan.display_name || configPlan.displayName, description: dbPlan.description || configPlan.description, }; }); }; const getCurrentPrice = (plan: any) => { if (!plan || plan.name === 'free') return 0; const option = plan.pricingOptions?.find( (opt: any) => opt.cycleKey === selectedCycle ); return option ? option.price : plan.pricingOptions?.[0]?.price || 0; }; const getCurrentPriceOption = (plan: any) => { if (!plan || plan.name === 'free') return null; return plan.pricingOptions?.find((opt: any) => opt.cycleKey === selectedCycle); }; const getIconComponent = (iconName: string) => { const icons: any = { star: FaStar, gem: FaGem, crown: FaCrown, }; return icons[iconName] || FaStar; }; // 获取按钮文字 const getButtonText = (plan: any) => { const currentPlanName = user?.subscription_type; const isActive = user?.subscription_status === 'active'; if (!isActive || !currentPlanName || currentPlanName === 'free') { return `选择${plan.displayName}`; } if (currentPlanName === plan.name) { // 同级续费 return `续费${plan.displayName}`; } // 升级或降级 if (currentPlanName === 'pro' && plan.name === 'max') { return `升级为${plan.displayName}`; } if (currentPlanName === 'max' && plan.name === 'pro') { return `到期后切换到${plan.displayName}`; } return `选择${plan.displayName}`; }; // 判断按钮是否可点击 const isButtonDisabled = (plan: any) => { return false; // 所有套餐都可以选择,包括当前套餐(续费) }; return ( {/* 背景光晕 */} {/* 标题区域 */} 订阅方案 立即开启智能决策 {/* 当前订阅状态 */} {user && user.subscription_type && user.subscription_type !== 'free' && user.subscription_status === 'active' && ( 当前订阅: {user.subscription_type === 'max' ? 'Max 旗舰版' : 'Pro 专业版'} {user.billing_cycle && ( {user.billing_cycle === 'monthly' ? '月付' : user.billing_cycle === 'quarterly' ? '季付' : user.billing_cycle === 'semiannual' ? '半年付' : user.billing_cycle === 'yearly' ? '年付' : user.billing_cycle} )} 使用中 到期时间 {user.subscription_end_date ? new Date(user.subscription_end_date).toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric' }) : '永久有效' } {user.subscription_end_date && (() => { const endDate = new Date(user.subscription_end_date); const today = new Date(); const daysLeft = Math.ceil((endDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24)); if (daysLeft > 0 && daysLeft <= 30) { return ( ⚠️ 还有 {daysLeft} 天到期,记得及时续费哦 ); } return null; })()} )} {/* 计费周期选择器 */} 选择计费周期 · 时长越长优惠越大 {(() => { const currentOption = getMergedPlans()[1]?.pricingOptions?.find( (opt: any) => opt.cycleKey === selectedCycle ); if (currentOption && currentOption.discountPercent > 0) { return ( 当前选择可节省 {currentOption.discountPercent}% 的费用 ); } return null; })()} {/* 套餐卡片 - 借鉴 index.pug 设计 */} {getMergedPlans().slice(1).map((plan: any, index: number) => { const IconComponent = getIconComponent(plan.icon); const currentPriceOption = getCurrentPriceOption(plan); const isCurrentPlan = user?.subscription_type === plan.name && user?.subscription_status === 'active'; const isPremium = plan.name === 'max'; return ( {/* 套餐标题 */} {plan.displayName} {/* 价格卡片 */} ¥{getCurrentPrice(plan)} / {currentPriceOption?.label || '月'} {/* 功能列表 */} {plan.features.map((feature: any, idx: number) => ( {feature.name} {feature.limit && ( ({feature.limit}) )} ))} ); })} {/* FAQ 区域 */} 常见问题 {subscriptionConfig.faqs.map((faq: any, index: number) => ( setOpenFaqIndex(openFaqIndex === index ? null : index)} > {faq.question} {openFaqIndex === index && ( {faq.answer.split('\n').map((line: string, idx: number) => ( {line} ))} )} ))} {/* 支付模态框 */} {paymentMethod === 'alipay' ? '支付宝支付' : '微信支付'} {!paymentOrder ? ( {/* 支付方式选择 */} 选择支付方式 {/* 订阅类型提示 */} {selectedPlan && priceInfo && ( <> {priceInfo.is_upgrade && ( {priceInfo.final_amount === 0 ? `恭喜!您的当前订阅剩余价值足够直接升级到${selectedPlan.displayName},无需支付额外费用!` : `升级到${selectedPlan.displayName},立即生效!按差价补缴费用`} )} {priceInfo.is_downgrade && ( 当前{priceInfo.current_plan?.toUpperCase()}订阅到期后自动切换到{selectedPlan.displayName} )} {priceInfo.is_renewal && ( 续费{selectedPlan.displayName},在当前到期日基础上延长时长 )} )} {/* 价格明细 */} {selectedPlan && priceInfo && ( {selectedPlan.displayName} · {selectedCycle === 'monthly' ? '月付' : selectedCycle === 'quarterly' ? '季付' : selectedCycle === 'semiannual' ? '半年付' : '年付'} ¥{priceInfo.original_price?.toFixed(2) || getCurrentPrice(selectedPlan).toFixed(2)} {/* 升级抵扣价值 */} {priceInfo.is_upgrade && priceInfo.remaining_value > 0 && ( 当前订阅剩余价值抵扣 -¥{priceInfo.remaining_value.toFixed(2)} )} {/* 优惠码折扣 */} {promoCodeApplied && priceInfo.discount_amount > 0 && ( 优惠码折扣 -¥{priceInfo.discount_amount.toFixed(2)} )} 实付金额: ¥{priceInfo.final_amount.toFixed(2)} )} {/* 优惠码输入 */} {selectedPlan && ( { setPromoCode(e.target.value.toUpperCase()); setPromoCodeError(''); }} size="md" isDisabled={promoCodeApplied} bg="rgba(255, 255, 255, 0.05)" border="1px solid rgba(255, 255, 255, 0.1)" color="white" _placeholder={{ color: 'rgba(255, 255, 255, 0.4)' }} _hover={{ borderColor: 'rgba(212, 175, 55, 0.3)' }} _focus={{ borderColor: '#D4AF37', boxShadow: '0 0 0 1px #D4AF37' }} /> {promoCodeError && ( {promoCodeError} )} {promoCodeApplied && priceInfo && ( 优惠码已应用!节省 ¥{priceInfo.discount_amount.toFixed(2)} )} )} {/* 会员协议确认 */} setAgreementChecked(e.target.checked)} colorScheme="green" size="md" > 我已阅读并同意 { const planName = (selectedPlan as { name?: string } | null)?.name?.toLowerCase(); return planName === 'pro' || planName === 'max' ? AGREEMENT_URLS[planName] : AGREEMENT_URLS.pro; })()} isExternal color="#3182CE" textDecoration="underline" mx={1} onClick={(e) => e.stopPropagation()} > 《{(selectedPlan as { name?: string } | null)?.name?.toLowerCase() === 'max' ? 'MAX' : 'PRO'}会员服务协议》 ) : ( {/* 根据支付方式显示不同提示 */} {(paymentOrder as any).payment_method === 'alipay' ? ( <> 支付宝支付 {(paymentOrder as any).is_mobile ? ( <> {(paymentOrder as any).is_wechat_browser ? ( <> 检测到您在微信中打开,请点击右上角「...」选择「在浏览器中打开」后再支付 或点击下方按钮尝试跳转 ) : ( 点击下方按钮打开支付宝完成支付 )} ) : ( <> 请在新打开的页面中完成支付 支付完成后点击下方按钮确认 )} ) : ( 请使用微信扫描二维码完成支付 )} {/* 倒计时 */} 订单有效时间: {formatTime(paymentCountdown)} {/* 微信二维码(仅微信支付显示) */} {(paymentOrder as any).payment_method !== 'alipay' && ( {(paymentOrder as any).qr_code_url ? ( 微信支付二维码 ) : ( )} )} {/* 订单信息 */} 订单号: {(paymentOrder as any).order_no} 支付金额: ¥{(paymentOrder as any).amount} {/* 操作按钮 */} {/* 支付宝:重新打开支付页面按钮 */} {(paymentOrder as any).payment_method === 'alipay' && (paymentOrder as any).pay_url && ( )} )} ); }