refactor(project): Reorganize frontend and backend directories

This commit is contained in:
2026-03-18 10:45:15 +08:00
parent cc9eaf4cdf
commit 92a139e470
513 changed files with 28251 additions and 287 deletions
@@ -0,0 +1,132 @@
import axios, { type AxiosInstance, type AxiosRequestConfig, type AxiosResponse, type InternalAxiosRequestConfig } from 'axios'
import { useUserStore } from '@/stores/user.ts'
import { showToast } from 'vant'
import router from '@/router'
// API 基础配置
const BASE_URL = import.meta.env.VITE_API_BASE_URL || '/api'
const TIMEOUT = 30000
// 创建 axios 实例
const service: AxiosInstance = axios.create({
baseURL: BASE_URL,
timeout: TIMEOUT,
headers: {
'Content-Type': 'application/json'
}
})
// 请求拦截器
service.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
const userStore = useUserStore()
// 添加 Token
if (userStore.token) {
config.headers.Authorization = `Bearer ${userStore.token}`
}
return config
},
(error) => {
console.error('请求错误:', error)
return Promise.reject(error)
}
)
// 响应拦截器
service.interceptors.response.use(
(response: AxiosResponse) => {
const { data } = response
// 业务状态码判断
if (data.code === 200) {
return data.data
}
// Token 过期
if (data.code === 401) {
const userStore = useUserStore()
userStore.logout()
router.push('/login')
showToast('登录已过期,请重新登录')
return Promise.reject(new Error('Token expired'))
}
// 其他业务错误
showToast(data.message || '请求失败')
return Promise.reject(new Error(data.message || '请求失败'))
},
(error) => {
console.error('响应错误:', error)
// 网络错误
if (error.code === 'ECONNABORTED') {
showToast('请求超时,请稍后重试')
} else if (error.message.includes('Network Error')) {
showToast('网络错误,请检查网络连接')
} else if (error.response) {
const status = error.response.status
switch (status) {
case 401:
const userStore = useUserStore()
userStore.logout()
router.push('/login')
showToast('登录已过期,请重新登录')
break
case 403:
showToast('没有权限访问')
break
case 404:
showToast('请求的资源不存在')
break
case 500:
showToast('服务器错误,请稍后重试')
break
default:
showToast(`请求失败: ${status}`)
}
}
return Promise.reject(error)
}
)
// 封装请求方法
const request = {
get<T = any>(url: string, params?: object, config?: AxiosRequestConfig): Promise<T> {
return service.get(url, { params, ...config })
},
post<T = any>(url: string, data?: object, config?: AxiosRequestConfig): Promise<T> {
return service.post(url, data, config)
},
put<T = any>(url: string, data?: object, config?: AxiosRequestConfig): Promise<T> {
return service.put(url, data, config)
},
delete<T = any>(url: string, params?: object, config?: AxiosRequestConfig): Promise<T> {
return service.delete(url, { params, ...config })
},
upload<T = any>(url: string, file: File, onProgress?: (percent: number) => void): Promise<T> {
const formData = new FormData()
formData.append('file', file)
return service.post(url, formData, {
headers: {
'Content-Type': 'multipart/form-data'
},
onUploadProgress: (progressEvent) => {
if (progressEvent.total && onProgress) {
const percent = Math.round((progressEvent.loaded * 100) / progressEvent.total)
onProgress(percent)
}
}
})
}
}
export default request
export { service as axiosInstance }