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 ? (
<>
检测到您在微信中打开,请点击右上角「...」选择「在浏览器中打开」后再支付
或点击下方按钮尝试跳转
>
) : (
点击下方按钮打开支付宝完成支付
)}
}
onClick={() => {
window.location.href = (paymentOrder as any).pay_url;
}}
_hover={{
bgGradient: 'linear-gradient(135deg, #4096ff, #1677FF)',
}}
>
打开支付宝付款
>
) : (
<>
请在新打开的页面中完成支付
支付完成后点击下方按钮确认
>
)}
>
) : (
请使用微信扫描二维码完成支付
)}
{/* 倒计时 */}
订单有效时间: {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 && (
}
onClick={handleReopenAlipay}
_hover={{
bgGradient: 'linear-gradient(135deg, #4096ff, #1677FF)',
transform: 'translateY(-2px)',
boxShadow: '0 8px 25px rgba(22, 119, 255, 0.4)',
}}
transition="all 0.3s"
>
重新打开支付页面
)}
}
onClick={handleForceUpdate}
isLoading={forceUpdating}
_hover={{
bgGradient: 'linear-gradient(135deg, #F4E3A7, #D4AF37)',
}}
>
已完成支付
)}
);
}