import request from '@/utils/http' type ExchangeResult = { token: string refreshToken: string expiresIn: number userInfo: Api.Auth.UserInfo } const SS_PREFIX = 'mp_wv_ex:' /** 同一 ticket 只兑换一次,避免 Shell 重复挂载 / web-view 二次加载把一次性票用掉 */ const exchangeInflight = new Map>() const exchangeDone = new Map() function readSessionCache(key: string): ExchangeResult | null { if (typeof sessionStorage === 'undefined') return null try { const raw = sessionStorage.getItem(SS_PREFIX + key) if (!raw) return null const data = JSON.parse(raw) as ExchangeResult if (!data?.token || !data?.refreshToken) return null return data } catch { return null } } function writeSessionCache(key: string, data: ExchangeResult) { if (typeof sessionStorage === 'undefined') return try { sessionStorage.setItem(SS_PREFIX + key, JSON.stringify(data)) } catch { /* quota / private mode */ } } export const mpWebviewApi = { exchange: (ticket: string) => { const key = String(ticket || '').trim() if (!key) { return Promise.reject(new Error('ticket不能为空')) } const mem = exchangeDone.get(key) if (mem) return Promise.resolve(mem) const ss = readSessionCache(key) if (ss) { exchangeDone.set(key, ss) return Promise.resolve(ss) } const pending = exchangeInflight.get(key) if (pending) return pending const req = request .post({ url: '/web/auth/mp-webview-exchange', data: { ticket: key }, showErrorMessage: false }) .then((data) => { exchangeDone.set(key, data) writeSessionCache(key, data) exchangeInflight.delete(key) return data }) .catch((err) => { exchangeInflight.delete(key) throw err }) exchangeInflight.set(key, req) return req } }