peixue-dev/peidu/uniapp/utils/request.js

337 lines
9.6 KiB
JavaScript
Raw Normal View History

/**
* 网络请求封装
*/
import { useUserStore } from '@/store/user'
// 根据环境自动切换API地址
// 开发环境:统一使用本地服务器
// 生产环境:使用线上服务器
// 开发模式标志(手动切换)
const IS_DEV = true // 改为 true 则使用本地开发环境
// 根据开发模式选择BASE_URL
const BASE_URL = IS_DEV
? 'http://localhost:8089' // 开发环境 - 本地服务器
: 'https://px.ddn-ai.cloud' // 生产环境 - 线上服务器
console.log('[Request] 当前环境:', IS_DEV ? '开发环境' : '生产环境')
console.log('[Request] BASE_URL:', BASE_URL)
const LOGIN_EXCLUDE_URLS = [
'/api/auth/login',
'/api/auth/wx-login',
'/api/user/login/wechat',
'/api/auth/register',
'/api/auth/reapply',
'/api/auth/send-code',
'/api/auth/refresh-token'
]
let isHandlingAuthExpired = false
function buildAuthHeader(token) {
if (!token) return ''
return token.startsWith('Bearer ') ? token : `Bearer ${token}`
}
function normalizeToken(token) {
return buildAuthHeader(token)
}
function shouldHandleAuthExpired(url) {
return !LOGIN_EXCLUDE_URLS.includes(url)
}
/**
* 发送请求
*/
function request(options) {
return new Promise((resolve, reject) => {
// 获取租户ID
const tenantId = uni.getStorageSync('currentTenantId')
// 获取token
const token = uni.getStorageSync('token')
const requestToken = token
// 设置请求头
const header = {
'Content-Type': 'application/json;charset=UTF-8',
...options.header
}
// 添加租户ID到请求头
if (tenantId) {
header['X-Tenant-Id'] = tenantId
}
// 添加token到请求头
if (token) {
const authHeader = buildAuthHeader(token)
header['Authorization'] = authHeader
console.log('[Request] 发送请求token:', token)
console.log('[Request] Authorization头:', authHeader)
}
// 处理 GET 请求参数(拼接到 URL
let url = BASE_URL + options.url
if (options.method === 'GET' && options.params) {
const queryString = Object.keys(options.params)
.filter(key => options.params[key] !== null && options.params[key] !== undefined && options.params[key] !== '')
.map(key => {
const value = options.params[key]
const encodedValue = (value !== null && typeof value === 'object')
? encodeURIComponent(JSON.stringify(value))
: encodeURIComponent(value)
return `${encodeURIComponent(key)}=${encodedValue}`
})
.join('&')
if (queryString) {
url += (url.includes('?') ? '&' : '?') + queryString
}
console.log('[Request] GET URL:', url)
console.log('[Request] GET Params:', options.params)
}
// 发送请求
uni.request({
url: url,
method: options.method || 'GET',
data: options.method === 'GET' ? undefined : (options.data || options.params),
header: header,
success: (res) => {
console.log('[Request] Response:', res)
// 处理401未登录
if (res.statusCode === 401) {
if (!shouldHandleAuthExpired(options.url)) {
reject({ code: 401, message: '未登录', data: res })
return
}
const latestToken = uni.getStorageSync('token')
if (latestToken && normalizeToken(requestToken) !== normalizeToken(latestToken)) {
reject({ code: 401, message: '未登录', data: res })
return
}
if (isHandlingAuthExpired) {
reject({ code: 401, message: '未登录', data: res })
return
}
isHandlingAuthExpired = true
console.log('[Request] 401 未登录清除token')
uni.removeStorageSync('token')
uni.removeStorageSync('userInfo')
uni.showModal({
title: '登录已过期',
content: '请重新登录',
showCancel: false,
success: () => {
uni.reLaunch({
url: '/pages/login/index'
})
},
complete: () => {
setTimeout(() => {
isHandlingAuthExpired = false
}, 500)
}
})
reject({ code: 401, message: '未登录', data: res })
return
}
if (res.statusCode === 200) {
if (res.data && typeof res.data === 'object' && res.data.code === 401) {
if (!shouldHandleAuthExpired(options.url)) {
reject({ code: 401, message: '未登录', data: res.data })
return
}
const latestToken = uni.getStorageSync('token')
if (latestToken && normalizeToken(requestToken) !== normalizeToken(latestToken)) {
reject({ code: 401, message: '未登录', data: res.data })
return
}
if (!isHandlingAuthExpired) {
isHandlingAuthExpired = true
console.log('[Request] 业务码401 未登录,清除所有登录信息')
uni.removeStorageSync('token')
uni.removeStorageSync('userInfo')
uni.removeStorageSync('currentRole') // 🔥 关键修复:也清除角色信息
uni.showModal({
title: '登录已过期',
content: '请重新登录',
showCancel: false,
success: () => {
uni.reLaunch({
url: '/pages/login/index'
})
},
complete: () => {
setTimeout(() => {
isHandlingAuthExpired = false
}, 500)
}
})
}
reject({ code: 401, message: '未登录', data: res.data })
return
}
// 返回完整的响应对象,让调用方自己处理
resolve(res.data)
} else if (res.statusCode === 404) {
console.error('[Request] 404 Not Found:', url)
uni.showToast({
title: '接口不存在',
icon: 'none'
})
reject({ code: 404, message: '接口不存在', data: res })
} else if (res.statusCode === 500) {
console.error('[Request] 500 Server Error:', res)
uni.showToast({
title: '服务器错误',
icon: 'none'
})
reject({ code: 500, message: '服务器错误', data: res })
} else {
console.error('[Request] Error:', res.statusCode, res)
uni.showToast({
title: `网络错误(${res.statusCode})`,
icon: 'none'
})
reject(res)
}
},
fail: (err) => {
console.error('[Request] Fail:', err)
uni.showToast({
title: '网络连接失败',
icon: 'none'
})
reject(err)
}
})
})
}
// 导出便捷方法
request.get = function(url, params) {
return request({
url: url,
method: 'GET',
params: params
})
}
request.post = function(url, data, params) {
// 如果有 params拼接到 URL
if (params && typeof params === 'object') {
const queryString = Object.keys(params)
.filter(key => params[key] !== null && params[key] !== undefined && params[key] !== '')
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
.join('&')
if (queryString) {
url += (url.includes('?') ? '&' : '?') + queryString
}
}
return request({
url: url,
method: 'POST',
data: data,
params: params
})
}
request.put = function(url, data, params) {
// 如果有 params拼接到 URL
if (params && typeof params === 'object') {
const queryString = Object.keys(params)
.filter(key => params[key] !== null && params[key] !== undefined && params[key] !== '')
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
.join('&')
if (queryString) {
url += (url.includes('?') ? '&' : '?') + queryString
}
}
return request({
url: url,
method: 'PUT',
data: data,
params: params
})
}
request.delete = function(url, params) {
return request({
url: url,
method: 'DELETE',
params: params
})
}
request.upload = function(url, filePath) {
return new Promise((resolve, reject) => {
const token = uni.getStorageSync('token')
const tenantId = uni.getStorageSync('currentTenantId')
const header = {
'Authorization': token ? `Bearer ${token}` : ''
}
if (tenantId) {
header['X-Tenant-Id'] = tenantId
}
const uploadTask = uni.uploadFile({
url: BASE_URL + url,
filePath: filePath,
name: 'file',
header: header,
timeout: 60000, // 60秒超时
success: (res) => {
try {
const data = JSON.parse(res.data)
if (data.code === 200) {
resolve(data.data)
} else {
uni.showToast({
title: data.message || '上传失败',
icon: 'none'
})
reject(data)
}
} catch (e) {
console.error('解析上传响应失败:', res.data)
reject({ message: '服务器响应异常' })
}
},
fail: (err) => {
console.error('上传失败:', err)
uni.showToast({
title: err.errMsg || '上传失败',
icon: 'none'
})
reject(err)
}
})
// 监听上传进度
uploadTask.onProgressUpdate((res) => {
console.log('上传进度:', res.progress + '%')
})
})
}
export default request