's''
This commit is contained in:
@@ -7,6 +7,9 @@ import {
|
||||
} from "@/config/services.config";
|
||||
import { SITE_URL } from "@/app/lib/env";
|
||||
|
||||
/** ZPAY 创建订单较慢(约 6–10s),需延长超时避免手机浏览器发起支付超时 */
|
||||
export const maxDuration = 30;
|
||||
|
||||
const ORDER_COOKIE = "join_pay_order";
|
||||
const SALON_PAY_PREFIX = "/salon";
|
||||
|
||||
@@ -165,23 +168,11 @@ h2{color:#1e293b;margin:0 0 8px;font-size:1.5rem;}
|
||||
.then(function(r){return r.json();})
|
||||
.then(function(d){
|
||||
if(d&&d.paid){doConfirm(0);return;}
|
||||
setTimeout(check,300);
|
||||
setTimeout(check,800);
|
||||
})
|
||||
.catch(function(){setTimeout(check,1000);});
|
||||
.catch(function(){setTimeout(check,1500);});
|
||||
}
|
||||
var manualBtn=document.createElement("button");
|
||||
manualBtn.textContent="支付完成?点此手动检查";
|
||||
manualBtn.style.cssText="margin-top:12px;padding:8px 16px;font-size:13px;color:#64748b;background:#f1f5f9;border:none;border-radius:8px;cursor:pointer";
|
||||
manualBtn.onclick=function(){
|
||||
manualBtn.disabled=true;
|
||||
manualBtn.textContent="检查中…";
|
||||
fetch("/api/pay/status?order_id="+encodeURIComponent(orderId),{cache:"no-store",credentials:"same-origin"})
|
||||
.then(function(r){return r.json();})
|
||||
.then(function(d){if(d&&d.paid){doConfirm(0);}else{manualBtn.disabled=false;manualBtn.textContent="支付完成?点此手动检查";}})
|
||||
.catch(function(){manualBtn.disabled=false;manualBtn.textContent="检查失败,重试";});
|
||||
};
|
||||
if(tip&&tip.parentNode){tip.parentNode.appendChild(manualBtn);}
|
||||
setTimeout(check,300);
|
||||
setTimeout(check,500);
|
||||
})();
|
||||
</script>
|
||||
</body></html>`;
|
||||
@@ -243,7 +234,7 @@ async function requestRedirect(
|
||||
payload: Record<string, unknown>
|
||||
) {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), 12000);
|
||||
const timeout = setTimeout(() => controller.abort(), 25000);
|
||||
try {
|
||||
return await fetch(`${apiUrl}${path}`, {
|
||||
method: "POST",
|
||||
@@ -309,30 +300,33 @@ export async function POST(request: NextRequest) {
|
||||
device
|
||||
);
|
||||
|
||||
const created = await createPayOrder(
|
||||
apiUrl,
|
||||
userId,
|
||||
returnUrl,
|
||||
totalFee,
|
||||
type,
|
||||
channel,
|
||||
forcedProvider,
|
||||
clientIp
|
||||
);
|
||||
// 微信内:xorpay 收银台,需先 createPayOrder
|
||||
// PC/手机浏览器:zpay,参考 nomadvip 直接走 redirect,跳过 payh5 避免重复建单
|
||||
const isWechat = device === "wechat";
|
||||
let created: Awaited<ReturnType<typeof createPayOrder>> | null = null;
|
||||
|
||||
if (!wantHtml) {
|
||||
const response = NextResponse.json({
|
||||
ok: true,
|
||||
params: created.params,
|
||||
payUrl: created.payUrl,
|
||||
provider: created.provider,
|
||||
order_id: created.orderId,
|
||||
});
|
||||
if (created.orderId) setPayOrderCookie(response, created.orderId);
|
||||
return response;
|
||||
}
|
||||
|
||||
if (created.provider === "xorpay") {
|
||||
if (isWechat) {
|
||||
created = await createPayOrder(
|
||||
apiUrl,
|
||||
userId,
|
||||
returnUrl,
|
||||
totalFee,
|
||||
type,
|
||||
channel,
|
||||
"xorpay",
|
||||
clientIp
|
||||
);
|
||||
if (!wantHtml) {
|
||||
const response = NextResponse.json({
|
||||
ok: true,
|
||||
params: created.params,
|
||||
payUrl: created.payUrl,
|
||||
provider: created.provider,
|
||||
order_id: created.orderId,
|
||||
});
|
||||
if (created.orderId) setPayOrderCookie(response, created.orderId);
|
||||
return response;
|
||||
}
|
||||
const html = buildPayHtml(created.payUrl, created.params, {
|
||||
directToCashier: true,
|
||||
orderId: created.orderId,
|
||||
@@ -345,6 +339,7 @@ export async function POST(request: NextRequest) {
|
||||
return response;
|
||||
}
|
||||
|
||||
// PC/手机:zpay 直接 redirect(手机 h5 得 302 跳转支付页,PC 得二维码页)
|
||||
const redirectPayload: Record<string, unknown> = {
|
||||
user_id: userId,
|
||||
site_id: SITE_ID,
|
||||
@@ -366,10 +361,18 @@ export async function POST(request: NextRequest) {
|
||||
if (redirectRes.status >= 301 && redirectRes.status <= 308) {
|
||||
const location = redirectRes.headers.get("location");
|
||||
if (location) {
|
||||
const orderId = redirectRes.headers.get("x-pay-order-id")?.trim();
|
||||
if (!wantHtml) {
|
||||
const res = NextResponse.json({
|
||||
ok: true,
|
||||
order_id: orderId,
|
||||
redirect_url: location,
|
||||
provider: "zpay",
|
||||
});
|
||||
if (orderId) setPayOrderCookie(res, orderId);
|
||||
return res;
|
||||
}
|
||||
const response = NextResponse.redirect(location);
|
||||
const orderId =
|
||||
redirectRes.headers.get("x-pay-order-id")?.trim() ||
|
||||
created.orderId;
|
||||
if (orderId) setPayOrderCookie(response, orderId);
|
||||
return response;
|
||||
}
|
||||
@@ -391,7 +394,7 @@ export async function POST(request: NextRequest) {
|
||||
c
|
||||
] || c)
|
||||
);
|
||||
const rawOrderId = String(resData.order_id || created.orderId).trim();
|
||||
const rawOrderId = String(resData.order_id || "").trim();
|
||||
const html = buildQrHtml(imgSrc, safeReturnUrl, rawOrderId, {
|
||||
channel: resData.channel || "wxpay",
|
||||
confirmUrl: "/api/pay/complete-order",
|
||||
@@ -405,6 +408,16 @@ export async function POST(request: NextRequest) {
|
||||
}
|
||||
|
||||
if (redirectRes.status === 200 && resData?.use_form) {
|
||||
created = await createPayOrder(
|
||||
apiUrl,
|
||||
userId,
|
||||
returnUrl,
|
||||
totalFee,
|
||||
type,
|
||||
channel,
|
||||
undefined,
|
||||
clientIp
|
||||
);
|
||||
const html = buildPayHtml(payConfig.zpaySubmitUrl, created.params, {
|
||||
directToCashier: true,
|
||||
orderId: String(resData.order_id || created.orderId).trim(),
|
||||
@@ -432,6 +445,17 @@ export async function POST(request: NextRequest) {
|
||||
);
|
||||
}
|
||||
|
||||
// 兜底:redirect 失败时回退到 payh5
|
||||
created = await createPayOrder(
|
||||
apiUrl,
|
||||
userId,
|
||||
returnUrl,
|
||||
totalFee,
|
||||
type,
|
||||
channel,
|
||||
undefined,
|
||||
clientIp
|
||||
);
|
||||
const html = buildPayHtml(created.payUrl, created.params, {
|
||||
orderId: created.orderId,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user