优惠码Bug修复
This commit is contained in:
@@ -79,7 +79,8 @@ export default function SubscriptionContent() {
|
||||
// State
|
||||
const [subscriptionPlans, setSubscriptionPlans] = useState([]);
|
||||
const [selectedPlan, setSelectedPlan] = useState(null);
|
||||
const [selectedCycle, setSelectedCycle] = useState('monthly');
|
||||
const [selectedCycle, setSelectedCycle] = useState('monthly'); // 保持向后兼容,默认月付
|
||||
const [selectedCycleOption, setSelectedCycleOption] = useState(null); // 当前选中的pricing_option对象
|
||||
const [paymentOrder, setPaymentOrder] = useState(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [paymentCountdown, setPaymentCountdown] = useState(0);
|
||||
@@ -587,15 +588,62 @@ export default function SubscriptionContent() {
|
||||
|
||||
const getCurrentPrice = (plan) => {
|
||||
if (!plan) return 0;
|
||||
|
||||
// 如果有pricing_options,使用它
|
||||
if (plan.pricing_options && plan.pricing_options.length > 0) {
|
||||
// 查找当前选中的周期选项
|
||||
const option = plan.pricing_options.find(opt =>
|
||||
opt.cycle_key === selectedCycle ||
|
||||
(selectedCycle === 'monthly' && opt.months === 1) ||
|
||||
(selectedCycle === 'yearly' && opt.months === 12)
|
||||
);
|
||||
return option ? option.price : plan.monthly_price;
|
||||
}
|
||||
|
||||
// 向后兼容:回退到monthly_price/yearly_price
|
||||
return selectedCycle === 'monthly' ? plan.monthly_price : plan.yearly_price;
|
||||
};
|
||||
|
||||
const getSavingsText = (plan) => {
|
||||
if (!plan || selectedCycle !== 'yearly') return null;
|
||||
const yearlyTotal = plan.monthly_price * 12;
|
||||
const savings = yearlyTotal - plan.yearly_price;
|
||||
const percentage = Math.round((savings / yearlyTotal) * 100);
|
||||
return `年付节省 ${percentage}%`;
|
||||
if (!plan) return null;
|
||||
|
||||
// 如果有pricing_options,从中查找discount_percent
|
||||
if (plan.pricing_options && plan.pricing_options.length > 0) {
|
||||
const currentOption = plan.pricing_options.find(opt =>
|
||||
opt.cycle_key === selectedCycle ||
|
||||
(selectedCycle === 'monthly' && opt.months === 1) ||
|
||||
(selectedCycle === 'yearly' && opt.months === 12)
|
||||
);
|
||||
|
||||
if (currentOption && currentOption.discount_percent) {
|
||||
return `立减 ${currentOption.discount_percent}%`;
|
||||
}
|
||||
|
||||
// 如果没有discount_percent,尝试计算节省金额
|
||||
if (currentOption && currentOption.months > 1) {
|
||||
const monthlyOption = plan.pricing_options.find(opt => opt.months === 1);
|
||||
if (monthlyOption) {
|
||||
const expectedTotal = monthlyOption.price * currentOption.months;
|
||||
const savings = expectedTotal - currentOption.price;
|
||||
if (savings > 0) {
|
||||
const percentage = Math.round((savings / expectedTotal) * 100);
|
||||
return `${currentOption.label || `${currentOption.months}个月`}节省 ${percentage}%`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 向后兼容:计算年付节省
|
||||
if (selectedCycle === 'yearly') {
|
||||
const yearlyTotal = plan.monthly_price * 12;
|
||||
const savings = yearlyTotal - plan.yearly_price;
|
||||
if (savings > 0) {
|
||||
const percentage = Math.round((savings / yearlyTotal) * 100);
|
||||
return `年付节省 ${percentage}%`;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
// 获取按钮文字(根据用户当前订阅判断是升级还是新订阅)
|
||||
@@ -717,26 +765,39 @@ export default function SubscriptionContent() {
|
||||
p={1}
|
||||
border="1px solid"
|
||||
borderColor={borderColor}
|
||||
flexWrap="wrap"
|
||||
>
|
||||
<Button
|
||||
variant={selectedCycle === 'monthly' ? 'solid' : 'ghost'}
|
||||
colorScheme={selectedCycle === 'monthly' ? 'blue' : 'gray'}
|
||||
size="md"
|
||||
onClick={() => setSelectedCycle('monthly')}
|
||||
borderRadius="md"
|
||||
>
|
||||
按月付费
|
||||
</Button>
|
||||
<Button
|
||||
variant={selectedCycle === 'yearly' ? 'solid' : 'ghost'}
|
||||
colorScheme={selectedCycle === 'yearly' ? 'blue' : 'gray'}
|
||||
size="md"
|
||||
onClick={() => setSelectedCycle('yearly')}
|
||||
borderRadius="md"
|
||||
>
|
||||
按年付费
|
||||
<Badge ml={2} colorScheme="red" fontSize="xs">省20%</Badge>
|
||||
</Button>
|
||||
{(() => {
|
||||
// 获取第一个套餐的pricing_options作为周期选项(假设所有套餐都有相同的周期)
|
||||
const firstPlan = subscriptionPlans.find(plan => plan.pricing_options);
|
||||
const cycleOptions = firstPlan?.pricing_options || [
|
||||
{ cycle_key: 'monthly', label: '按月付费', months: 1 },
|
||||
{ cycle_key: 'yearly', label: '按年付费', months: 12, discount_percent: 20 }
|
||||
];
|
||||
|
||||
return cycleOptions.map((option, index) => {
|
||||
const cycleKey = option.cycle_key || (option.months === 1 ? 'monthly' : option.months === 12 ? 'yearly' : `${option.months}months`);
|
||||
const isSelected = selectedCycle === cycleKey;
|
||||
|
||||
return (
|
||||
<Button
|
||||
key={index}
|
||||
variant={isSelected ? 'solid' : 'ghost'}
|
||||
colorScheme={isSelected ? 'blue' : 'gray'}
|
||||
size="md"
|
||||
onClick={() => setSelectedCycle(cycleKey)}
|
||||
borderRadius="md"
|
||||
>
|
||||
{option.label || `${option.months}个月`}
|
||||
{option.discount_percent && (
|
||||
<Badge ml={2} colorScheme="red" fontSize="xs">
|
||||
省{option.discount_percent}%
|
||||
</Badge>
|
||||
)}
|
||||
</Button>
|
||||
);
|
||||
});
|
||||
})()}
|
||||
</HStack>
|
||||
</Flex>
|
||||
|
||||
@@ -911,7 +972,22 @@ export default function SubscriptionContent() {
|
||||
{getCurrentPrice(plan).toFixed(0)}
|
||||
</Text>
|
||||
<Text fontSize="sm" color={secondaryText}>
|
||||
/{selectedCycle === 'monthly' ? '月' : '年'}
|
||||
{(() => {
|
||||
if (plan.pricing_options) {
|
||||
const option = plan.pricing_options.find(opt =>
|
||||
opt.cycle_key === selectedCycle ||
|
||||
(selectedCycle === 'monthly' && opt.months === 1) ||
|
||||
(selectedCycle === 'yearly' && opt.months === 12)
|
||||
);
|
||||
if (option) {
|
||||
// 如果months是1,显示"/月";如果是12,显示"/年";否则显示周期label
|
||||
if (option.months === 1) return '/月';
|
||||
if (option.months === 12) return '/年';
|
||||
return `/${option.months}个月`;
|
||||
}
|
||||
}
|
||||
return selectedCycle === 'monthly' ? '/月' : '/年';
|
||||
})()}
|
||||
</Text>
|
||||
</HStack>
|
||||
</Flex>
|
||||
@@ -1091,7 +1167,7 @@ export default function SubscriptionContent() {
|
||||
align="center"
|
||||
>
|
||||
<Text fontWeight="semibold" color={textColor}>
|
||||
可以在月付和年付之间切换吗?
|
||||
升级或切换套餐时,原套餐的费用怎么办?
|
||||
</Text>
|
||||
<Icon
|
||||
as={openFaqIndex === 2 ? FaChevronUp : FaChevronDown}
|
||||
@@ -1100,14 +1176,28 @@ export default function SubscriptionContent() {
|
||||
</Flex>
|
||||
<Collapse in={openFaqIndex === 2}>
|
||||
<Box p={4} pt={0} color={secondaryText}>
|
||||
<Text>
|
||||
可以。您可以随时更改计费周期。如果从月付切换到年付,系统会计算剩余价值并应用到新的订阅中。年付用户可享受20%的折扣优惠。
|
||||
</Text>
|
||||
<VStack spacing={2} align="stretch">
|
||||
<Text>
|
||||
当您升级套餐或切换计费周期时,系统会自动计算您当前订阅的剩余价值并用于抵扣新套餐的费用。
|
||||
</Text>
|
||||
<Text fontWeight="medium" fontSize="sm">
|
||||
计算方式:
|
||||
</Text>
|
||||
<Text fontSize="sm" pl={3}>
|
||||
• <strong>剩余价值</strong> = 原套餐价格 × (剩余天数 / 总天数)
|
||||
</Text>
|
||||
<Text fontSize="sm" pl={3}>
|
||||
• <strong>实付金额</strong> = 新套餐价格 - 剩余价值 - 优惠码折扣
|
||||
</Text>
|
||||
<Text fontSize="sm" color="blue.600" mt={2}>
|
||||
例如:您购买了年付Pro版(¥999),使用了180天后升级到Max版(¥1999/年),剩余价值约¥500将自动抵扣,实付约¥1499。
|
||||
</Text>
|
||||
</VStack>
|
||||
</Box>
|
||||
</Collapse>
|
||||
</Box>
|
||||
|
||||
{/* FAQ 4 */}
|
||||
{/* FAQ 4 - 原FAQ 3 */}
|
||||
<Box
|
||||
border="1px solid"
|
||||
borderColor={borderColor}
|
||||
@@ -1125,7 +1215,7 @@ export default function SubscriptionContent() {
|
||||
align="center"
|
||||
>
|
||||
<Text fontWeight="semibold" color={textColor}>
|
||||
是否提供退款?
|
||||
可以在月付和年付之间切换吗?
|
||||
</Text>
|
||||
<Icon
|
||||
as={openFaqIndex === 3 ? FaChevronUp : FaChevronDown}
|
||||
@@ -1135,13 +1225,13 @@ export default function SubscriptionContent() {
|
||||
<Collapse in={openFaqIndex === 3}>
|
||||
<Box p={4} pt={0} color={secondaryText}>
|
||||
<Text>
|
||||
我们提供7天无理由退款保证。如果您在订阅后7天内对服务不满意,可以申请全额退款。超过7天后,我们将根据实际使用情况进行评估。
|
||||
可以。您可以随时更改计费周期。如果从月付切换到年付,系统会计算剩余价值并应用到新的订阅中。年付用户可享受20%的折扣优惠。
|
||||
</Text>
|
||||
</Box>
|
||||
</Collapse>
|
||||
</Box>
|
||||
|
||||
{/* FAQ 5 */}
|
||||
{/* FAQ 5 - 原FAQ 4 */}
|
||||
<Box
|
||||
border="1px solid"
|
||||
borderColor={borderColor}
|
||||
@@ -1159,7 +1249,7 @@ export default function SubscriptionContent() {
|
||||
align="center"
|
||||
>
|
||||
<Text fontWeight="semibold" color={textColor}>
|
||||
Pro版和Max版有什么区别?
|
||||
是否提供退款?
|
||||
</Text>
|
||||
<Icon
|
||||
as={openFaqIndex === 4 ? FaChevronUp : FaChevronDown}
|
||||
@@ -1167,6 +1257,40 @@ export default function SubscriptionContent() {
|
||||
/>
|
||||
</Flex>
|
||||
<Collapse in={openFaqIndex === 4}>
|
||||
<Box p={4} pt={0} color={secondaryText}>
|
||||
<Text>
|
||||
我们提供7天无理由退款保证。如果您在订阅后7天内对服务不满意,可以申请全额退款。超过7天后,我们将根据实际使用情况进行评估。
|
||||
</Text>
|
||||
</Box>
|
||||
</Collapse>
|
||||
</Box>
|
||||
|
||||
{/* FAQ 6 - 原FAQ 5 */}
|
||||
<Box
|
||||
border="1px solid"
|
||||
borderColor={borderColor}
|
||||
borderRadius="lg"
|
||||
overflow="hidden"
|
||||
>
|
||||
<Flex
|
||||
p={4}
|
||||
cursor="pointer"
|
||||
onClick={() => setOpenFaqIndex(openFaqIndex === 5 ? null : 5)}
|
||||
bg={openFaqIndex === 5 ? bgAccent : 'transparent'}
|
||||
_hover={{ bg: bgAccent }}
|
||||
transition="all 0.2s"
|
||||
justify="space-between"
|
||||
align="center"
|
||||
>
|
||||
<Text fontWeight="semibold" color={textColor}>
|
||||
Pro版和Max版有什么区别?
|
||||
</Text>
|
||||
<Icon
|
||||
as={openFaqIndex === 5 ? FaChevronUp : FaChevronDown}
|
||||
color={textColor}
|
||||
/>
|
||||
</Flex>
|
||||
<Collapse in={openFaqIndex === 5}>
|
||||
<Box p={4} pt={0} color={secondaryText}>
|
||||
<Text>
|
||||
Pro版适合个人专业用户,提供高级图表、历史数据分析等功能。Max版则是为团队和企业设计,额外提供实时数据推送、API访问、无限制的数据存储和团队协作功能,并享有优先技术支持。
|
||||
@@ -1220,7 +1344,19 @@ export default function SubscriptionContent() {
|
||||
</Flex>
|
||||
<Flex justify="space-between">
|
||||
<Text color={secondaryText}>计费周期:</Text>
|
||||
<Text>{selectedCycle === 'monthly' ? '按月付费' : '按年付费'}</Text>
|
||||
<Text>
|
||||
{(() => {
|
||||
if (selectedPlan?.pricing_options) {
|
||||
const option = selectedPlan.pricing_options.find(opt =>
|
||||
opt.cycle_key === selectedCycle ||
|
||||
(selectedCycle === 'monthly' && opt.months === 1) ||
|
||||
(selectedCycle === 'yearly' && opt.months === 12)
|
||||
);
|
||||
return option?.label || (selectedCycle === 'monthly' ? '按月付费' : '按年付费');
|
||||
}
|
||||
return selectedCycle === 'monthly' ? '按月付费' : '按年付费';
|
||||
})()}
|
||||
</Text>
|
||||
</Flex>
|
||||
|
||||
{/* 价格明细 */}
|
||||
|
||||
Reference in New Issue
Block a user