2026-08-31 11:33:59 +08:00
|
|
|
|
import config from '@/config/index.js'
|
|
|
|
|
|
|
|
|
|
|
|
function buildUrl(url, baseURL = config.baseURL) {
|
|
|
|
|
|
const normalizedBaseURL = baseURL.endsWith('/') ? baseURL.slice(0, -1) : baseURL
|
|
|
|
|
|
const path = url.startsWith('/') ? url : `/${url}`
|
|
|
|
|
|
return `${normalizedBaseURL}${path}`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function getNetworkErrorMessage(error) {
|
|
|
|
|
|
const errorMessage = String(error?.errMsg || '')
|
|
|
|
|
|
if (errorMessage.toLowerCase().includes('timeout')) {
|
|
|
|
|
|
return '请求超时,请稍后重试'
|
|
|
|
|
|
}
|
|
|
|
|
|
return '无法连接服务器,请检查网络后重试'
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function getHeaders(headers = {}, includeJsonContentType = true) {
|
|
|
|
|
|
const token = uni.getStorageSync(config.tokenKey)
|
|
|
|
|
|
const result = {
|
|
|
|
|
|
...(includeJsonContentType ? { 'Content-Type': 'application/json' } : {}),
|
|
|
|
|
|
[config.channelHeaderKey]: config.channel,
|
|
|
|
|
|
...headers
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (token) {
|
|
|
|
|
|
result[config.tokenHeaderKey] = String(token).startsWith('Bearer ') ? token : `Bearer ${token}`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-03 19:56:19 +08:00
|
|
|
|
async function refreshAccessToken() {
|
|
|
|
|
|
const refreshToken = uni.getStorageSync('scanapp_refresh_token')
|
|
|
|
|
|
if (!refreshToken) return ''
|
|
|
|
|
|
const response = await uniRequest('/auth/refresh', 'POST', { refresh_token: refreshToken }, {
|
|
|
|
|
|
baseURL: config.apiBaseURL,
|
|
|
|
|
|
showError: false
|
|
|
|
|
|
})
|
|
|
|
|
|
const accessToken = response?.access_token
|
|
|
|
|
|
if (!accessToken) return ''
|
|
|
|
|
|
uni.setStorageSync(config.tokenKey, accessToken)
|
|
|
|
|
|
if (response.refresh_token) uni.setStorageSync('scanapp_refresh_token', response.refresh_token)
|
|
|
|
|
|
return accessToken
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function uniRequest(url, method, data = {}, options = {}) {
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
|
const requestUrl = buildUrl(url, options.baseURL || config.baseURL)
|
|
|
|
|
|
uni.request({
|
|
|
|
|
|
url: requestUrl,
|
|
|
|
|
|
method,
|
|
|
|
|
|
data,
|
|
|
|
|
|
header: getHeaders(options.headers),
|
|
|
|
|
|
timeout: options.timeout || 15000,
|
|
|
|
|
|
success: (res) => {
|
|
|
|
|
|
let body = res.data || {}
|
|
|
|
|
|
if (typeof body === 'string') {
|
|
|
|
|
|
try { body = JSON.parse(body) } catch { body = { msg: body } }
|
|
|
|
|
|
}
|
|
|
|
|
|
if (Number(body.code) === 0) {
|
|
|
|
|
|
resolve(body.data)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
reject(new Error(body.msg || '请求失败'))
|
|
|
|
|
|
},
|
|
|
|
|
|
fail: () => reject(new Error('网络请求失败'))
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-31 11:33:59 +08:00
|
|
|
|
function request(url, method, data = {}, options = {}) {
|
|
|
|
|
|
const baseURL = options.baseURL || config.baseURL
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
|
const requestUrl = buildUrl(url, baseURL)
|
|
|
|
|
|
uni.request({
|
|
|
|
|
|
url: requestUrl,
|
|
|
|
|
|
method,
|
|
|
|
|
|
data,
|
|
|
|
|
|
header: getHeaders(options.headers),
|
|
|
|
|
|
timeout: options.timeout || 15000,
|
2026-09-03 19:56:19 +08:00
|
|
|
|
success: async (res) => {
|
2026-08-31 11:33:59 +08:00
|
|
|
|
let body = res.data || {}
|
|
|
|
|
|
if (typeof body === 'string') {
|
|
|
|
|
|
try {
|
|
|
|
|
|
body = JSON.parse(body)
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
body = { msg: body }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-03 19:56:19 +08:00
|
|
|
|
if (Number(body.code) === 401 && !options._retry) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const token = await refreshAccessToken()
|
|
|
|
|
|
if (token) {
|
|
|
|
|
|
resolve(request(url, method, data, { ...options, _retry: true }))
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('[scanapp] 刷新登录令牌失败', error)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-31 11:33:59 +08:00
|
|
|
|
if (Number(body.code) === 0) {
|
|
|
|
|
|
resolve(options.returnFullResponse ? body : body.data)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const message = body.msg || `请求失败(HTTP ${res.statusCode || 0},code ${body.code ?? 'unknown'})`
|
|
|
|
|
|
console.error('[scanapp] 请求失败', {
|
|
|
|
|
|
url: requestUrl,
|
|
|
|
|
|
statusCode: res.statusCode,
|
|
|
|
|
|
code: body.code,
|
|
|
|
|
|
message,
|
|
|
|
|
|
body
|
|
|
|
|
|
})
|
|
|
|
|
|
if (options.showError !== false) {
|
|
|
|
|
|
uni.showToast({ title: message, icon: 'none' })
|
|
|
|
|
|
}
|
|
|
|
|
|
reject(new Error(message))
|
|
|
|
|
|
},
|
|
|
|
|
|
fail: (error) => {
|
|
|
|
|
|
const message = getNetworkErrorMessage(error)
|
|
|
|
|
|
console.error('[scanapp] 网络请求失败', {
|
|
|
|
|
|
url: requestUrl,
|
|
|
|
|
|
rawMessage: error?.errMsg,
|
|
|
|
|
|
message,
|
|
|
|
|
|
error
|
|
|
|
|
|
})
|
|
|
|
|
|
if (options.showError !== false) {
|
|
|
|
|
|
uni.showToast({ title: message, icon: 'none' })
|
|
|
|
|
|
}
|
|
|
|
|
|
reject(new Error(message))
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function uploadFile(url, filePath, formData = {}, options = {}) {
|
|
|
|
|
|
const baseURL = options.baseURL || config.baseURL
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
|
const requestUrl = buildUrl(url, baseURL)
|
|
|
|
|
|
const token = uni.getStorageSync(config.tokenKey)
|
|
|
|
|
|
const header = getHeaders(options.headers, false)
|
|
|
|
|
|
if (token) {
|
|
|
|
|
|
header[config.tokenHeaderKey] = String(token).startsWith('Bearer ') ? token : `Bearer ${token}`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uni.uploadFile({
|
|
|
|
|
|
url: requestUrl,
|
|
|
|
|
|
filePath,
|
|
|
|
|
|
name: options.name || 'file',
|
|
|
|
|
|
formData,
|
|
|
|
|
|
header,
|
|
|
|
|
|
timeout: options.timeout || 30000,
|
|
|
|
|
|
success: (res) => {
|
|
|
|
|
|
let body = res.data || {}
|
|
|
|
|
|
if (typeof body === 'string') {
|
|
|
|
|
|
try {
|
|
|
|
|
|
body = JSON.parse(body)
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
body = { msg: body }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (Number(body.code) === 0) {
|
|
|
|
|
|
resolve(options.returnFullResponse ? body : body.data)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const message = body.msg || `上传失败(HTTP ${res.statusCode || 0},code ${body.code ?? 'unknown'})`
|
|
|
|
|
|
if (options.showError !== false) {
|
|
|
|
|
|
uni.showToast({ title: message, icon: 'none' })
|
|
|
|
|
|
}
|
|
|
|
|
|
reject(new Error(message))
|
|
|
|
|
|
},
|
|
|
|
|
|
fail: (error) => {
|
|
|
|
|
|
const message = getNetworkErrorMessage(error)
|
|
|
|
|
|
if (options.showError !== false) {
|
|
|
|
|
|
uni.showToast({ title: message, icon: 'none' })
|
|
|
|
|
|
}
|
|
|
|
|
|
reject(new Error(message))
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
get(url, data = {}, options = {}) {
|
|
|
|
|
|
return request(url, 'GET', data, options)
|
|
|
|
|
|
},
|
|
|
|
|
|
post(url, data = {}, options = {}) {
|
|
|
|
|
|
return request(url, 'POST', data, options)
|
|
|
|
|
|
},
|
|
|
|
|
|
put(url, data = {}, options = {}) {
|
|
|
|
|
|
return request(url, 'PUT', data, options)
|
|
|
|
|
|
},
|
|
|
|
|
|
delete(url, data = {}, options = {}) {
|
|
|
|
|
|
return request(url, 'DELETE', data, options)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|