import config from '../config.js' import storage from './storage.js' let isRefreshing = false let refreshSubscribers = [] const subscribeTokenRefresh = (callback) => { refreshSubscribers.push(callback) } const onTokenRefreshed = (token) => { refreshSubscribers.forEach(callback => callback(token)) refreshSubscribers = [] } const request = (options) => { return new Promise((resolve, reject) => { const fullUrl = config.baseUrl + options.url console.log('=== 请求开始 ===') console.log('URL:', fullUrl) console.log('Method:', options.method || 'GET') console.log('Data:', options.data) const token = storage.getToken() const { noAuthModal = false } = options uni.request({ url: fullUrl, method: options.method || 'GET', data: options.data || {}, header: { 'Content-Type': 'application/json', ...(token ? { 'Authorization': `Bearer ${token}` } : {}), ...options.header }, timeout: config.timeout, success: async (res) => { console.log('=== 请求成功 ===') console.log('StatusCode:', res.statusCode) console.log('Response:', res.data) const { statusCode, data } = res if (statusCode === 401) { console.log('=== Token 过期,尝试刷新 ===') if (isRefreshing) { return new Promise((resolve) => { subscribeTokenRefresh((newToken) => { options.header = options.header || {} options.header.Authorization = `Bearer ${newToken}` resolve(request(options)) }) }).then(resolve).catch(reject) } isRefreshing = true try { const refreshToken = storage.getRefreshToken() if (!refreshToken) { throw new Error('没有刷新令牌') } const refreshRes = await new Promise((resolve, reject) => { uni.request({ url: config.baseUrl + '/gw/open/refresh_token', method: 'POST', data: { refreshToken }, header: { 'Content-Type': 'application/json' }, success: (res) => { if (res.statusCode === 200 && res.data.code === 0) { resolve(res.data) } else { reject(res.data) } }, fail: reject }) }) if (refreshRes.data && refreshRes.data.accessToken) { storage.setToken(refreshRes.data.accessToken) if (refreshRes.data.refreshToken) { storage.setRefreshToken(refreshRes.data.refreshToken) } onTokenRefreshed(refreshRes.data.accessToken) isRefreshing = false options.header = options.header || {} options.header.Authorization = `Bearer ${refreshRes.data.accessToken}` const retryRes = await request(options) resolve(retryRes) } else { throw new Error('刷新令牌失败') } } catch (refreshError) { console.error('=== 刷新令牌失败 ===', refreshError) isRefreshing = false storage.removeToken() storage.removeRefreshToken() storage.removeUserInfo() if (!noAuthModal) { uni.showModal({ title: '登录过期', content: '请重新登录', showCancel: false, success: () => { uni.reLaunch({ url: '/pages/login/login' }) } }) } else { // 不弹出窗口,直接返回错误 const error = new Error('401 Unauthorized') error.statusCode = 401 reject(error) return } reject(refreshError) } } else if (statusCode === 200) { if (data.code === 0 || data.success === true) { resolve(data) } else { console.error('=== 业务错误 ===') console.error('Code:', data.code) console.error('Message:', data.message) if (!noAuthModal) { uni.showModal({ title: '请求失败', content: data.message || '服务器返回错误', showCancel: false }) } reject(data) } } else { console.error('=== HTTP错误 ===') console.error('StatusCode:', statusCode) console.error('Response:', data) if (!noAuthModal) { uni.showModal({ title: '网络错误', content: `状态码: ${statusCode}`, showCancel: false }) } reject(res) } }, fail: (err) => { console.error('=== 请求失败 ===') console.error('Error:', err) console.error('Error Message:', err.errMsg) let errorMsg = '网络连接失败' if (err.errMsg) { if (err.errMsg.includes('timeout')) { errorMsg = '请求超时,请检查网络' } else if (err.errMsg.includes('fail')) { errorMsg = '网络连接失败,请检查网络设置' } else if (err.errMsg.includes('request:fail')) { errorMsg = `连接失败: ${err.errMsg}` } } if (!noAuthModal) { uni.showModal({ title: '错误', content: errorMsg, showCancel: false }) } reject(err) } }) }) } const api = { wxLogin(code) { return request({ url: config.api.login, method: 'POST', data: { wxMiniCode: code } }) }, getQuestion(categorySn) { return request({ url: config.api.getQuestion, method: 'POST', data: categorySn ? { category_sn: categorySn } : {} }) }, answerQuestion(sn, answer) { return request({ url: config.api.answerQuestion, method: 'POST', data: { sn, answer } }) }, getCategoryQuestion(categorySn) { return request({ url: config.api.getCategoryQuestion, method: 'POST', data: { category_sn: categorySn } }) }, answerCategoryQuestion(sn, answer) { return request({ url: config.api.answerCategoryQuestion, method: 'POST', data: { sn, answer } }) }, getQuicklyQuestion() { return request({ url: config.api.getQuicklyQuestion, method: 'POST' }) }, answerQuicklyQuestion(sn, answer) { return request({ url: config.api.answerQuicklyQuestion, method: 'POST', data: { sn, answer } }) }, getAllCategory() { return request({ url: config.api.getAllCategory, method: 'POST' }) }, getRecord(page = 1, pageSize = 10) { return request({ url: '/qgdzs/auth/get_record', method: 'POST', data: { page, page_size: pageSize }, noAuthModal: true }) }, getQuestionBySn(questionSn) { return request({ url: '/qgdzs/open/get_question', method: 'POST', data: { question_sn: questionSn } }) }, getQuestionInfo(questionSn) { return request({ url: '/qgdzs/open/get_question_info', method: 'POST', data: { question_sn: questionSn } }) }, get(url, data = {}) { return request({ url, method: 'GET', data }) }, post(url, data = {}) { return request({ url, method: 'POST', data }) }, put(url, data = {}) { return request({ url, method: 'PUT', data }) }, delete(url, data = {}) { return request({ url, method: 'DELETE', data }) } } export default api