feat: 订阅支付弹窗添加会员协议确认功能
- SubscriptionContentNew.tsx: 添加协议确认 Checkbox 和链接 - SubscriptionContent.js: 同步添加协议确认功能(旧版组件) - 根据套餐类型动态显示 PRO/MAX 会员服务协议链接 - 未勾选协议时点击支付按钮显示 Toast 提示 - 切换套餐时自动重置协议勾选状态 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -32,6 +32,8 @@ import {
|
||||
Input,
|
||||
InputGroup,
|
||||
InputRightElement,
|
||||
Checkbox,
|
||||
Link as ChakraLink,
|
||||
} from '@chakra-ui/react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { logger } from '../../utils/logger';
|
||||
@@ -55,6 +57,12 @@ import {
|
||||
} from 'react-icons/fa';
|
||||
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',
|
||||
};
|
||||
|
||||
export default function SubscriptionContent() {
|
||||
// Auth context
|
||||
const { user } = useAuth();
|
||||
@@ -97,6 +105,9 @@ export default function SubscriptionContent() {
|
||||
const [validatingPromo, setValidatingPromo] = useState(false);
|
||||
const [priceInfo, setPriceInfo] = useState(null); // 价格信息(包含升级计算)
|
||||
|
||||
// 会员协议确认状态
|
||||
const [agreementChecked, setAgreementChecked] = useState(false);
|
||||
|
||||
// 加载订阅套餐数据
|
||||
useEffect(() => {
|
||||
fetchSubscriptionPlans();
|
||||
@@ -286,6 +297,9 @@ export default function SubscriptionContent() {
|
||||
|
||||
setSelectedPlan(plan);
|
||||
|
||||
// 切换套餐时重置协议勾选状态
|
||||
setAgreementChecked(false);
|
||||
|
||||
// 计算价格(包含升级判断)
|
||||
await calculatePrice(plan, selectedCycle, promoCodeApplied ? promoCode : null);
|
||||
|
||||
@@ -1603,11 +1617,45 @@ export default function SubscriptionContent() {
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* 会员协议确认 */}
|
||||
<Checkbox
|
||||
isChecked={agreementChecked}
|
||||
onChange={(e) => setAgreementChecked(e.target.checked)}
|
||||
colorScheme="green"
|
||||
size="md"
|
||||
>
|
||||
<Text fontSize="sm" color={secondaryText}>
|
||||
我已阅读并同意
|
||||
<ChakraLink
|
||||
href={AGREEMENT_URLS[selectedPlan?.name?.toLowerCase()] || AGREEMENT_URLS.pro}
|
||||
isExternal
|
||||
color="blue.500"
|
||||
textDecoration="underline"
|
||||
mx={1}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
《{selectedPlan?.name?.toLowerCase() === 'max' ? 'MAX' : 'PRO'}会员服务协议》
|
||||
</ChakraLink>
|
||||
</Text>
|
||||
</Checkbox>
|
||||
|
||||
<Button
|
||||
colorScheme="green"
|
||||
size="lg"
|
||||
leftIcon={<Icon as={FaWeixin} />}
|
||||
onClick={handleCreateOrder}
|
||||
onClick={() => {
|
||||
if (!agreementChecked) {
|
||||
toast({
|
||||
title: '请先阅读并同意会员服务协议',
|
||||
status: 'warning',
|
||||
duration: 3000,
|
||||
isClosable: true,
|
||||
position: 'top',
|
||||
});
|
||||
return;
|
||||
}
|
||||
handleCreateOrder();
|
||||
}}
|
||||
isLoading={loading}
|
||||
loadingText="创建订单中..."
|
||||
isDisabled={!selectedPlan}
|
||||
|
||||
@@ -23,6 +23,8 @@ import {
|
||||
Icon,
|
||||
Container,
|
||||
useBreakpointValue,
|
||||
Checkbox,
|
||||
Link as ChakraLink,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FaWeixin,
|
||||
@@ -46,6 +48,12 @@ 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[];
|
||||
@@ -154,6 +162,9 @@ export default function SubscriptionContentNew() {
|
||||
|
||||
const [openFaqIndex, setOpenFaqIndex] = useState(null);
|
||||
|
||||
// 会员协议确认状态
|
||||
const [agreementChecked, setAgreementChecked] = useState(false);
|
||||
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const toast = useToast();
|
||||
|
||||
@@ -418,6 +429,10 @@ export default function SubscriptionContentNew() {
|
||||
);
|
||||
|
||||
setSelectedPlan(plan);
|
||||
|
||||
// 切换套餐时重置协议勾选状态
|
||||
setAgreementChecked(false);
|
||||
|
||||
await calculatePrice(plan, selectedCycle, promoCodeApplied ? promoCode : null);
|
||||
onOpen();
|
||||
};
|
||||
@@ -1607,6 +1622,28 @@ export default function SubscriptionContentNew() {
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* 会员协议确认 */}
|
||||
<Checkbox
|
||||
isChecked={agreementChecked}
|
||||
onChange={(e) => setAgreementChecked(e.target.checked)}
|
||||
colorScheme="green"
|
||||
size="md"
|
||||
>
|
||||
<Text fontSize="sm" color="rgba(255, 255, 255, 0.7)">
|
||||
我已阅读并同意
|
||||
<ChakraLink
|
||||
href={AGREEMENT_URLS[(selectedPlan as any)?.name?.toLowerCase()] || AGREEMENT_URLS.pro}
|
||||
isExternal
|
||||
color="#3182CE"
|
||||
textDecoration="underline"
|
||||
mx={1}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
《{(selectedPlan as any)?.name?.toLowerCase() === 'max' ? 'MAX' : 'PRO'}会员服务协议》
|
||||
</ChakraLink>
|
||||
</Text>
|
||||
</Checkbox>
|
||||
|
||||
<Button
|
||||
w="full"
|
||||
size="lg"
|
||||
@@ -1615,7 +1652,19 @@ export default function SubscriptionContentNew() {
|
||||
: 'linear-gradient(135deg, #07C160, #059048)'}
|
||||
color="white"
|
||||
fontWeight="bold"
|
||||
onClick={handleCreatePaymentOrder}
|
||||
onClick={() => {
|
||||
if (!agreementChecked) {
|
||||
toast({
|
||||
title: '请先阅读并同意会员服务协议',
|
||||
status: 'warning',
|
||||
duration: 3000,
|
||||
isClosable: true,
|
||||
position: 'top',
|
||||
});
|
||||
return;
|
||||
}
|
||||
handleCreatePaymentOrder();
|
||||
}}
|
||||
isLoading={loading}
|
||||
isDisabled={!selectedPlan}
|
||||
leftIcon={paymentMethod === 'alipay'
|
||||
|
||||
Reference in New Issue
Block a user