/** 微信公众号 H5 网页授权(注册 / 绑定页无 code 时跳转) */ import { clearStashedInviteRef, readStashedInviteRef, stashInviteRef, } from '@/utils/inviteRefStorage'; export type WeChatH5Page = 'register' | 'bind' | 'login'; const DEFAULT_MP_APP_ID = 'wxd5141ba46c856e1f'; export function resolveWeChatMpAppId(): string { const fromEnv = import.meta.env.VITE_WECHAT_MP_APPID as string | undefined; return fromEnv?.trim() || DEFAULT_MP_APP_ID; } /** @deprecated 使用 stashInviteRef */ export function stashWeChatInviteRef(inviteCode?: string | null): void { stashInviteRef(inviteCode); } /** @deprecated 使用 readStashedInviteRef */ export function readStashedWeChatInviteRef(): string { return readStashedInviteRef(); } /** @deprecated 使用 clearStashedInviteRef */ export function clearStashedWeChatInviteRef(): void { clearStashedInviteRef(); } /** 从 OAuth state 解析邀请码(格式 register:CODE) */ export function parseInviteRefFromOAuthState(state: unknown): string { const raw = String(state ?? '').trim(); const match = raw.match(/^(?:register|bind):(.+)$/i); if (!match?.[1]) return ''; try { return decodeURIComponent(match[1]).trim(); } catch { return match[1].trim(); } } /** * 解析当前页邀请码:query.ref / query.invite → OAuth state → 7 天暂存 */ export function resolveWeChatInviteRef(query: Record): string { const fromQuery = String(query.ref ?? query.invite ?? '').trim(); if (fromQuery) { stashInviteRef(fromQuery); return fromQuery; } const fromState = parseInviteRefFromOAuthState(query.state); if (fromState) { stashInviteRef(fromState); return fromState; } return readStashedInviteRef(); } function resolveOAuthRedirectPath(page: WeChatH5Page): string { if (page === 'login') { return `${window.location.origin}/h5/login`; } return `${window.location.origin}/wechat/${page}`; } /** * 跳转微信 OAuth。 * - register/bind:邀请码写入 state + 7 天暂存 * - login:可选把登录后回跳路径写入 state(login:/h5/orders) */ export function redirectToWeChatOAuth( page: WeChatH5Page, inviteCode?: string | null, options?: { afterLoginPath?: string | null }, ): void { const appId = resolveWeChatMpAppId(); const redirectUri = encodeURIComponent(resolveOAuthRedirectPath(page)); let state = page; if (page === 'login') { const after = String(options?.afterLoginPath ?? '').trim(); if (after.startsWith('/h5')) { state = `login:${encodeURIComponent(after)}`; } } else { const code = String(inviteCode ?? '').trim() || readStashedInviteRef(); if (code) stashInviteRef(code); state = code ? `${page}:${encodeURIComponent(code)}` : page; } window.location.replace( `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}` + `&redirect_uri=${redirectUri}` + `&response_type=code&scope=snsapi_userinfo&state=${state}#wechat_redirect`, ); } /** 从 OAuth state 解析登录后回跳路径 */ export function parseAfterLoginPathFromOAuthState(state: unknown): string { const raw = String(state ?? '').trim(); const match = raw.match(/^login:(.+)$/i); if (!match?.[1]) return ''; try { const path = decodeURIComponent(match[1]).trim(); return path.startsWith('/h5') ? path : ''; } catch { const path = match[1].trim(); return path.startsWith('/h5') ? path : ''; } }