Simplify App bootstrap, cast HTTP helpers for vue-tsc, and align leftover string ids. Co-authored-by: Cursor <cursoragent@cursor.com>
98 lines
2.9 KiB
TypeScript
98 lines
2.9 KiB
TypeScript
/**
|
||
* 地磅(db)模块 HTTP 客户端
|
||
* 协议:直接 JSON 响应(非门户 code/data 信封)
|
||
*/
|
||
import axios, { type AxiosRequestConfig, type InternalAxiosRequestConfig } from 'axios'
|
||
import { showToast } from 'vant'
|
||
import { useUserStore } from '@/store/modules/user'
|
||
|
||
type RetryableConfig = InternalAxiosRequestConfig & {
|
||
_retry?: boolean
|
||
showErrorMessage?: boolean
|
||
}
|
||
|
||
/** 地磅集合根路径须带尾斜杠,否则 307 会丢 Authorization */
|
||
const DB_COLLECTION_ROOT = /^\/(plans|inventory|weighing)$/
|
||
|
||
function normalizeDbUrl(url?: string): string | undefined {
|
||
if (!url || url.endsWith('/')) return url
|
||
return DB_COLLECTION_ROOT.test(url) ? `${url}/` : url
|
||
}
|
||
|
||
const getBaseURL = () => {
|
||
if (import.meta.env.DEV) return '/api'
|
||
return import.meta.env.VITE_API_URL || '/api'
|
||
}
|
||
|
||
const dbAxios = axios.create({
|
||
baseURL: getBaseURL(),
|
||
timeout: 60000,
|
||
headers: { 'Content-Type': 'application/json' }
|
||
})
|
||
|
||
dbAxios.interceptors.request.use((config: InternalAxiosRequestConfig) => {
|
||
if (config.url) {
|
||
config.url = normalizeDbUrl(config.url)
|
||
}
|
||
const store = useUserStore()
|
||
const token = store.accessToken || sessionStorage.getItem('accessToken') || ''
|
||
if (token) {
|
||
config.headers.Authorization = `Bearer ${token}`
|
||
}
|
||
return config
|
||
})
|
||
|
||
dbAxios.interceptors.response.use(
|
||
(res) => res.data,
|
||
async (err) => {
|
||
const status = err.response?.status
|
||
const config = err.config as RetryableConfig | undefined
|
||
|
||
if (status === 401) {
|
||
const userStore = useUserStore()
|
||
userStore.logOut()
|
||
showToast({ type: 'fail', message: '登录已过期,请重新登录' })
|
||
setTimeout(() => {
|
||
window.location.hash = '#/login'
|
||
}, 1500)
|
||
return Promise.reject(err)
|
||
}
|
||
|
||
if (config?.showErrorMessage !== false) {
|
||
const detail = err.response?.data?.detail
|
||
const message =
|
||
typeof detail === 'string'
|
||
? detail
|
||
: Array.isArray(detail)
|
||
? detail.map((x: { msg?: string }) => x.msg).filter(Boolean).join(';')
|
||
: err.response?.data?.message || err.response?.data?.msg
|
||
showToast({ type: 'fail', message: message || err.message || '网络异常' })
|
||
}
|
||
return Promise.reject(err)
|
||
}
|
||
)
|
||
|
||
function request<T = unknown>(config: AxiosRequestConfig): Promise<T> {
|
||
return dbAxios.request<any, T>(config) as Promise<T>
|
||
}
|
||
|
||
const db = {
|
||
get<T = unknown>(config: AxiosRequestConfig): Promise<T> {
|
||
return request<T>({ ...config, method: 'GET' })
|
||
},
|
||
post<T = unknown>(config: AxiosRequestConfig): Promise<T> {
|
||
return request<T>({ ...config, method: 'POST' })
|
||
},
|
||
put<T = unknown>(config: AxiosRequestConfig): Promise<T> {
|
||
return request<T>({ ...config, method: 'PUT' })
|
||
},
|
||
patch<T = unknown>(config: AxiosRequestConfig): Promise<T> {
|
||
return request<T>({ ...config, method: 'PATCH' })
|
||
},
|
||
del<T = unknown>(config: AxiosRequestConfig): Promise<T> {
|
||
return request<T>({ ...config, method: 'DELETE' })
|
||
}
|
||
}
|
||
|
||
export default db
|