update pay ui
This commit is contained in:
@@ -36,7 +36,9 @@ import {
|
||||
FaTimes,
|
||||
FaChevronDown,
|
||||
FaChevronUp,
|
||||
FaExternalLinkAlt,
|
||||
} from 'react-icons/fa';
|
||||
import { AlipayCircleOutlined } from '@ant-design/icons';
|
||||
|
||||
import { logger } from '../../utils/logger';
|
||||
import { useAuth } from '../../contexts/AuthContext';
|
||||
@@ -147,6 +149,7 @@ export default function SubscriptionContentNew() {
|
||||
const [paymentCountdown, setPaymentCountdown] = useState(300);
|
||||
const [autoCheckInterval, setAutoCheckInterval] = useState(null);
|
||||
const [forceUpdating, setForceUpdating] = useState(false);
|
||||
const [paymentMethod, setPaymentMethod] = useState<'wechat' | 'alipay'>('wechat'); // 支付方式
|
||||
|
||||
const [openFaqIndex, setOpenFaqIndex] = useState(null);
|
||||
|
||||
@@ -392,14 +395,21 @@ export default function SubscriptionContentNew() {
|
||||
}
|
||||
}
|
||||
|
||||
const paymentMethodName = paymentMethod === 'alipay' ? 'alipay' : 'wechat_pay';
|
||||
|
||||
subscriptionEvents.trackPaymentInitiated({
|
||||
planName: selectedPlan.name,
|
||||
paymentMethod: 'wechat_pay',
|
||||
paymentMethod: paymentMethodName,
|
||||
amount: price,
|
||||
billingCycle: selectedCycle,
|
||||
});
|
||||
|
||||
const response = await fetch('/api/payment/create-order', {
|
||||
// 根据支付方式选择不同的 API
|
||||
const apiUrl = paymentMethod === 'alipay'
|
||||
? '/api/payment/alipay/create-order'
|
||||
: '/api/payment/create-order';
|
||||
|
||||
const response = await fetch(apiUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -415,28 +425,54 @@ export default function SubscriptionContentNew() {
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
if (data.success) {
|
||||
setPaymentOrder(data.data);
|
||||
setPaymentCountdown(30 * 60); // 30分钟
|
||||
startAutoPaymentCheck(data.data.id);
|
||||
if (paymentMethod === 'alipay') {
|
||||
// 支付宝:跳转到支付页面
|
||||
if (data.data.pay_url) {
|
||||
setPaymentOrder(data.data);
|
||||
setPaymentCountdown(30 * 60);
|
||||
startAutoPaymentCheck(data.data.id, 'alipay');
|
||||
|
||||
toast({
|
||||
title: '订单创建成功',
|
||||
description: '请使用微信扫描二维码完成支付',
|
||||
status: 'success',
|
||||
duration: 3000,
|
||||
isClosable: true,
|
||||
});
|
||||
toast({
|
||||
title: '订单创建成功',
|
||||
description: '正在跳转到支付宝支付页面...',
|
||||
status: 'success',
|
||||
duration: 3000,
|
||||
isClosable: true,
|
||||
});
|
||||
|
||||
// 延迟跳转,让用户看到提示
|
||||
setTimeout(() => {
|
||||
window.open(data.data.pay_url, '_blank');
|
||||
}, 500);
|
||||
} else {
|
||||
throw new Error('支付链接获取失败');
|
||||
}
|
||||
} else {
|
||||
// 微信:显示二维码
|
||||
setPaymentOrder(data.data);
|
||||
setPaymentCountdown(30 * 60);
|
||||
startAutoPaymentCheck(data.data.id, 'wechat');
|
||||
|
||||
toast({
|
||||
title: '订单创建成功',
|
||||
description: '请使用微信扫描二维码完成支付',
|
||||
status: 'success',
|
||||
duration: 3000,
|
||||
isClosable: true,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
throw new Error(data.message || '创建订单失败');
|
||||
throw new Error(data.error || data.message || '创建订单失败');
|
||||
}
|
||||
} else {
|
||||
throw new Error('网络请求失败');
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(errorData.error || '网络请求失败');
|
||||
}
|
||||
} catch (error: any) {
|
||||
subscriptionEvents.trackPaymentFailed(
|
||||
{
|
||||
planName: selectedPlan.name,
|
||||
paymentMethod: 'wechat_pay',
|
||||
paymentMethod: paymentMethod === 'alipay' ? 'alipay' : 'wechat_pay',
|
||||
amount: getCurrentPrice(selectedPlan),
|
||||
},
|
||||
error.message
|
||||
@@ -454,25 +490,30 @@ export default function SubscriptionContentNew() {
|
||||
}
|
||||
};
|
||||
|
||||
const startAutoPaymentCheck = (orderId: string) => {
|
||||
const startAutoPaymentCheck = (orderId: string, method: 'wechat' | 'alipay' = 'wechat') => {
|
||||
// 根据支付方式选择不同的状态查询 API
|
||||
const statusApiUrl = method === 'alipay'
|
||||
? `/api/payment/alipay/order/${orderId}/status`
|
||||
: `/api/payment/order/${orderId}/status`;
|
||||
|
||||
const checkInterval = setInterval(async () => {
|
||||
try {
|
||||
const response = await fetch(`/api/payment/order/${orderId}/status`, {
|
||||
const response = await fetch(statusApiUrl, {
|
||||
credentials: 'include',
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
if (data.success && data.data.status === 'paid') {
|
||||
if (data.success && (data.data.status === 'paid' || data.payment_success)) {
|
||||
clearInterval(checkInterval);
|
||||
setAutoCheckInterval(null);
|
||||
|
||||
subscriptionEvents.trackPaymentSuccessful({
|
||||
planName: selectedPlan?.name,
|
||||
paymentMethod: 'wechat_pay',
|
||||
paymentMethod: method === 'alipay' ? 'alipay' : 'wechat_pay',
|
||||
amount: paymentOrder?.amount,
|
||||
orderId: orderId,
|
||||
transactionId: data.data.transaction_id,
|
||||
transactionId: data.data.transaction_id || data.data.alipay_trade_no,
|
||||
});
|
||||
|
||||
toast({
|
||||
@@ -500,13 +541,19 @@ export default function SubscriptionContentNew() {
|
||||
|
||||
setForceUpdating(true);
|
||||
try {
|
||||
const response = await fetch(`/api/payment/order/${paymentOrder.order_id}/status`, {
|
||||
// 根据订单的支付方式选择不同的查询 API
|
||||
const orderPaymentMethod = (paymentOrder as any).payment_method || paymentMethod;
|
||||
const statusApiUrl = orderPaymentMethod === 'alipay'
|
||||
? `/api/payment/alipay/order/${(paymentOrder as any).id}/status`
|
||||
: `/api/payment/order/${(paymentOrder as any).id}/status`;
|
||||
|
||||
const response = await fetch(statusApiUrl, {
|
||||
credentials: 'include',
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
if (data.success && data.data.status === 'paid') {
|
||||
if (data.success && (data.data.status === 'paid' || data.payment_success)) {
|
||||
toast({
|
||||
title: '支付成功!',
|
||||
description: '您的订阅已激活',
|
||||
@@ -540,6 +587,13 @@ export default function SubscriptionContentNew() {
|
||||
}
|
||||
};
|
||||
|
||||
// 重新打开支付宝支付页面
|
||||
const handleReopenAlipay = () => {
|
||||
if (paymentOrder && (paymentOrder as any).pay_url) {
|
||||
window.open((paymentOrder as any).pay_url, '_blank');
|
||||
}
|
||||
};
|
||||
|
||||
// 合并数据库数据和前端配置
|
||||
const getMergedPlans = () => {
|
||||
// 如果数据库还没有加载数据,使用静态配置
|
||||
@@ -1176,11 +1230,60 @@ export default function SubscriptionContentNew() {
|
||||
<Modal isOpen={isOpen} onClose={onClose} size="lg" isCentered>
|
||||
<ModalOverlay bg="rgba(0, 0, 0, 0.8)" backdropFilter="blur(10px)" />
|
||||
<ModalContent bg="#1e1e1e" borderRadius="2xl" border="1px solid rgba(255, 255, 255, 0.1)">
|
||||
<ModalHeader color="white">微信支付</ModalHeader>
|
||||
<ModalHeader color="white">
|
||||
{paymentMethod === 'alipay' ? '支付宝支付' : '微信支付'}
|
||||
</ModalHeader>
|
||||
<ModalCloseButton color="white" />
|
||||
<ModalBody pb={6}>
|
||||
{!paymentOrder ? (
|
||||
<VStack spacing={6} align="stretch">
|
||||
{/* 支付方式选择 */}
|
||||
<Box>
|
||||
<Text color="rgba(255, 255, 255, 0.7)" fontSize="sm" mb={3}>
|
||||
选择支付方式
|
||||
</Text>
|
||||
<HStack spacing={3}>
|
||||
<Button
|
||||
flex={1}
|
||||
h="60px"
|
||||
bg={paymentMethod === 'wechat' ? 'rgba(7, 193, 96, 0.15)' : 'rgba(255, 255, 255, 0.05)'}
|
||||
border="2px solid"
|
||||
borderColor={paymentMethod === 'wechat' ? '#07C160' : 'rgba(255, 255, 255, 0.1)'}
|
||||
borderRadius="xl"
|
||||
onClick={() => setPaymentMethod('wechat')}
|
||||
_hover={{
|
||||
borderColor: paymentMethod === 'wechat' ? '#07C160' : 'rgba(255, 255, 255, 0.3)',
|
||||
bg: paymentMethod === 'wechat' ? 'rgba(7, 193, 96, 0.2)' : 'rgba(255, 255, 255, 0.08)',
|
||||
}}
|
||||
transition="all 0.2s"
|
||||
>
|
||||
<HStack spacing={3}>
|
||||
<Icon as={FaWeixin} color="#07C160" boxSize={6} />
|
||||
<Text color="white" fontWeight="medium">微信支付</Text>
|
||||
</HStack>
|
||||
</Button>
|
||||
<Button
|
||||
flex={1}
|
||||
h="60px"
|
||||
bg={paymentMethod === 'alipay' ? 'rgba(22, 119, 255, 0.15)' : 'rgba(255, 255, 255, 0.05)'}
|
||||
border="2px solid"
|
||||
borderColor={paymentMethod === 'alipay' ? '#1677FF' : 'rgba(255, 255, 255, 0.1)'}
|
||||
borderRadius="xl"
|
||||
onClick={() => setPaymentMethod('alipay')}
|
||||
_hover={{
|
||||
borderColor: paymentMethod === 'alipay' ? '#1677FF' : 'rgba(255, 255, 255, 0.3)',
|
||||
bg: paymentMethod === 'alipay' ? 'rgba(22, 119, 255, 0.2)' : 'rgba(255, 255, 255, 0.08)',
|
||||
}}
|
||||
transition="all 0.2s"
|
||||
>
|
||||
<HStack spacing={3}>
|
||||
<Box as={AlipayCircleOutlined} fontSize="24px" color="#1677FF" />
|
||||
<Text color="white" fontWeight="medium">支付宝</Text>
|
||||
</HStack>
|
||||
</Button>
|
||||
</HStack>
|
||||
</Box>
|
||||
|
||||
{/* 订阅类型提示 */}
|
||||
{selectedPlan && priceInfo && (
|
||||
<>
|
||||
@@ -1357,26 +1460,67 @@ export default function SubscriptionContentNew() {
|
||||
<Button
|
||||
w="full"
|
||||
size="lg"
|
||||
bgGradient="linear-gradient(135deg, #D4AF37, #B8941F)"
|
||||
color="#000"
|
||||
bgGradient={paymentMethod === 'alipay'
|
||||
? 'linear-gradient(135deg, #1677FF, #0958d9)'
|
||||
: 'linear-gradient(135deg, #07C160, #059048)'}
|
||||
color="white"
|
||||
fontWeight="bold"
|
||||
onClick={handleCreatePaymentOrder}
|
||||
isLoading={loading}
|
||||
isDisabled={!selectedPlan}
|
||||
leftIcon={paymentMethod === 'alipay'
|
||||
? <Box as={AlipayCircleOutlined} fontSize="20px" />
|
||||
: <Icon as={FaWeixin} boxSize={5} />}
|
||||
_hover={{
|
||||
bgGradient: 'linear-gradient(135deg, #F4E3A7, #D4AF37)',
|
||||
bgGradient: paymentMethod === 'alipay'
|
||||
? 'linear-gradient(135deg, #4096ff, #1677FF)'
|
||||
: 'linear-gradient(135deg, #10d76e, #07C160)',
|
||||
transform: 'translateY(-2px)',
|
||||
boxShadow: paymentMethod === 'alipay'
|
||||
? '0 8px 25px rgba(22, 119, 255, 0.4)'
|
||||
: '0 8px 25px rgba(7, 193, 96, 0.4)',
|
||||
}}
|
||||
transition="all 0.3s"
|
||||
>
|
||||
{priceInfo?.is_upgrade && priceInfo?.final_amount === 0
|
||||
? '立即免费升级'
|
||||
: '创建微信支付订单'}
|
||||
: paymentMethod === 'alipay'
|
||||
? '支付宝支付'
|
||||
: '微信扫码支付'}
|
||||
</Button>
|
||||
</VStack>
|
||||
) : (
|
||||
<VStack spacing={4}>
|
||||
<Text color="rgba(255, 255, 255, 0.7)" fontSize="lg" fontWeight="bold">
|
||||
请使用微信扫描二维码完成支付
|
||||
</Text>
|
||||
{/* 根据支付方式显示不同提示 */}
|
||||
{(paymentOrder as any).payment_method === 'alipay' ? (
|
||||
<>
|
||||
<Box
|
||||
p={4}
|
||||
bg="rgba(22, 119, 255, 0.1)"
|
||||
borderRadius="lg"
|
||||
border="1px solid rgba(22, 119, 255, 0.3)"
|
||||
w="full"
|
||||
textAlign="center"
|
||||
>
|
||||
<HStack justify="center" spacing={2} mb={2}>
|
||||
<Box as={AlipayCircleOutlined} fontSize="24px" color="#1677FF" />
|
||||
<Text color="#1677FF" fontSize="lg" fontWeight="bold">
|
||||
支付宝支付
|
||||
</Text>
|
||||
</HStack>
|
||||
<Text color="rgba(255, 255, 255, 0.7)" fontSize="sm">
|
||||
请在新打开的页面中完成支付
|
||||
</Text>
|
||||
<Text color="rgba(255, 255, 255, 0.5)" fontSize="xs" mt={1}>
|
||||
支付完成后点击下方按钮确认
|
||||
</Text>
|
||||
</Box>
|
||||
</>
|
||||
) : (
|
||||
<Text color="rgba(255, 255, 255, 0.7)" fontSize="lg" fontWeight="bold">
|
||||
请使用微信扫描二维码完成支付
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{/* 倒计时 */}
|
||||
<Box
|
||||
@@ -1389,7 +1533,7 @@ export default function SubscriptionContentNew() {
|
||||
<HStack justify="center" spacing={2} mb={2}>
|
||||
<Icon as={FaClock} color="orange.400" />
|
||||
<Text color="orange.300" fontSize="sm">
|
||||
二维码有效时间: {formatTime(paymentCountdown)}
|
||||
订单有效时间: {formatTime(paymentCountdown)}
|
||||
</Text>
|
||||
</HStack>
|
||||
<Progress
|
||||
@@ -1400,36 +1544,38 @@ export default function SubscriptionContentNew() {
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{/* 二维码 */}
|
||||
<Box textAlign="center">
|
||||
{paymentOrder.qr_code_url ? (
|
||||
<Image
|
||||
src={paymentOrder.qr_code_url}
|
||||
alt="微信支付二维码"
|
||||
mx="auto"
|
||||
maxW="200px"
|
||||
border="2px solid"
|
||||
borderColor="rgba(255, 255, 255, 0.2)"
|
||||
borderRadius="lg"
|
||||
bg="white"
|
||||
p={2}
|
||||
/>
|
||||
) : (
|
||||
<Flex
|
||||
w="200px"
|
||||
h="200px"
|
||||
mx="auto"
|
||||
bg="rgba(255, 255, 255, 0.05)"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
border="2px solid"
|
||||
borderColor="rgba(255, 255, 255, 0.2)"
|
||||
borderRadius="lg"
|
||||
>
|
||||
<Icon as={FaQrcode} color="rgba(255, 255, 255, 0.3)" boxSize={12} />
|
||||
</Flex>
|
||||
)}
|
||||
</Box>
|
||||
{/* 微信二维码(仅微信支付显示) */}
|
||||
{(paymentOrder as any).payment_method !== 'alipay' && (
|
||||
<Box textAlign="center">
|
||||
{(paymentOrder as any).qr_code_url ? (
|
||||
<Image
|
||||
src={(paymentOrder as any).qr_code_url}
|
||||
alt="微信支付二维码"
|
||||
mx="auto"
|
||||
maxW="200px"
|
||||
border="2px solid"
|
||||
borderColor="rgba(255, 255, 255, 0.2)"
|
||||
borderRadius="lg"
|
||||
bg="white"
|
||||
p={2}
|
||||
/>
|
||||
) : (
|
||||
<Flex
|
||||
w="200px"
|
||||
h="200px"
|
||||
mx="auto"
|
||||
bg="rgba(255, 255, 255, 0.05)"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
border="2px solid"
|
||||
borderColor="rgba(255, 255, 255, 0.2)"
|
||||
borderRadius="lg"
|
||||
>
|
||||
<Icon as={FaQrcode} color="rgba(255, 255, 255, 0.3)" boxSize={12} />
|
||||
</Flex>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* 订单信息 */}
|
||||
<Box
|
||||
@@ -1440,18 +1586,39 @@ export default function SubscriptionContentNew() {
|
||||
w="full"
|
||||
>
|
||||
<Text fontSize="xs" color="rgba(255, 255, 255, 0.5)" mb={2}>
|
||||
订单号: {paymentOrder.order_no}
|
||||
订单号: {(paymentOrder as any).order_no}
|
||||
</Text>
|
||||
<Flex justify="space-between" align="baseline">
|
||||
<Text color="rgba(255, 255, 255, 0.7)">支付金额:</Text>
|
||||
<Text fontSize="xl" fontWeight="bold" color="#D4AF37">
|
||||
¥{paymentOrder.amount}
|
||||
¥{(paymentOrder as any).amount}
|
||||
</Text>
|
||||
</Flex>
|
||||
</Box>
|
||||
|
||||
{/* 操作按钮 */}
|
||||
<VStack spacing={3} w="full">
|
||||
{/* 支付宝:重新打开支付页面按钮 */}
|
||||
{(paymentOrder as any).payment_method === 'alipay' && (paymentOrder as any).pay_url && (
|
||||
<Button
|
||||
w="full"
|
||||
size="lg"
|
||||
bgGradient="linear-gradient(135deg, #1677FF, #0958d9)"
|
||||
color="white"
|
||||
fontWeight="bold"
|
||||
leftIcon={<Icon as={FaExternalLinkAlt} />}
|
||||
onClick={handleReopenAlipay}
|
||||
_hover={{
|
||||
bgGradient: 'linear-gradient(135deg, #4096ff, #1677FF)',
|
||||
transform: 'translateY(-2px)',
|
||||
boxShadow: '0 8px 25px rgba(22, 119, 255, 0.4)',
|
||||
}}
|
||||
transition="all 0.3s"
|
||||
>
|
||||
重新打开支付页面
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<Button
|
||||
w="full"
|
||||
size="lg"
|
||||
|
||||
Reference in New Issue
Block a user