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

337 lines
9.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 网络请求封装
*/
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