Files
QSY-lvjuxcx/utils/request.js
2026-06-29 09:42:53 +08:00

211 lines
5.6 KiB
JavaScript

import { config } from '../config.js'
import { clearLoginSession, getAuthToken } from './app-state'
import { getCurrentLanguage } from './i18n'
const API_BASE_URL = config.baseURL
const FILE_BASE_URL = config.filePrefix
const FIXED_PROVIDER_TYPE = 'WechatMiniProgram'
function getRequestText(key = '') {
const language = getCurrentLanguage()
const isEn = language === 'en'
const map = {
requestFailed: isEn ? 'Request failed' : '请求失败',
loginExpired: isEn ? 'Login expired. Please sign in again' : '登录已过期,请重新登录',
tooManyRequests: isEn ? 'Too many requests. Please try again later' : '操作太频繁了,请稍后再试',
networkFailed: isEn ? 'Network request failed' : '网络请求失败'
}
return map[key] || ''
}
function normalizeUrl(url = '') {
if (/^https?:\/\//i.test(url)) {
return url
}
if (!url) {
return API_BASE_URL
}
if (url.startsWith('/')) {
return `${API_BASE_URL}${url}`
}
return `${API_BASE_URL}/${url}`
}
function isPlainRequestObject(value) {
return !!value && typeof value === 'object' && !Array.isArray(value)
}
function appendFixedProviderType(payload) {
if (isPlainRequestObject(payload)) {
return {
...payload,
ProviderType: FIXED_PROVIDER_TYPE
}
}
return {
ProviderType: FIXED_PROVIDER_TYPE
}
}
function hasBusinessCode(payload) {
return !!payload && typeof payload === 'object' && Object.prototype.hasOwnProperty.call(payload, 'code')
}
function isBusinessSuccess(payload) {
if (!hasBusinessCode(payload)) {
return true
}
const code = String(payload.code)
return code === '200' || code === '0'
}
function normalizeBusinessError(payload, fallback = {}) {
const message = (payload && (payload.msg || payload.message)) || fallback.errMsg || getRequestText('requestFailed')
return {
...fallback,
...(payload && typeof payload === 'object' ? payload : {}),
message
}
}
function getCurrentRoute() {
const pages = getCurrentPages()
if (!Array.isArray(pages) || !pages.length) {
return ''
}
const currentPage = pages[pages.length - 1] || {}
return currentPage.route || ''
}
function shouldSkipUnauthorizedRedirect() {
const route = getCurrentRoute()
return route === 'pkgAccount/login/login' || route === 'pages/login/index' || route === 'pages/login/login'
}
function handleUnauthorized(responseData) {
clearLoginSession()
if (shouldSkipUnauthorizedRedirect()) {
return
}
uni.showToast({
title: getRequestText('loginExpired'),
icon: 'none',
duration: 2000
})
setTimeout(() => {
uni.reLaunch({
url: '/pkgAccount/login/login'
})
}, 500)
}
export function request(options = {}) {
const {
url = '',
method = 'GET',
data,
params,
header = {},
hideErrorToast = false,
withAuth = true
} = options
return new Promise((resolve, reject) => {
const token = withAuth ? getAuthToken() : ''
const uppercaseMethod = String(method || 'GET').toUpperCase()
const normalizedParams = appendFixedProviderType(params)
const normalizedData = appendFixedProviderType(data)
uni.request({
url: normalizeUrl(url),
method: uppercaseMethod,
data: uppercaseMethod === 'GET'
? (params !== undefined ? normalizedParams : normalizedData)
: normalizedData,
header: {
'Content-Type': 'application/json',
'X-Requested-Language': getCurrentLanguage(),
...(token ? { Authorization: `Bearer ${token}` } : {}),
...header
},
success: (res) => {
const { statusCode, data: responseData } = res
if ((statusCode === 401) || (responseData && Number(responseData.code) === 401)) {
handleUnauthorized(responseData)
reject(normalizeBusinessError(responseData, res))
return
}
if (statusCode === 429) {
if (!hideErrorToast) {
uni.showToast({
title: getRequestText('tooManyRequests'),
icon: 'none',
duration: 2500
})
}
reject({
...normalizeBusinessError(responseData, res),
message: getRequestText('tooManyRequests'),
__toastShown: !hideErrorToast
})
return
}
if (statusCode >= 200 && statusCode < 300) {
if (isBusinessSuccess(responseData)) {
resolve(responseData)
return
}
const businessError = normalizeBusinessError(responseData, res)
if (!hideErrorToast) {
uni.showToast({
title: businessError.message || getRequestText('requestFailed'),
icon: 'none',
duration: 2000
})
}
reject({
...businessError,
__toastShown: !hideErrorToast
})
return
}
const requestError = normalizeBusinessError(responseData, res)
if (!hideErrorToast) {
uni.showToast({
title: requestError.message || getRequestText('requestFailed'),
icon: 'none'
})
}
reject({
...requestError,
__toastShown: !hideErrorToast
})
},
fail: (error) => {
const requestError = normalizeBusinessError(null, error)
if (!hideErrorToast) {
uni.showToast({
title: requestError.message || getRequestText('networkFailed'),
icon: 'none'
})
}
reject({
...requestError,
__toastShown: !hideErrorToast
})
}
})
})
}
export { API_BASE_URL, FILE_BASE_URL }
export default request