import { API_BASE, TOKEN_KEY, REFRESH_TOKEN_KEY, USER_INFO_KEY } from '@/config/api' let clearingAuth = false function createUnauthorizedError(rawUrl = '') { const loginApiPattern = /\/mini\/auth\/login(?:$|\?)/ const message = loginApiPattern.test(String(rawUrl)) ? '用户名或密码错误,请重新输入' : '登录状态已失效,请重新登录' const error = new Error(message) error.name = 'UnauthorizedError' return error } async function onHttpUnauthorized() { if (clearingAuth) return clearingAuth = true // 先同步清理本地登录态,避免 store 动态导入失败时仍被识别为已登录 uni.removeStorageSync(TOKEN_KEY) uni.removeStorageSync(REFRESH_TOKEN_KEY) uni.removeStorageSync(USER_INFO_KEY) try { const { useUserStore } = await import('@/stores/user') useUserStore().clearLoginInfo() } catch (error) { // ignore } const pages = typeof getCurrentPages === 'function' ? getCurrentPages() : [] const currentRoute = pages.length ? pages[pages.length - 1].route : '' if (currentRoute === 'pages/login/login') { clearingAuth = false return } uni.showToast({ title: '登录已失效,请重新登录', icon: 'none' }) uni.reLaunch({ url: '/pages/login/login', fail: () => { // 某些端在请求回调中 reLaunch 可能失败,使用 redirectTo 兜底 uni.redirectTo({ url: '/pages/login/login' }) }, complete: () => { setTimeout(() => { clearingAuth = false }, 800) } }) } function isBizUnauthorized(data) { if (!data || typeof data !== 'object') return false return data.code === 401 } export function request(options) { if (clearingAuth) { return Promise.reject(createUnauthorizedError(options?.url)) } const rawToken = uni.getStorageSync(TOKEN_KEY) const token = typeof rawToken === 'string' ? rawToken.trim() : '' const rawUrl = options.url || '' const url = rawUrl.startsWith('http') ? rawUrl : `${API_BASE}${rawUrl.startsWith('/') ? rawUrl : `/${rawUrl}`}` return new Promise((resolve, reject) => { uni.request({ ...options, url, header: { 'Content-Type': 'application/json', ...(token ? { Authorization: `Bearer ${token}` } : {}), ...(options.header || {}) }, success: (res) => { if (res.statusCode === 401 || isBizUnauthorized(res.data)) { onHttpUnauthorized() reject(createUnauthorizedError(rawUrl)) return } resolve(res) }, fail: (err) => reject(err) }) }) } export function parseResponseJson(res) { const d = res.data if (d == null) return d if (typeof d === 'string') { try { return JSON.parse(d) } catch (error) { return d } } return d }