This commit is contained in:
eric
2026-04-01 02:23:17 -05:00
parent 056dadc817
commit de86a65293
8 changed files with 202 additions and 52 deletions

View File

@@ -14,6 +14,7 @@ const ANONYMOUS_USER_COOKIE_MAX_AGE = 60 * 60 * 24 * 30;
const PAY_ORDER_COOKIE = "nomadvip_pay_order";
const PAY_ORDER_MAX_AGE = 60 * 15;
const VIP_PAY_TEST_MODE_KEY = "vipPayTestMode";
const PAY_LAUNCH_OVERLAY_ID = "nomadvip-pay-launch-overlay";
function getStorage(key: string): string | null {
if (typeof window === "undefined") return null;
@@ -50,6 +51,41 @@ function setPayOrderCookie(orderId: string): void {
)}; Path=/; Max-Age=${PAY_ORDER_MAX_AGE}; SameSite=Lax${secure}`;
}
function getDisplayProfile() {
const wechatNick = (getStorage("wechatNick") || "").trim();
const userName = (getStorage("userName") || "").trim();
const userEmail = (getStorage("userEmail") || "").trim();
const wechatAvatar = (getStorage("wechatAvatar") || "").trim();
const displayName = wechatNick || userName || userEmail || "当前用户";
return { displayName, avatar: wechatAvatar || "" };
}
function showPayLaunchOverlay(displayName: string, avatar?: string): void {
if (typeof document === "undefined") return;
if (!(avatar || "").trim()) return;
const prev = document.getElementById(PAY_LAUNCH_OVERLAY_ID);
if (prev) prev.remove();
const safeName = displayName.replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c] || c);
const safeAvatar = (avatar || "").replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c] || c);
const node = document.createElement("div");
node.id = PAY_LAUNCH_OVERLAY_ID;
node.style.cssText = "position:fixed;inset:0;z-index:9999;display:flex;align-items:center;justify-content:center;background:rgba(15,23,42,.28);pointer-events:none;";
node.innerHTML = `
<div style="display:flex;align-items:center;gap:10px;padding:12px 14px;border-radius:12px;background:#0f172a;color:#e2e8f0;box-shadow:0 10px 30px rgba(2,6,23,.35);max-width:90vw;">
<img src="${safeAvatar}" alt="${safeName}" style="width:30px;height:30px;border-radius:9999px;object-fit:cover;border:1px solid rgba(148,163,184,.5);" />
<div style="font-size:13px;line-height:1.35;">
<div style="font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:56vw;">开通对象:${safeName}</div>
<div style="opacity:.88;">正在为你升级 VIP马上进入支付...</div>
</div>
</div>
`;
document.body.appendChild(node);
window.setTimeout(() => {
const current = document.getElementById(PAY_LAUNCH_OVERLAY_ID);
if (current) current.remove();
}, 2400);
}
function savePendingOrder(orderId: string): void {
const normalizedOrderId = orderId.trim();
if (!normalizedOrderId) return;
@@ -118,6 +154,8 @@ async function getOrCreateUserId(): Promise<string> {
function redirectToPayZpay(params: {
user_id: string;
wechat_userid?: string;
wechat_nick?: string;
wechat_avatar?: string;
return_url: string;
total_fee: number;
type: string;
@@ -132,6 +170,8 @@ function redirectToPayZpay(params: {
const fields: [string, string][] = [
["user_id", params.user_id],
...(params.wechat_userid ? [["wechat_userid", params.wechat_userid] as [string, string]] : []),
...(params.wechat_nick ? [["wechat_nick", params.wechat_nick] as [string, string]] : []),
...(params.wechat_avatar ? [["wechat_avatar", params.wechat_avatar] as [string, string]] : []),
["return_url", params.return_url],
["total_fee", String(params.total_fee)],
["type", params.type],
@@ -155,6 +195,8 @@ async function redirectToPayZpayH5(
params: {
user_id: string;
wechat_userid?: string;
wechat_nick?: string;
wechat_avatar?: string;
return_url: string;
total_fee: number;
type: string;
@@ -215,6 +257,8 @@ async function redirectToPayZpayH5(
function payWechatXorpaySync(params: {
user_id: string;
wechat_userid?: string;
wechat_nick?: string;
wechat_avatar?: string;
return_url: string;
total_fee: number;
type: string;
@@ -228,6 +272,8 @@ function payWechatXorpaySync(params: {
const fields: [string, string][] = [
["user_id", params.user_id],
...(params.wechat_userid ? [["wechat_userid", params.wechat_userid] as [string, string]] : []),
...(params.wechat_nick ? [["wechat_nick", params.wechat_nick] as [string, string]] : []),
...(params.wechat_avatar ? [["wechat_avatar", params.wechat_avatar] as [string, string]] : []),
["return_url", params.return_url],
["total_fee", String(params.total_fee)],
["type", params.type],
@@ -271,9 +317,17 @@ export async function triggerPay(
(getStorage("userid") || "").trim();
const isPayTestMode = getStorage(VIP_PAY_TEST_MODE_KEY) === "1";
const totalFee = isPayTestMode ? 100 : getPaymentConfig().defaultAmount ?? 8800;
const profile = getDisplayProfile();
const shouldShowLaunchOverlay =
device !== "wechat" && !!(profile.avatar || "").trim();
if (shouldShowLaunchOverlay) {
showPayLaunchOverlay(profile.displayName, profile.avatar);
}
const base = {
user_id: userId,
wechat_userid: wechatUserId || undefined,
wechat_nick: profile.displayName,
wechat_avatar: profile.avatar || undefined,
return_url: returnUrl,
total_fee: totalFee,
type: "vip",