diff --git a/service/license/src/api/payment.ts b/service/license/src/api/payment.ts index 7a8ad5f48d1..36f8d38a9dd 100644 --- a/service/license/src/api/payment.ts +++ b/service/license/src/api/payment.ts @@ -1,5 +1,11 @@ import { GET, POST } from '@/services/request'; -import { PaymentData, PaymentParams, PaymentResult, PaymentResultParams } from '@/types'; +import { + CheckWeChatType, + PaymentData, + PaymentParams, + PaymentResult, + PaymentResultParams +} from '@/types'; export const createPayment = (payload: PaymentParams) => POST('/api/payment/create', payload); @@ -7,4 +13,5 @@ export const createPayment = (payload: PaymentParams) => export const handlePaymentResult = (payload: PaymentResultParams) => POST('/api/payment/result', payload); -export const checkWechatPay = () => GET('/api/payment/checkWechat'); +export const checkWechatPay = (type: CheckWeChatType) => + GET('/api/payment/checkWechat', { type }); diff --git a/service/license/src/components/Pagination/index.tsx b/service/license/src/components/Pagination/index.tsx index a2aaaa36c22..a9fc3639fc5 100644 --- a/service/license/src/components/Pagination/index.tsx +++ b/service/license/src/components/Pagination/index.tsx @@ -3,7 +3,7 @@ import { useState } from 'react'; type PaginationProps = { totalItems: number; itemsPerPage: number; - onPageChange: any; + onPageChange: (page: number) => void; }; export default function Pagination({ totalItems, itemsPerPage, onPageChange }: PaginationProps) { diff --git a/service/license/src/pages/api/payment/checkWechat.ts b/service/license/src/pages/api/payment/checkWechat.ts index 37883831022..8b1fdade555 100644 --- a/service/license/src/pages/api/payment/checkWechat.ts +++ b/service/license/src/pages/api/payment/checkWechat.ts @@ -1,12 +1,21 @@ import { authSession } from '@/services/backend/auth'; -import { findRecentNopayOrder, updatePaymentStatus } from '@/services/backend/db/payment'; +import { createClusterAndLicense } from '@/services/backend/db/cluster'; +import { generateLicenseToken } from '@/services/backend/db/license'; +import { findRecentNopayOrder, updatePaymentAndIssueLicense } from '@/services/backend/db/payment'; import { jsonRes } from '@/services/backend/response'; import { getSealosPay } from '@/services/pay'; -import { PaymentResult, PaymentStatus } from '@/types'; +import { + CheckWeChatType, + ClusterType, + LicenseRecordPayload, + PaymentResult, + PaymentStatus +} from '@/types'; import type { NextApiRequest, NextApiResponse } from 'next'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { + const { type } = req.query as { type: CheckWeChatType }; const userInfo = await authSession(req.headers); if (!userInfo) { return jsonRes(res, { code: 401, message: 'token verify error' }); @@ -40,14 +49,42 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }) }).then((res) => res.json()); - const updateStatusResult = await updatePaymentStatus({ - orderID: payment?.orderID, - status: result.status, - uid: userInfo.uid - }); + if (type === 'license' && result.status === PaymentStatus.PaymentSuccess) { + await updatePaymentAndIssueLicense({ + uid: userInfo.uid, + status: result.status, + amount: payment.amount, + quota: payment.amount, + orderID: payment.orderID, + payMethod: payment.payMethod, + type: 'Account' + }); + } + + if (type === 'cluster' && result.status === PaymentStatus.PaymentSuccess) { + const _token = generateLicenseToken({ type: 'Account', data: { amount: payment.amount } }); + const record: LicenseRecordPayload = { + uid: userInfo.uid, + amount: payment.amount, + token: _token, + orderID: payment.orderID, + quota: payment.amount, + payMethod: payment.payMethod, + type: 'Account' + }; + await createClusterAndLicense({ + licensePayload: record, + clusterPayload: { + uid: userInfo.uid, + orderID: payment.orderID, + type: ClusterType.Enterprise + } + }); + } + console.log('Handle wechat shutdown situation'); return jsonRes(res, { - data: updateStatusResult + data: result }); } catch (error) { console.error(error, '===payment error===\n'); diff --git a/service/license/src/pages/cluster/components/Record.tsx b/service/license/src/pages/cluster/components/Record.tsx index 867a9cface4..aa69fe5d6c7 100644 --- a/service/license/src/pages/cluster/components/Record.tsx +++ b/service/license/src/pages/cluster/components/Record.tsx @@ -104,7 +104,13 @@ export default function ClusterRecord({ changeClusterId, clusterId }: TClusterRe )} - {}} /> + { + setPage(page); + }} + /> ); diff --git a/service/license/src/pages/license/components/Recharge.tsx b/service/license/src/pages/license/components/Recharge.tsx index 513a53f6015..1e8c296672d 100644 --- a/service/license/src/pages/license/components/Recharge.tsx +++ b/service/license/src/pages/license/components/Recharge.tsx @@ -43,7 +43,7 @@ export default function RechargeComponent() { const [wechatPaymentData, setWechatPaymentData] = useState(); const { data: platformEnv } = useQuery(['getPlatformEnv'], getSystemEnv); // 用于避免微信支付,窗口关闭后感知不到的问题 - // const { paymentData, setPaymentData, deletePaymentData } = usePaymentDataStore(); + const { paymentData, setPaymentData, deletePaymentData, isExpired } = usePaymentDataStore(); const onClosePayment = useCallback(() => { setOrderID(''); @@ -94,6 +94,7 @@ export default function RechargeComponent() { setOrderID(data.orderID); setWechatPaymentData({ tradeNO: data?.tradeNO, codeURL: data?.codeURL }); setComplete(2); + setPaymentData(data.orderID); } }, onError(err: any) { @@ -121,6 +122,7 @@ export default function RechargeComponent() { position: 'top' }); queryClient.invalidateQueries(['getLicenseActive']); + deletePaymentData(); }, onError(err: any) { toast({ @@ -156,22 +158,24 @@ export default function RechargeComponent() { } }); - // checkWechatPay - // useQuery(['checkWechatPay'], () => checkWechatPay(), { - // enabled: !!paymentData?.orderId, - // onSuccess(data) { - // console.log(data, '------'); - // if (data.status === PaymentStatus.PaymentSuccess) { - // toast({ - // status: 'success', - // title: t('Payment Successful'), // 这里改为license 签发成功 - // isClosable: true, - // duration: 9000, - // position: 'top' - // }); - // } - // } - // }); + // checkWechatPay; + useQuery(['checkWechatPay'], () => checkWechatPay('license'), { + enabled: !isExpired() && !!paymentData?.orderId, + onSuccess(data) { + console.log(data, 'Handle wechat shutdown situation'); + if (data.status === PaymentStatus.PaymentSuccess) { + toast({ + status: 'success', + title: t('Payment Successful'), // 这里改为license 签发成功 + isClosable: true, + duration: 9000, + position: 'top' + }); + queryClient.invalidateQueries(['getLicenseActive']); + deletePaymentData(); + } + } + }); useEffect(() => { const { stripeState, orderID } = router.query; diff --git a/service/license/src/pages/license/components/Record.tsx b/service/license/src/pages/license/components/Record.tsx index 60ac515c7bb..d77de18227c 100644 --- a/service/license/src/pages/license/components/Record.tsx +++ b/service/license/src/pages/license/components/Record.tsx @@ -98,7 +98,11 @@ export default function History() { )} - {}} /> + setPage(page)} + /> ); diff --git a/service/license/src/pages/pricing/components/Product.tsx b/service/license/src/pages/pricing/components/Product.tsx index c98cfc88f84..bd17f454775 100644 --- a/service/license/src/pages/pricing/components/Product.tsx +++ b/service/license/src/pages/pricing/components/Product.tsx @@ -30,6 +30,7 @@ import { useCallback, useEffect, useState } from 'react'; import ServicePackage from './ServicePackage'; import useRouteParamsStore from '@/stores/routeParams'; import useSessionStore from '@/stores/session'; +import usePaymentDataStore from '@/stores/payment'; export default function Product() { const { t } = useTranslation(); @@ -48,6 +49,7 @@ export default function Product() { const [remainingSeconds, setRemainingSeconds] = useState(2); // 初始值为2秒 const { data: routeParams, setRouteParams, clearRouteParams } = useRouteParamsStore(); const { isUserLogin } = useSessionStore(); + const { paymentData, setPaymentData, deletePaymentData, isExpired } = usePaymentDataStore(); const onClosePayment = useCallback(() => { setOrderID(''); @@ -58,7 +60,7 @@ export default function Product() { const openPayModal = () => { setComplete(1); setPayType('wechat'); - paymentMutation.mutate((599 * 100).toString()); + paymentMutation.mutate((1 * 100).toString()); onOpen(); }; @@ -105,6 +107,7 @@ export default function Product() { setOrderID(data.orderID); setWechatData({ tradeNO: data?.tradeNO, codeURL: data?.codeURL }); setComplete(2); + setPaymentData(data.orderID); } }, onError(err: any) { @@ -126,7 +129,7 @@ export default function Product() { console.log(data, 'clusterMutation'); setComplete(3); queryClient.invalidateQueries(['getClusterRecord']); - // onClosePayment(); + deletePaymentData(); }, onError(err: any) { toast({ @@ -148,6 +151,7 @@ export default function Product() { console.log(data, 'clusterAndLicenseMutation'); setComplete(3); queryClient.invalidateQueries(['getClusterRecord']); + deletePaymentData(); }, onError(err: any) { toast({ @@ -184,19 +188,24 @@ export default function Product() { }); // checkWechatPay - // useQuery(['checkWechatPay'], () => checkWechatPay(), { - // onSuccess(data) { - // if (data.status === PaymentStatus.PaymentSuccess) { - // toast({ - // status: 'success', - // title: t('License issued successfully'), // 这里改为license 签发成功 - // isClosable: true, - // duration: 9000, - // position: 'top' - // }); - // } - // } - // }); + useQuery(['checkWechatPay'], () => checkWechatPay('cluster'), { + enabled: !isExpired() && !!paymentData?.orderId, + onSuccess(data) { + console.log(data, 'Handle wechat shutdown situation'); + if (data.status === PaymentStatus.PaymentSuccess) { + toast({ + status: 'success', + title: t('Payment Successful'), // 这里改为license 签发成功 + isClosable: true, + duration: 9000, + position: 'top' + }); + deletePaymentData(); + queryClient.invalidateQueries(['getClusterRecord']); + setComplete(3); + } + } + }); // handle stripe useEffect(() => { @@ -273,6 +282,7 @@ export default function Product() { void; + setPaymentData: (orderId: string) => void; deletePaymentData: () => void; + isExpired: () => boolean; }; export const usePaymentDataStore = create( persist( - immer((set) => ({ + immer((set, get) => ({ paymentData: undefined, - setPaymentData: (data) => set({ paymentData: data }), - deletePaymentData: () => set({ paymentData: undefined }) + setPaymentData: (id) => { + const currentTime = new Date().getTime(); // 获取当前时间戳 + const expirationTime = currentTime + 5 * 60000; // 10 minutes in milliseconds + set({ + paymentData: { + orderId: id, + expirationTime: expirationTime + } + }); + }, + deletePaymentData: () => set({ paymentData: undefined }), + isExpired: () => { + const paymentData = get().paymentData; + if (paymentData && paymentData.expirationTime) { + const currentTime = new Date().getTime(); + return currentTime > paymentData.expirationTime; + } + return false; + } })), { name: 'paymentData' diff --git a/service/license/src/types/payment.ts b/service/license/src/types/payment.ts index 7be21157a6e..ab3e1055783 100644 --- a/service/license/src/types/payment.ts +++ b/service/license/src/types/payment.ts @@ -13,6 +13,7 @@ export type PaymentDB = { updatedAt: Date; // Modification timestamp }; +export type CheckWeChatType = 'license' | 'cluster'; export type TPayMethod = 'stripe' | 'wechat'; export type StripeCallBackUrl = '/pricing' | '/license';