update pay function

This commit is contained in:
2025-11-19 22:56:28 +08:00
parent eae495ac34
commit 8bdfd0389c

View File

@@ -243,7 +243,7 @@ export default function SubscriptionContentNew() {
}, },
credentials: 'include', credentials: 'include',
body: JSON.stringify({ body: JSON.stringify({
plan_type: selectedPlan.name, plan_name: selectedPlan.name,
billing_cycle: selectedCycle, billing_cycle: selectedCycle,
promo_code: promoCodeApplied ? promoCode : null, promo_code: promoCodeApplied ? promoCode : null,
}), }),
@@ -582,18 +582,28 @@ export default function SubscriptionContentNew() {
h="100%" h="100%"
borderRadius="20px" borderRadius="20px"
overflow="hidden" overflow="hidden"
bg={isPremium ? 'rgba(10, 10, 10, 0.5)' : 'rgba(10, 10, 10, 0.3)'}
border={isPremium ? '1px solid rgba(212, 175, 55, 0.3)' : '1px solid rgba(255, 255, 255, 0.1)'} border={isPremium ? '1px solid rgba(212, 175, 55, 0.3)' : '1px solid rgba(255, 255, 255, 0.1)'}
boxShadow={isPremium ? '0 20px 60px rgba(212, 175, 55, 0.2)' : '0 20px 60px rgba(0, 0, 0, 0.3)'}
transition="all 0.4s cubic-bezier(0.4, 0, 0.2, 1)" transition="all 0.4s cubic-bezier(0.4, 0, 0.2, 1)"
_hover={{
transform: 'translateY(-8px)',
borderColor: isPremium ? 'rgba(212, 175, 55, 0.5)' : 'rgba(255, 255, 255, 0.2)',
boxShadow: isPremium
? '0 30px 80px rgba(212, 175, 55, 0.3)'
: '0 30px 80px rgba(0, 0, 0, 0.5)',
}}
_before={ _before={
isPremium isPremium
? { ? {
content: '""', content: '""',
position: 'absolute', position: 'absolute',
top: '-144px', top: '50%',
left: '52px', left: '50%',
width: '420px', transform: 'translate(-50%, -50%)',
maskImage: 'radial-gradient(circle at center, black 20%, transparent 52%)', width: '120%',
WebkitMaskImage: 'radial-gradient(circle at center, black 20%, transparent 52%)', height: '120%',
background: 'radial-gradient(circle at center, rgba(212, 175, 55, 0.1) 0%, transparent 70%)',
pointerEvents: 'none', pointerEvents: 'none',
zIndex: 0, zIndex: 0,
} }
@@ -609,26 +619,24 @@ export default function SubscriptionContentNew() {
pointerEvents: 'none', pointerEvents: 'none',
}} }}
> >
{/* 推荐标签 */} {/* 套餐标题 */}
{plan.badge && (
<Box <Box
position="relative" position="relative"
zIndex={2} zIndex={2}
py={2} py={3}
px={8.5} px={8.5}
fontSize="sm" fontSize="lg"
fontWeight="bold" fontWeight="bold"
bgGradient={ bgGradient={
isPremium isPremium
? 'linear-gradient(to right, rgba(212, 175, 55, 0.2), rgba(212, 175, 55, 0.2))' ? 'linear-gradient(to right, rgba(212, 175, 55, 0.2), rgba(212, 175, 55, 0.2))'
: 'transparent' : 'linear-gradient(to right, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.05))'
} }
borderTopRadius="20px" borderTopRadius="20px"
color={isPremium ? '#D4AF37' : 'white'} color={isPremium ? '#D4AF37' : 'white'}
> >
{plan.displayName} {plan.displayName}
</Box> </Box>
)}
<VStack <VStack
spacing={0} spacing={0}
@@ -636,7 +644,7 @@ export default function SubscriptionContentNew() {
position="relative" position="relative"
zIndex={3} zIndex={3}
flex={1} flex={1}
mt={plan.badge ? -5 : 0} mt={-1}
p={3.5} p={3.5}
pb={8} pb={8}
backdropFilter={isPremium ? 'blur(32px)' : 'blur(20px)'} backdropFilter={isPremium ? 'blur(32px)' : 'blur(20px)'}
@@ -655,108 +663,137 @@ export default function SubscriptionContentNew() {
{/* 价格卡片 */} {/* 价格卡片 */}
<Box <Box
position="relative" position="relative"
mb={8} mb={6}
p={5} p={6}
borderRadius="13px" borderRadius="16px"
bg={isPremium ? 'rgba(255, 255, 255, 0.1)' : 'rgba(255, 255, 255, 0.02)'} bg={isPremium ? 'rgba(212, 175, 55, 0.1)' : 'rgba(255, 255, 255, 0.03)'}
backdropFilter="blur(20px)" backdropFilter="blur(20px)"
boxShadow={isPremium ? '0 20px 60px rgba(0, 0, 0, 0.7)' : '0 20px 60px rgba(0, 0, 0, 0.5)'} boxShadow="0 8px 32px rgba(0, 0, 0, 0.4)"
_after={{ _after={{
content: '""', content: '""',
position: 'absolute', position: 'absolute',
inset: 0, inset: 0,
borderRadius: '13px', borderRadius: '16px',
border: '1px solid', border: '1px solid',
borderColor: 'rgba(255, 255, 255, 0.1)', borderColor: isPremium ? 'rgba(212, 175, 55, 0.2)' : 'rgba(255, 255, 255, 0.1)',
pointerEvents: 'none', pointerEvents: 'none',
}} }}
> >
<HStack align="baseline" spacing={3} mb={4}> <Flex align="baseline" justify="center" mb={5}>
<Text <Text
fontSize="4xl" fontSize="5xl"
fontWeight="bold" fontWeight="bold"
bgGradient="radial-gradient(circle at center, #FFFFFF 0%, rgba(255,255,255,0.6) 100%)" bgGradient="radial-gradient(circle at center, #FFFFFF 0%, rgba(255,255,255,0.6) 100%)"
bgClip="text" bgClip="text"
lineHeight="1.2" lineHeight="1"
letterSpacing="-0.02em"
> >
¥{getCurrentPrice(plan)} ¥{getCurrentPrice(plan)}
</Text> </Text>
<Text fontSize="sm" color="rgba(255, 255, 255, 0.7)"> <Text fontSize="lg" color="rgba(255, 255, 255, 0.6)" ml={2}>
/ {currentPriceOption?.label || '月'} / {currentPriceOption?.label || '月'}
</Text> </Text>
</HStack> </Flex>
<Button <Button
w="full" w="full"
size="lg" size="lg"
py={6} h="56px"
bgGradient={ bg={
isPremium isCurrentPlan
? 'linear-gradient(135deg, #D4AF37, #B8941F)' ? 'transparent'
: 'linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.05))' : isPremium
? 'linear-gradient(135deg, #D4AF37 0%, #B8941F 100%)'
: 'rgba(255, 255, 255, 0.05)'
}
color={
isCurrentPlan
? 'rgba(255, 255, 255, 0.5)'
: isPremium
? '#000'
: '#fff'
}
border={
isCurrentPlan
? '1px solid rgba(255, 255, 255, 0.2)'
: isPremium
? 'none'
: '1px solid rgba(255, 255, 255, 0.1)'
} }
color={isPremium ? '#000' : 'rgba(255, 255, 255, 0.9)'}
border={isPremium ? 'none' : '1px solid rgba(255, 255, 255, 0.1)'}
fontWeight="bold" fontWeight="bold"
fontSize="md" fontSize="md"
borderRadius="lg"
onClick={() => !isCurrentPlan && handleSubscribe(plan)} onClick={() => !isCurrentPlan && handleSubscribe(plan)}
isDisabled={isCurrentPlan} isDisabled={isCurrentPlan}
cursor={isCurrentPlan ? 'not-allowed' : 'pointer'}
_hover={ _hover={
!isCurrentPlan !isCurrentPlan
? { ? {
transform: 'scale(1.02)', transform: 'translateY(-2px)',
shadow: isPremium shadow: isPremium
? '0 0 30px rgba(212, 175, 55, 0.4)' ? '0 8px 30px rgba(212, 175, 55, 0.4)'
: '0 4px 12px rgba(255, 255, 255, 0.1)', : '0 8px 20px rgba(255, 255, 255, 0.1)',
bg: isPremium
? 'linear-gradient(135deg, #E5C047 0%, #C9A52F 100%)'
: 'rgba(255, 255, 255, 0.08)',
} }
: {} : {}
} }
transition="all 0.3s" _active={
!isCurrentPlan
? {
transform: 'translateY(0)',
}
: {}
}
transition="all 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
> >
{isCurrentPlan ? '当前套餐' : `选择${plan.displayName}`} {isCurrentPlan ? '当前套餐' : `选择${plan.displayName}`}
</Button> </Button>
</Box> </Box>
{/* 功能列表 */} {/* 功能列表 */}
<VStack spacing={5} align="stretch" px={3.5}> <VStack spacing={4} align="stretch" px={2}>
{plan.features.map((feature: any, idx: number) => ( {plan.features.map((feature: any, idx: number) => (
<HStack key={idx} spacing={2.5} align="center"> <Flex key={idx} align="start" gap={3}>
<Flex <Flex
justify="center" justify="center"
align="center" align="center"
flexShrink={0} flexShrink={0}
w={5} w={5}
h={5} h={5}
mt={0.5}
bg={feature.enabled ? (isPremium ? '#D4AF37' : '#00ff88') : 'transparent'} bg={feature.enabled ? (isPremium ? '#D4AF37' : '#00ff88') : 'transparent'}
borderRadius="full" borderRadius="full"
boxShadow={ boxShadow={
feature.enabled feature.enabled
? isPremium ? isPremium
? '0.0625rem 0.0625rem 0.0625rem 0 rgba(212,175,55,0.30) inset, 0 0 0.625rem 0 rgba(212,175,55,0.50) inset' ? '0 0 0 1px rgba(212,175,55,0.30) inset, 0 0 10px rgba(212,175,55,0.50) inset'
: '0.0625rem 0.0625rem 0.0625rem 0 rgba(255,255,255,0.20) inset, 0 0 0.625rem 0 rgba(255,255,255,0.50) inset' : '0 0 0 1px rgba(255,255,255,0.20) inset, 0 0 10px rgba(255,255,255,0.50) inset'
: 'none' : 'none'
} }
> >
<Icon <Icon
as={feature.enabled ? FaCheck : FaTimes} as={feature.enabled ? FaCheck : FaTimes}
color={feature.enabled ? '#000' : 'rgba(255, 255, 255, 0.3)'} color={feature.enabled ? '#000' : 'rgba(255, 255, 255, 0.3)'}
boxSize={5} boxSize={3}
/> />
</Flex> </Flex>
<Text <Text
fontSize="sm" fontSize="sm"
color={feature.enabled ? 'rgba(255, 255, 255, 0.9)' : 'rgba(255, 255, 255, 0.3)'} color={feature.enabled ? 'rgba(255, 255, 255, 0.85)' : 'rgba(255, 255, 255, 0.35)'}
flex={1} flex={1}
fontWeight={feature.enabled && isPremium && idx === 0 ? 'medium' : 'normal'} fontWeight={feature.enabled && isPremium && idx === 0 ? 'semibold' : 'normal'}
lineHeight="1.6"
> >
{feature.name} {feature.name}
{feature.limit && ( {feature.limit && (
<Text as="span" fontSize="xs" color="#D4AF37" ml={1}> <Text as="span" fontSize="xs" color={isPremium ? '#E5C047' : '#00ff88'} ml={1.5} fontWeight="medium">
({feature.limit}) ({feature.limit})
</Text> </Text>
)} )}
</Text> </Text>
</HStack> </Flex>
))} ))}
</VStack> </VStack>
</VStack> </VStack>
@@ -851,13 +888,127 @@ export default function SubscriptionContentNew() {
<ModalCloseButton color="white" /> <ModalCloseButton color="white" />
<ModalBody pb={6}> <ModalBody pb={6}>
{!paymentOrder ? ( {!paymentOrder ? (
<VStack spacing={6}> <VStack spacing={6} align="stretch">
{/* 价格明细 */}
{selectedPlan && priceInfo && (
<Box
p={4}
bg="rgba(255, 255, 255, 0.05)"
borderRadius="lg"
border="1px solid rgba(255, 255, 255, 0.1)"
>
<VStack spacing={3} align="stretch">
<Flex justify="space-between" align="center">
<Text color="rgba(255, 255, 255, 0.7)" fontSize="sm"> <Text color="rgba(255, 255, 255, 0.7)" fontSize="sm">
: {selectedPlan?.displayName} · {selectedCycle === 'monthly' ? '月付' : selectedCycle === 'quarterly' ? '季付' : selectedCycle === 'semiannual' ? '半年付' : '年付'} {selectedPlan.displayName} · {selectedCycle === 'monthly' ? '月付' : selectedCycle === 'quarterly' ? '季付' : selectedCycle === 'semiannual' ? '半年付' : '年付'}
</Text> </Text>
<Text color="#D4AF37" fontSize="3xl" fontWeight="bold"> <Text color="white" fontWeight="medium">
¥{priceInfo?.final_amount || getCurrentPrice(selectedPlan)} ¥{priceInfo.original_price?.toFixed(2) || getCurrentPrice(selectedPlan).toFixed(2)}
</Text> </Text>
</Flex>
{/* 升级抵扣价值 */}
{priceInfo.is_upgrade && priceInfo.remaining_value > 0 && (
<Flex justify="space-between" align="center">
<Text color="rgba(255, 255, 255, 0.7)" fontSize="sm">
</Text>
<Text color="green.400" fontWeight="medium">
-¥{priceInfo.remaining_value.toFixed(2)}
</Text>
</Flex>
)}
{/* 优惠码折扣 */}
{promoCodeApplied && priceInfo.discount_amount > 0 && (
<Flex justify="space-between" align="center">
<HStack spacing={2}>
<Icon as={FaCheck} color="green.400" boxSize={3} />
<Text color="rgba(255, 255, 255, 0.7)" fontSize="sm">
</Text>
</HStack>
<Text color="green.400" fontWeight="medium">
-¥{priceInfo.discount_amount.toFixed(2)}
</Text>
</Flex>
)}
<Divider borderColor="rgba(255, 255, 255, 0.1)" />
<Flex justify="space-between" align="baseline">
<Text fontSize="lg" fontWeight="bold" color="white">:</Text>
<Text fontSize="2xl" fontWeight="bold" color="#D4AF37">
¥{priceInfo.final_amount.toFixed(2)}
</Text>
</Flex>
</VStack>
</Box>
)}
{/* 优惠码输入 */}
{selectedPlan && (
<Box>
<HStack spacing={2}>
<Input
placeholder="输入优惠码(可选)"
value={promoCode}
onChange={(e) => {
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' }}
/>
<Button
bgGradient="linear-gradient(135deg, rgba(138, 43, 226, 0.8), rgba(123, 31, 162, 0.8))"
color="white"
onClick={handleValidatePromoCode}
isLoading={validatingPromo}
isDisabled={!promoCode || promoCodeApplied}
minW="80px"
_hover={{
bgGradient: 'linear-gradient(135deg, rgba(138, 43, 226, 1), rgba(123, 31, 162, 1))',
}}
>
</Button>
</HStack>
{promoCodeError && (
<Text color="red.400" fontSize="sm" mt={2}>
{promoCodeError}
</Text>
)}
{promoCodeApplied && priceInfo && (
<HStack
mt={2}
p={2}
bg="rgba(72, 187, 120, 0.1)"
borderRadius="md"
border="1px solid rgba(72, 187, 120, 0.3)"
>
<Icon as={FaCheck} color="green.400" />
<Text color="green.400" fontSize="sm" fontWeight="medium" flex={1}>
¥{priceInfo.discount_amount.toFixed(2)}
</Text>
<Icon
as={FaTimes}
color="rgba(255, 255, 255, 0.5)"
cursor="pointer"
onClick={handleRemovePromoCode}
_hover={{ color: 'red.400' }}
/>
</HStack>
)}
</Box>
)}
<Button <Button
w="full" w="full"
size="lg" size="lg"
@@ -866,8 +1017,12 @@ export default function SubscriptionContentNew() {
fontWeight="bold" fontWeight="bold"
onClick={handleCreatePaymentOrder} onClick={handleCreatePaymentOrder}
isLoading={loading} isLoading={loading}
isDisabled={!selectedPlan}
_hover={{
bgGradient: 'linear-gradient(135deg, #F4E3A7, #D4AF37)',
}}
> >
</Button> </Button>
</VStack> </VStack>
) : ( ) : (