refactor: 简化支付展示逻辑 - 有 payUrl 直接跳转,有 qrCode 显示二维码
移除 isRedirectPayment / mobileRedirectUrl 等支付类型判断, 前端只根据后端返回的字段决定行为: - payUrl → 自动跳转,无需确认 - qrCode → 展示二维码 + 中心图标 - clientSecret → Stripe 嵌入式表单 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,6 @@ import { useEffect, useMemo, useState, useCallback, useRef } from 'react';
|
|||||||
import QRCode from 'qrcode';
|
import QRCode from 'qrcode';
|
||||||
import {
|
import {
|
||||||
isStripeType,
|
isStripeType,
|
||||||
isRedirectPayment,
|
|
||||||
getPaymentMeta,
|
getPaymentMeta,
|
||||||
getPaymentIconSrc,
|
getPaymentIconSrc,
|
||||||
getPaymentChannelLabel,
|
getPaymentChannelLabel,
|
||||||
@@ -78,32 +77,22 @@ export default function PaymentQRCode({
|
|||||||
const [popupBlocked, setPopupBlocked] = useState(false);
|
const [popupBlocked, setPopupBlocked] = useState(false);
|
||||||
const paymentMethodListenerAdded = useRef(false);
|
const paymentMethodListenerAdded = useRef(false);
|
||||||
|
|
||||||
// alipay_direct 使用电脑网站支付,payUrl 是跳转链接不是二维码内容
|
// 有 payUrl 就直接跳转,不需要确认
|
||||||
const isRedirect = isRedirectPayment(paymentType);
|
const shouldAutoRedirect = !expired && !isStripeType(paymentType) && !!payUrl;
|
||||||
|
|
||||||
// 移动端可用的跳转链接:优先 payUrl,其次尝试 qrCode(微信 weixin:// 协议可直接唤起)
|
|
||||||
const mobileRedirectUrl = payUrl || (qrCode && /^(https?:|weixin:)/i.test(qrCode) ? qrCode : null);
|
|
||||||
|
|
||||||
// 自动跳转:redirect 支付方式 或 移动端 H5
|
|
||||||
const shouldAutoRedirect = !expired && !isStripeType(paymentType) && ((isRedirect && payUrl) || (isMobile && mobileRedirectUrl));
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!shouldAutoRedirect || redirected) return;
|
if (!shouldAutoRedirect || redirected) return;
|
||||||
const url = isRedirect ? payUrl! : mobileRedirectUrl!;
|
|
||||||
setRedirected(true);
|
setRedirected(true);
|
||||||
// embedded iframe 不能 location.href 跳转,用 window.open
|
|
||||||
if (isEmbedded) {
|
if (isEmbedded) {
|
||||||
window.open(url, '_blank');
|
window.open(payUrl!, '_blank');
|
||||||
} else {
|
} else {
|
||||||
window.location.href = url;
|
window.location.href = payUrl!;
|
||||||
}
|
}
|
||||||
}, [shouldAutoRedirect, redirected, isRedirect, payUrl, mobileRedirectUrl, isEmbedded]);
|
}, [shouldAutoRedirect, redirected, payUrl, isEmbedded]);
|
||||||
|
|
||||||
const qrPayload = useMemo(() => {
|
const qrPayload = useMemo(() => {
|
||||||
if (isRedirect && !qrCode) return '';
|
return (qrCode || '').trim();
|
||||||
const value = (qrCode || payUrl || '').trim();
|
}, [qrCode]);
|
||||||
return value;
|
|
||||||
}, [qrCode, payUrl, isRedirect]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
@@ -476,7 +465,7 @@ export default function PaymentQRCode({
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<a
|
<a
|
||||||
href={isRedirect ? payUrl! : mobileRedirectUrl!}
|
href={payUrl!}
|
||||||
target={isEmbedded ? '_blank' : '_self'}
|
target={isEmbedded ? '_blank' : '_self'}
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className={`flex w-full items-center justify-center gap-2 rounded-lg py-3 font-medium text-white shadow-md ${meta.buttonClass}`}
|
className={`flex w-full items-center justify-center gap-2 rounded-lg py-3 font-medium text-white shadow-md ${meta.buttonClass}`}
|
||||||
@@ -511,18 +500,7 @@ export default function PaymentQRCode({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!qrDataUrl && payUrl && (
|
{!qrDataUrl && (
|
||||||
<a
|
|
||||||
href={payUrl}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="rounded-lg bg-blue-600 px-8 py-3 font-medium text-white hover:bg-blue-700"
|
|
||||||
>
|
|
||||||
{TEXT_GO_PAY}
|
|
||||||
</a>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!qrDataUrl && !payUrl && (
|
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<div
|
<div
|
||||||
className={[
|
className={[
|
||||||
|
|||||||
Reference in New Issue
Block a user