update pay ui
This commit is contained in:
1176
concept_hierarchy.json
Normal file
1176
concept_hierarchy.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,7 @@ import {
|
|||||||
Input,
|
Input,
|
||||||
Icon,
|
Icon,
|
||||||
Container,
|
Container,
|
||||||
|
useBreakpointValue,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import {
|
import {
|
||||||
FaWeixin,
|
FaWeixin,
|
||||||
@@ -42,6 +43,87 @@ import { useAuth } from '../../contexts/AuthContext';
|
|||||||
import { useSubscriptionEvents } from '../../hooks/useSubscriptionEvents';
|
import { useSubscriptionEvents } from '../../hooks/useSubscriptionEvents';
|
||||||
import { subscriptionConfig, themeColors } from '../../views/Pages/Account/subscription-content';
|
import { subscriptionConfig, themeColors } from '../../views/Pages/Account/subscription-content';
|
||||||
|
|
||||||
|
// 计费周期选择器组件 - 移动端垂直布局(年付在上),桌面端水平布局
|
||||||
|
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 (
|
||||||
|
<Flex
|
||||||
|
direction={{ base: 'column', md: 'row' }}
|
||||||
|
gap={3}
|
||||||
|
p={2}
|
||||||
|
bg="rgba(255, 255, 255, 0.03)"
|
||||||
|
borderRadius="xl"
|
||||||
|
border="1px solid"
|
||||||
|
borderColor="rgba(255, 255, 255, 0.1)"
|
||||||
|
backdropFilter="blur(10px)"
|
||||||
|
justify="center"
|
||||||
|
align="center"
|
||||||
|
w={{ base: 'full', md: 'auto' }}
|
||||||
|
maxW={{ base: '320px', md: 'none' }}
|
||||||
|
mx="auto"
|
||||||
|
>
|
||||||
|
{displayOptions.map((option: any) => (
|
||||||
|
<Box key={option.cycleKey} position="relative" w={{ base: 'full', md: 'auto' }}>
|
||||||
|
{option.discountPercent > 0 && (
|
||||||
|
<Badge
|
||||||
|
position="absolute"
|
||||||
|
top={{ base: '50%', md: '-10px' }}
|
||||||
|
right={{ base: '10px', md: '-10px' }}
|
||||||
|
transform={{ base: 'translateY(-50%)', md: 'none' }}
|
||||||
|
colorScheme="red"
|
||||||
|
fontSize="xs"
|
||||||
|
px={2}
|
||||||
|
py={1}
|
||||||
|
borderRadius="full"
|
||||||
|
fontWeight="bold"
|
||||||
|
zIndex={1}
|
||||||
|
>
|
||||||
|
省{option.discountPercent}%
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
size="lg"
|
||||||
|
w={{ base: 'full', md: 'auto' }}
|
||||||
|
px={6}
|
||||||
|
py={6}
|
||||||
|
borderRadius="lg"
|
||||||
|
bg={selectedCycle === option.cycleKey ? 'linear-gradient(135deg, #D4AF37, #B8941F)' : 'transparent'}
|
||||||
|
color={selectedCycle === option.cycleKey ? '#000' : '#fff'}
|
||||||
|
border="1px solid"
|
||||||
|
borderColor={selectedCycle === option.cycleKey ? 'rgba(212, 175, 55, 0.3)' : 'rgba(255, 255, 255, 0.1)'}
|
||||||
|
onClick={() => onSelectCycle(option.cycleKey)}
|
||||||
|
_hover={{
|
||||||
|
transform: 'translateY(-2px)',
|
||||||
|
borderColor: 'rgba(212, 175, 55, 0.5)',
|
||||||
|
shadow: selectedCycle === option.cycleKey
|
||||||
|
? '0 0 20px rgba(212, 175, 55, 0.3)'
|
||||||
|
: '0 4px 12px rgba(0, 0, 0, 0.5)',
|
||||||
|
}}
|
||||||
|
transition="all 0.3s"
|
||||||
|
fontWeight="bold"
|
||||||
|
justifyContent={{ base: 'flex-start', md: 'center' }}
|
||||||
|
pl={{ base: 6, md: 6 }}
|
||||||
|
>
|
||||||
|
{option.label}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default function SubscriptionContentNew() {
|
export default function SubscriptionContentNew() {
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
const subscriptionEvents = useSubscriptionEvents({
|
const subscriptionEvents = useSubscriptionEvents({
|
||||||
@@ -51,7 +133,7 @@ export default function SubscriptionContentNew() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const [selectedCycle, setSelectedCycle] = useState('monthly');
|
const [selectedCycle, setSelectedCycle] = useState('yearly');
|
||||||
const [selectedPlan, setSelectedPlan] = useState(null);
|
const [selectedPlan, setSelectedPlan] = useState(null);
|
||||||
const [subscriptionPlans, setSubscriptionPlans] = useState([]);
|
const [subscriptionPlans, setSubscriptionPlans] = useState([]);
|
||||||
const [priceInfo, setPriceInfo] = useState(null);
|
const [priceInfo, setPriceInfo] = useState(null);
|
||||||
@@ -751,61 +833,11 @@ export default function SubscriptionContentNew() {
|
|||||||
选择计费周期 · 时长越长优惠越大
|
选择计费周期 · 时长越长优惠越大
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<HStack
|
<CycleSelector
|
||||||
spacing={3}
|
options={getMergedPlans()[1]?.pricingOptions || []}
|
||||||
p={2}
|
selectedCycle={selectedCycle}
|
||||||
bg="rgba(255, 255, 255, 0.03)"
|
onSelectCycle={setSelectedCycle}
|
||||||
borderRadius="xl"
|
/>
|
||||||
border="1px solid"
|
|
||||||
borderColor="rgba(255, 255, 255, 0.1)"
|
|
||||||
backdropFilter="blur(10px)"
|
|
||||||
flexWrap="wrap"
|
|
||||||
justify="center"
|
|
||||||
>
|
|
||||||
{getMergedPlans()[1]?.pricingOptions?.map((option: any, index: number) => (
|
|
||||||
<Box key={index} position="relative">
|
|
||||||
{option.discountPercent > 0 && (
|
|
||||||
<Badge
|
|
||||||
position="absolute"
|
|
||||||
top="-10px"
|
|
||||||
right="-10px"
|
|
||||||
colorScheme="red"
|
|
||||||
fontSize="xs"
|
|
||||||
px={2}
|
|
||||||
py={1}
|
|
||||||
borderRadius="full"
|
|
||||||
fontWeight="bold"
|
|
||||||
zIndex={1}
|
|
||||||
>
|
|
||||||
省{option.discountPercent}%
|
|
||||||
</Badge>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Button
|
|
||||||
size="lg"
|
|
||||||
px={6}
|
|
||||||
py={6}
|
|
||||||
borderRadius="lg"
|
|
||||||
bg={selectedCycle === option.cycleKey ? 'linear-gradient(135deg, #D4AF37, #B8941F)' : 'transparent'}
|
|
||||||
color={selectedCycle === option.cycleKey ? '#000' : '#fff'}
|
|
||||||
border="1px solid"
|
|
||||||
borderColor={selectedCycle === option.cycleKey ? 'rgba(212, 175, 55, 0.3)' : 'rgba(255, 255, 255, 0.1)'}
|
|
||||||
onClick={() => setSelectedCycle(option.cycleKey)}
|
|
||||||
_hover={{
|
|
||||||
transform: 'translateY(-2px)',
|
|
||||||
borderColor: 'rgba(212, 175, 55, 0.5)',
|
|
||||||
shadow: selectedCycle === option.cycleKey
|
|
||||||
? '0 0 20px rgba(212, 175, 55, 0.3)'
|
|
||||||
: '0 4px 12px rgba(0, 0, 0, 0.5)',
|
|
||||||
}}
|
|
||||||
transition="all 0.3s"
|
|
||||||
fontWeight="bold"
|
|
||||||
>
|
|
||||||
{option.label}
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
))}
|
|
||||||
</HStack>
|
|
||||||
|
|
||||||
{(() => {
|
{(() => {
|
||||||
const currentOption = getMergedPlans()[1]?.pricingOptions?.find(
|
const currentOption = getMergedPlans()[1]?.pricingOptions?.find(
|
||||||
|
|||||||
Reference in New Issue
Block a user