From e2eda2ddb865cfb7daf58cc1770bf563648b5a1c Mon Sep 17 00:00:00 2001 From: moux1024 <403053463@qq.com> Date: Thu, 25 Sep 2025 17:24:39 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D:=20=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E9=A1=B5=E5=86=85=E8=AF=B7=E6=B1=82=E9=87=8D=E5=AE=9A=E5=90=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/pay-redirect/page.tsx | 81 ++++++++++++++++++++++++--------- app/pricing/page.tsx | 54 ++++------------------ components/layout/top-bar.tsx | 56 ++++------------------- components/pages/home-page2.tsx | 38 ++++------------ 4 files changed, 87 insertions(+), 142 deletions(-) diff --git a/app/pay-redirect/page.tsx b/app/pay-redirect/page.tsx index 24fc220..f11b8b5 100644 --- a/app/pay-redirect/page.tsx +++ b/app/pay-redirect/page.tsx @@ -2,38 +2,75 @@ import React from "react"; import { TailwindSpinner } from "@/components/common/GlobalLoad"; +import { useSearchParams } from "next/navigation"; +import { createCheckoutSession, buyTokens } from "@/lib/stripe"; export default function PayRedirectPage() { - const [status, setStatus] = React.useState("Waiting for secure checkout redirect..."); + const [status, setStatus] = React.useState("Preparing checkout..."); const [error, setError] = React.useState(""); + const searchParams = useSearchParams(); React.useEffect(() => { - const handleMessage = (event: MessageEvent) => { + const type = (searchParams.get("type") || "").toLowerCase(); + if (!type) { + setStatus(""); + setError("Missing payment type."); + return; + } + + const redirectTo = async () => { try { - if (event.origin !== window.location.origin) return; - const data = event.data || {}; - if (data?.type === "redirect-to-payment" && typeof data?.url === "string") { - setStatus("Redirecting to Stripe Checkout..."); - window.location.href = data.url as string; - } else if (data?.type === "redirect-error") { - setError(typeof data?.message === "string" ? data.message : "Failed to create payment. Please close this page and try again."); + if (type === "token") { + const amountStr = searchParams.get("amount"); + const pkg = searchParams.get("pkg") || "basic"; + const amount = Number(amountStr); + if (!amount || amount <= 0) { + throw new Error("Invalid token amount"); + } + setStatus("Creating token purchase session..."); + const resp = await buyTokens({ token_amount: amount, package_type: pkg }); + if (resp?.successful && resp?.data?.checkout_url) { + setStatus("Redirecting to Stripe Checkout..."); + window.location.href = resp.data.checkout_url as string; + return; + } + throw new Error(resp?.message || "Failed to create token checkout session"); } - } catch { - setError("An error occurred while processing redirect info. Please close this page and try again."); + + if (type === "subscription") { + const plan = searchParams.get("plan"); + const billing = (searchParams.get("billing") || "month") as "month" | "year"; + if (!plan) { + throw new Error("Missing plan name"); + } + const currentUser = JSON.parse(localStorage.getItem("currentUser") || "{}"); + if (!currentUser?.id) { + throw new Error("Not logged in. Please sign in and try again."); + } + setStatus("Creating subscription session..."); + const result = await createCheckoutSession({ + user_id: String(currentUser.id), + plan_name: plan, + billing_cycle: billing, + }); + if (result?.successful && result?.data?.checkout_url) { + setStatus("Redirecting to Stripe Checkout..."); + window.location.href = result.data.checkout_url as string; + return; + } + throw new Error(result?.message || "Failed to create subscription session"); + } + + throw new Error("Unsupported payment type"); + } catch (e: unknown) { + setStatus(""); + setError(e instanceof Error ? e.message : "Failed to prepare checkout."); } }; - window.addEventListener("message", handleMessage); - const timeoutId = window.setTimeout(() => { - setStatus(""); - setError("No redirect instruction received. It may be a network issue or the page was blocked. Please go back and try again."); - }, 15000); - - return () => { - window.removeEventListener("message", handleMessage); - window.clearTimeout(timeoutId); - }; - }, []); + redirectTo(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [searchParams]); return (
diff --git a/app/pricing/page.tsx b/app/pricing/page.tsx index 9ea40bd..01291e4 100644 --- a/app/pricing/page.tsx +++ b/app/pricing/page.tsx @@ -85,54 +85,18 @@ function HomeModule5() { const handleSubscribe = async (planName: string) => { setLoadingPlan(planName); - - // 先同步打开同域重定向页,避免拦截 - const redirectWindow = window.open('/pay-redirect', '_blank'); - if (!redirectWindow) { + // 改为直接携带参数打开 pay-redirect,由其内部完成创建与跳转 + const url = `/pay-redirect?type=subscription&plan=${encodeURIComponent(planName)}&billing=${encodeURIComponent(billingType)}`; + const win = window.open(url, '_blank'); + // 通知当前窗口等待支付(显示loading模态框) + window.postMessage({ + type: 'waiting-payment', + paymentType: 'subscription', + }, '*'); + if (!win) { setLoadingPlan(null); throw new Error('Unable to open redirect window, please check popup settings'); } - - try { - const { createCheckoutSession } = await import("@/lib/stripe"); - - const User = JSON.parse(localStorage.getItem("currentUser") || "{}"); - if (!User.id) { - throw new Error("Unable to obtain user ID, please log in again"); - } - - const result = await createCheckoutSession({ - user_id: String(User.id), - plan_name: planName, - billing_cycle: billingType, - }); - - if (!result.successful || !result.data?.checkout_url) { - throw new Error("create checkout session failed"); - } - - // 通知当前窗口等待支付(显示loading模态框) - window.postMessage({ - type: 'waiting-payment', - paymentType: 'subscription', - }, '*'); - - // 通过 postMessage 通知新页面执行重定向 - redirectWindow.postMessage({ - type: 'redirect-to-payment', - url: result.data.checkout_url, - }, window.location.origin); - } catch (error) { - // 通知新页错误信息 - try { - redirectWindow.postMessage({ - type: 'redirect-error', - message: 'Failed to create checkout session', - }, window.location.origin); - } catch {} - setLoadingPlan(null); - throw new Error("create checkout session failed, please try again later"); - } }; return (
{ if (!currentUser?.id) { console.error("用户未登录"); @@ -99,52 +99,14 @@ export function TopBar({ collapsed, isDesktop=true }: { collapsed: boolean, isDe console.error("Token数量必须大于0"); return; } - - // 先同步打开同域新页面,避免被拦截 - const redirectWindow = window.open("/pay-redirect", "_blank"); - if (!redirectWindow) { - console.error("无法打开支付重定向页面,可能被浏览器拦截"); - return; - } - - setIsBuyingTokens(true); - try { - const response = await buyTokens({ - token_amount: tokenAmount, - package_type: "basic" - }); - - if (response.successful && response.data?.checkout_url) { - // 通知当前窗口等待支付,标识为Token购买 - window.postMessage({ - type: "waiting-payment", - paymentType: "token" - }, "*"); - sessionStorage.setItem('session_id', response.data.session_id); - // 通过 postMessage 通知新页面进行重定向 - redirectWindow.postMessage({ - type: "redirect-to-payment", - url: response.data.checkout_url - }, window.location.origin); - } else { - console.error("创建Token购买失败:", response.message); - // 通知新页显示错误 - redirectWindow.postMessage({ - type: "redirect-error", - message: response.message || "创建支付失败" - }, window.location.origin); - } - } catch (error: unknown) { - console.error("Token购买失败:", error); - try { - redirectWindow.postMessage({ - type: "redirect-error", - message: "网络或服务异常,请关闭此页重试" - }, window.location.origin); - } catch {} - } finally { - setIsBuyingTokens(false); - } + // 直接打开带参数的 pay-redirect,新窗口内自行创建会话并跳转 + const url = `/pay-redirect?type=token&amount=${encodeURIComponent(tokenAmount)}&pkg=basic`; + window.open(url, "_blank"); + // 通知当前窗口等待支付(显示loading模态框) + window.postMessage({ + type: 'waiting-payment', + paymentType: 'subscription', + }, '*'); }; // 处理自定义金额购买 diff --git a/components/pages/home-page2.tsx b/components/pages/home-page2.tsx index f75a0c4..20e7dee 100644 --- a/components/pages/home-page2.tsx +++ b/components/pages/home-page2.tsx @@ -1249,34 +1249,16 @@ function HomeModule5() { const handleSubscribe = async (planName: string) => { localStorage.setItem("callBackUrl", pathname); - try { - // 使用新的Checkout Session方案(更简单!) - const { createCheckoutSession, redirectToCheckout } = await import( - "@/lib/stripe" - ); - - // 从localStorage获取当前用户信息 - const User = JSON.parse(localStorage.getItem("currentUser") || "{}"); - - if (!User.id) { - throw new Error("无法获取用户ID,请重新登录"); - } - - // 1. 创建Checkout Session - const result = await createCheckoutSession({ - user_id: String(User.id), - plan_name: planName, - billing_cycle: billingType, - }); - - if (!result.successful || !result.data) { - throw new Error("create checkout session failed"); - } - - setShowCallbackModal(true); - window.open(result.data.checkout_url, "_blank"); - } catch (error) { - throw new Error("create checkout session failed, please try again later"); + // 改为直接携带参数打开 pay-redirect,由其内部完成创建与跳转 + const url = `/pay-redirect?type=subscription&plan=${encodeURIComponent(planName)}&billing=${encodeURIComponent(billingType)}`; + const win = window.open(url, "_blank"); + // 通知当前窗口等待支付(显示loading模态框) + window.postMessage({ + type: 'waiting-payment', + paymentType: 'subscription', + }, '*'); + if (!win) { + throw new Error("Unable to open redirect window, please check popup settings"); } }; return (