update pay function

This commit is contained in:
2025-11-20 07:46:50 +08:00
parent f515dc94f4
commit 4a1157c0b6
3 changed files with 285 additions and 48 deletions

View File

@@ -51,7 +51,7 @@ export default function SubscriptionContentNew() {
},
});
const [selectedCycle, setSelectedCycle] = useState('yearly');
const [selectedCycle, setSelectedCycle] = useState('monthly');
const [selectedPlan, setSelectedPlan] = useState(null);
const [subscriptionPlans, setSubscriptionPlans] = useState([]);
const [priceInfo, setPriceInfo] = useState(null);
@@ -491,6 +491,37 @@ export default function SubscriptionContentNew() {
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 (
<Box
minH="100vh"
@@ -562,6 +593,115 @@ export default function SubscriptionContentNew() {
</motion.div>
</VStack>
{/* 当前订阅状态 */}
{user && user.subscription_type && user.subscription_type !== 'free' && user.subscription_status === 'active' && (
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.5, delay: 0.2 }}
>
<Box
mb={12}
p={6}
borderRadius="2xl"
bg="rgba(212, 175, 55, 0.05)"
border="2px solid"
borderColor="rgba(212, 175, 55, 0.3)"
backdropFilter="blur(20px)"
maxW="600px"
mx="auto"
position="relative"
overflow="hidden"
_before={{
content: '""',
position: 'absolute',
top: 0,
left: 0,
right: 0,
height: '4px',
bgGradient: 'linear-gradient(90deg, rgba(212, 175, 55, 0.5), rgba(212, 175, 55, 1), rgba(212, 175, 55, 0.5))',
}}
>
<VStack spacing={4} align="stretch">
<HStack justify="space-between" align="center">
<HStack spacing={3}>
<Icon
as={user.subscription_type === 'max' ? FaCrown : FaGem}
color="#D4AF37"
boxSize={6}
/>
<VStack align="start" spacing={0}>
<Text color="white" fontSize="lg" fontWeight="bold">
: {user.subscription_type === 'max' ? 'Max 旗舰版' : 'Pro 专业版'}
</Text>
<Text color="rgba(255, 255, 255, 0.6)" fontSize="xs">
{user.billing_cycle === 'monthly' ? '月付' :
user.billing_cycle === 'quarterly' ? '季付' :
user.billing_cycle === 'semiannual' ? '半年付' : '年付'}
</Text>
</VStack>
</HStack>
<Badge
px={3}
py={1}
borderRadius="full"
bg="rgba(76, 175, 80, 0.2)"
border="1px solid rgba(76, 175, 80, 0.4)"
color="green.300"
fontSize="xs"
fontWeight="medium"
>
使
</Badge>
</HStack>
<Divider borderColor="rgba(212, 175, 55, 0.2)" />
<Flex justify="space-between" align="center">
<HStack spacing={2}>
<Icon as={FaClock} color="rgba(212, 175, 55, 0.8)" boxSize={4} />
<Text color="rgba(255, 255, 255, 0.7)" fontSize="sm">
</Text>
</HStack>
<Text color="#D4AF37" fontSize="md" fontWeight="bold">
{user.end_date
? new Date(user.end_date).toLocaleDateString('zh-CN', {
year: 'numeric',
month: 'long',
day: 'numeric'
})
: '永久有效'
}
</Text>
</Flex>
{user.end_date && (() => {
const endDate = new Date(user.end_date);
const today = new Date();
const daysLeft = Math.ceil((endDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24));
if (daysLeft > 0 && daysLeft <= 30) {
return (
<Box
p={2}
borderRadius="md"
bg="rgba(255, 165, 0, 0.1)"
border="1px solid rgba(255, 165, 0, 0.3)"
>
<Text color="orange.300" fontSize="xs" textAlign="center">
{daysLeft}
</Text>
</Box>
);
}
return null;
})()}
</VStack>
</Box>
</motion.div>
)}
{/* 计费周期选择器 */}
<VStack spacing={6} mb={16}>
<Text fontSize="md" color="rgba(255, 255, 255, 0.7)">
@@ -791,55 +931,41 @@ export default function SubscriptionContentNew() {
size="lg"
h="56px"
bg={
isCurrentPlan
? 'transparent'
: isPremium
isPremium
? 'linear-gradient(135deg, #D4AF37 0%, #B8941F 100%)'
: 'rgba(255, 255, 255, 0.05)'
}
color={
isCurrentPlan
? 'rgba(255, 255, 255, 0.5)'
: isPremium
isPremium
? '#000'
: '#fff'
}
border={
isCurrentPlan
? '1px solid rgba(255, 255, 255, 0.2)'
: isPremium
isPremium
? 'none'
: '1px solid rgba(255, 255, 255, 0.1)'
}
fontWeight="bold"
fontSize="md"
borderRadius="lg"
onClick={() => !isCurrentPlan && handleSubscribe(plan)}
isDisabled={isCurrentPlan}
cursor={isCurrentPlan ? 'not-allowed' : 'pointer'}
_hover={
!isCurrentPlan
? {
transform: 'translateY(-2px)',
shadow: isPremium
? '0 8px 30px rgba(212, 175, 55, 0.4)'
: '0 8px 20px rgba(255, 255, 255, 0.1)',
bg: isPremium
? 'linear-gradient(135deg, #E5C047 0%, #C9A52F 100%)'
: 'rgba(255, 255, 255, 0.08)',
}
: {}
}
_active={
!isCurrentPlan
? {
transform: 'translateY(0)',
}
: {}
}
onClick={() => handleSubscribe(plan)}
isDisabled={isButtonDisabled(plan)}
cursor="pointer"
_hover={{
transform: 'translateY(-2px)',
shadow: isPremium
? '0 8px 30px rgba(212, 175, 55, 0.4)'
: '0 8px 20px rgba(255, 255, 255, 0.1)',
bg: isPremium
? 'linear-gradient(135deg, #E5C047 0%, #C9A52F 100%)'
: 'rgba(255, 255, 255, 0.08)',
}}
_active={{
transform: 'translateY(0)',
}}
transition="all 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
>
{isCurrentPlan ? '当前套餐' : `选择${plan.displayName}`}
{getButtonText(plan)}
</Button>
</Box>
@@ -980,6 +1106,57 @@ export default function SubscriptionContentNew() {
<ModalBody pb={6}>
{!paymentOrder ? (
<VStack spacing={6} align="stretch">
{/* 订阅类型提示 */}
{selectedPlan && priceInfo && (
<>
{priceInfo.is_upgrade && (
<Box
p={3}
bg="rgba(76, 175, 80, 0.1)"
borderRadius="lg"
border="1px solid rgba(76, 175, 80, 0.3)"
>
<HStack spacing={2}>
<Icon as={FaCheck} color="green.400" />
<Text color="green.400" fontSize="sm" fontWeight="medium">
{selectedPlan.displayName}
</Text>
</HStack>
</Box>
)}
{priceInfo.is_downgrade && (
<Box
p={3}
bg="rgba(255, 165, 0, 0.1)"
borderRadius="lg"
border="1px solid rgba(255, 165, 0, 0.3)"
>
<HStack spacing={2}>
<Icon as={FaClock} color="orange.400" />
<Text color="orange.400" fontSize="sm" fontWeight="medium">
{priceInfo.current_plan?.toUpperCase()}{selectedPlan.displayName}
</Text>
</HStack>
</Box>
)}
{priceInfo.is_renewal && (
<Box
p={3}
bg="rgba(33, 150, 243, 0.1)"
borderRadius="lg"
border="1px solid rgba(33, 150, 243, 0.3)"
>
<HStack spacing={2}>
<Icon as={FaRedo} color="blue.400" />
<Text color="blue.400" fontSize="sm" fontWeight="medium">
{selectedPlan.displayName}
</Text>
</HStack>
</Box>
)}
</>
)}
{/* 价格明细 */}
{selectedPlan && priceInfo && (
<Box