import { isWechatMiniProgramRuntime } from './payment/paymentPlatform'; const WECHAT_JS_SDK_URL = 'https://res.wx.qq.com/open/js/jweixin-1.6.0.js'; const SUBSCRIBE_RESULT_HASH_KEY = 'wx_subscribe_result'; const SUBSCRIBE_RESULT_TIMEOUT_MS = 30_000; const SUBSCRIBE_RESULT_RETURN_FALLBACK_MS = 800; function clearSubscribeResultHash() { const rawHash = window.location.hash.replace(/^#/, ''); if (!rawHash.includes(`${SUBSCRIBE_RESULT_HASH_KEY}=`)) { return; } const params = new URLSearchParams(rawHash); params.delete(SUBSCRIBE_RESULT_HASH_KEY); const nextHash = params.toString(); window.history.replaceState( null, '', `${window.location.pathname}${window.location.search}${nextHash ? `#${nextHash}` : ''}`, ); } function readSubscribeResultFromHash() { const value = new URLSearchParams(window.location.hash.replace(/^#/, '')).get( SUBSCRIBE_RESULT_HASH_KEY, ); if (!value) { return null; } clearSubscribeResultHash(); return value; } function waitSubscribeResultFromHash(timeoutMs = SUBSCRIBE_RESULT_TIMEOUT_MS) { const immediateResult = readSubscribeResultFromHash(); if (immediateResult) { return Promise.resolve(immediateResult); } return new Promise((resolve) => { let timer: number | null = null; let resumeFallbackTimer: number | null = null; const cleanup = () => { window.removeEventListener('hashchange', handleHashChange); window.removeEventListener('focus', handleResume); window.removeEventListener('pageshow', handleResume); document.removeEventListener('visibilitychange', handleResume); if (timer !== null) { window.clearTimeout(timer); } if (resumeFallbackTimer !== null) { window.clearTimeout(resumeFallbackTimer); } }; const finish = (result: string | null) => { cleanup(); resolve(result); }; const consume = () => { const result = readSubscribeResultFromHash(); if (result) { finish(result); return true; } return false; }; const handleHashChange = () => { consume(); }; const handleResume = () => { if ( typeof document !== 'undefined' && document.visibilityState === 'hidden' ) { return; } if (consume()) { return; } // 中文注释:订阅授权只影响后续通知,不应阻断生成;原生页返回但没有 hash // 回灌时,按已返回处理,让原本的生成提交流程继续执行。 if (resumeFallbackTimer === null) { resumeFallbackTimer = window.setTimeout( () => finish('returned'), SUBSCRIBE_RESULT_RETURN_FALLBACK_MS, ); } }; window.addEventListener('hashchange', handleHashChange); window.addEventListener('focus', handleResume); window.addEventListener('pageshow', handleResume); document.addEventListener('visibilitychange', handleResume); timer = window.setTimeout(() => finish(null), timeoutMs); }); } function loadWechatJsSdk() { if ( !isWechatMiniProgramRuntime() || typeof window === 'undefined' ) { return Promise.reject(new Error('not_mini_program')); } if (window.wx?.miniProgram?.navigateTo) { return Promise.resolve(window.wx); } return new Promise>((resolve, reject) => { const existingScript = document.querySelector( `script[src="${WECHAT_JS_SDK_URL}"]`, ); const complete = () => { if (window.wx?.miniProgram?.navigateTo) { resolve(window.wx); } else { reject(new Error('wechat_js_sdk_unavailable')); } }; if (existingScript) { existingScript.addEventListener('load', complete, { once: true }); existingScript.addEventListener('error', () => reject(new Error('wechat_js_sdk_load_failed')), { once: true, }); complete(); return; } const script = document.createElement('script'); script.src = WECHAT_JS_SDK_URL; script.async = true; script.onload = complete; script.onerror = () => reject(new Error('wechat_js_sdk_load_failed')); document.head.appendChild(script); }); } export async function requestGenerationResultSubscribePermission() { if (!isWechatMiniProgramRuntime() || typeof window === 'undefined') { return false; } let wxBridge: NonNullable; try { wxBridge = await loadWechatJsSdk(); } catch { return false; } const miniProgram = wxBridge.miniProgram; if (!miniProgram || typeof miniProgram.navigateTo !== 'function') { return false; } const requestId = `subscribe_generation_result_${Date.now()}`; const navigated = await new Promise((resolve) => { miniProgram.navigateTo?.({ url: `/pages/subscribe-message/index?requestId=${encodeURIComponent(requestId)}&scene=generation-result&autoRequest=1`, success() { resolve(true); }, fail() { resolve(false); }, }); }); if (!navigated) { return false; } const resultPromise = waitSubscribeResultFromHash(); const result = await resultPromise; return Boolean(result); }