2025-10-09 09:29:36 +08:00
|
|
|
|
import axios from 'axios'
|
2025-10-23 13:43:42 +08:00
|
|
|
|
import { showToast, showNotify, showConfirmDialog, closeToast } from 'vant'
|
2025-10-09 09:29:36 +08:00
|
|
|
|
import { getLocal } from '@/utils/local'
|
2025-10-23 13:43:42 +08:00
|
|
|
|
import router from '@/router/index'
|
2025-10-27 14:02:26 +08:00
|
|
|
|
import { useOverallStore, useGenerateStore, useUserInfoStore } from '@/stores'
|
2025-10-23 13:43:42 +08:00
|
|
|
|
|
2025-10-27 11:08:26 +08:00
|
|
|
|
// 扩展 AxiosRequestConfig 接口
|
|
|
|
|
|
declare module 'axios' {
|
|
|
|
|
|
interface AxiosRequestConfig {
|
|
|
|
|
|
loading?: boolean
|
|
|
|
|
|
loadingDom?: any
|
|
|
|
|
|
repeatRequest?: boolean
|
|
|
|
|
|
meta?: {
|
|
|
|
|
|
responseAll?: boolean
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-09 09:29:36 +08:00
|
|
|
|
// 创建axios实例
|
2025-10-24 17:36:00 +08:00
|
|
|
|
// console.log(import.meta.env,123)
|
|
|
|
|
|
|
2025-10-09 09:29:36 +08:00
|
|
|
|
const service = axios.create({
|
2025-10-27 11:43:07 +08:00
|
|
|
|
// baseURL: import.meta.env.VITE_APP_URL, // api的base_url
|
|
|
|
|
|
timeout: 20000 // 请求超时时间
|
2025-10-09 09:29:36 +08:00
|
|
|
|
})
|
2025-10-27 11:43:07 +08:00
|
|
|
|
if (import.meta.env.MODE != 'development') {
|
2025-10-24 17:36:00 +08:00
|
|
|
|
service.defaults.baseURL = import.meta.env.VITE_APP_URL
|
|
|
|
|
|
}
|
2025-10-27 11:43:07 +08:00
|
|
|
|
axios.defaults.headers.post['Content-Type'] = 'application/json'
|
|
|
|
|
|
axios.defaults.headers.post['lang'] = 'en' //配置语言请求头
|
|
|
|
|
|
axios.defaults.withCredentials = true //跨域携带cookie
|
2025-10-09 09:29:36 +08:00
|
|
|
|
|
|
|
|
|
|
// request拦截器
|
|
|
|
|
|
service.interceptors.request.use(
|
|
|
|
|
|
(config: any) => {
|
|
|
|
|
|
removePending(config)
|
|
|
|
|
|
// 如果repeatRequest不配置,那么默认该请求就取消重复接口请求
|
|
|
|
|
|
!config.repeatRequest && addPending(config)
|
|
|
|
|
|
// 打开loading
|
|
|
|
|
|
if (config.loading) {
|
|
|
|
|
|
LoadingInstance._count++
|
|
|
|
|
|
if (LoadingInstance._count === 1) {
|
|
|
|
|
|
openLoading(config.loadingDom)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 如果登录了,有token,则请求携带token
|
|
|
|
|
|
// Do something before request is sent
|
2025-10-27 14:02:26 +08:00
|
|
|
|
const token = useUserInfoStore().state.token
|
|
|
|
|
|
if (token) {
|
|
|
|
|
|
config.headers.Authorization = token // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
|
2025-10-27 11:43:07 +08:00
|
|
|
|
// config.headers['X-Token'] = getLocal('token') // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
|
2025-10-09 09:29:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
return config
|
|
|
|
|
|
},
|
|
|
|
|
|
(error) => {
|
|
|
|
|
|
// Do something with request error
|
|
|
|
|
|
console.log(error) // for debug
|
|
|
|
|
|
Promise.reject(error)
|
|
|
|
|
|
}
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// respone拦截器
|
|
|
|
|
|
service.interceptors.response.use(
|
|
|
|
|
|
// response => response,
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页
|
|
|
|
|
|
* 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
|
|
|
|
|
|
*/
|
|
|
|
|
|
(response: any) => {
|
2025-10-28 11:33:20 +08:00
|
|
|
|
// 如果是llm/streamChat这样的流式接口,不走这样的处理
|
|
|
|
|
|
if (response.config.url.includes('llm/streamChat')) {
|
|
|
|
|
|
return response
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-09 09:29:36 +08:00
|
|
|
|
// 已完成请求的删除请求中数组
|
|
|
|
|
|
removePending(response.config)
|
|
|
|
|
|
// 关闭loading
|
|
|
|
|
|
if (response.config.loading) {
|
|
|
|
|
|
closeLoading()
|
|
|
|
|
|
}
|
|
|
|
|
|
const res = response.data
|
|
|
|
|
|
// 处理异常的情况
|
2025-10-27 11:43:07 +08:00
|
|
|
|
console.log(res)
|
2025-10-24 14:05:28 +08:00
|
|
|
|
if (res.code != 0) {
|
2025-10-09 11:33:47 +08:00
|
|
|
|
showToast({
|
2025-10-27 11:43:07 +08:00
|
|
|
|
message: res.errMsg || res.message,
|
|
|
|
|
|
// type: 'fail',
|
|
|
|
|
|
duration: 5000,
|
2025-10-28 11:33:20 +08:00
|
|
|
|
position: 'top',
|
|
|
|
|
|
icon: 'none'
|
2025-10-09 09:29:36 +08:00
|
|
|
|
})
|
2025-10-27 11:43:07 +08:00
|
|
|
|
|
2025-10-09 09:29:36 +08:00
|
|
|
|
return Promise.reject(new Error('error'))
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 默认只返回data,不返回状态码和message
|
|
|
|
|
|
// 通过 meta 中的 responseAll 配置来取决后台是否返回所有数据(包括状态码,message和data)
|
|
|
|
|
|
const isbackAll = response.config.meta && response.config.meta.responseAll
|
|
|
|
|
|
if (isbackAll) {
|
|
|
|
|
|
return res
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return res.data
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
(error) => {
|
2025-10-24 15:18:23 +08:00
|
|
|
|
if(error?.response){
|
2025-10-27 11:52:15 +08:00
|
|
|
|
if (error.config?.loading) closeLoading() // 关闭loading
|
2025-10-24 15:18:23 +08:00
|
|
|
|
if(error?.response?.status === 401){//如果是记录浏览器页面就不跳转login
|
|
|
|
|
|
// showConfirmDialog({
|
|
|
|
|
|
// title: '确定登出',
|
|
|
|
|
|
// message: '你已被登出,可以取消继续留在该页面,或者重新登录',
|
|
|
|
|
|
// confirmButtonText: '重新登录',
|
|
|
|
|
|
// cancelButtonText: '取消'
|
|
|
|
|
|
// }).then(() => {
|
|
|
|
|
|
// store.loginOut().then(() => {
|
|
|
|
|
|
// location.reload() // 为了重新实例化vue-router对象 避免bug
|
|
|
|
|
|
// })
|
|
|
|
|
|
// })
|
2025-10-27 11:26:21 +08:00
|
|
|
|
showToast({
|
|
|
|
|
|
message: 'Please log in and try again.',
|
|
|
|
|
|
duration: 5000
|
|
|
|
|
|
})
|
|
|
|
|
|
router.push('/welcome')
|
|
|
|
|
|
useGenerateStore().clearGenerateData()
|
|
|
|
|
|
return Promise.reject(false)
|
2025-10-24 15:18:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
error.config && removePending(error.config)
|
|
|
|
|
|
console.log('err' + error) // for debug
|
|
|
|
|
|
showToast({
|
|
|
|
|
|
message: error.message,
|
|
|
|
|
|
type: 'fail',
|
|
|
|
|
|
duration: 5000
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2025-10-09 09:29:36 +08:00
|
|
|
|
return Promise.reject(error)
|
|
|
|
|
|
}
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// --------------------------------取消接口重复请求的函数-----------------------------------
|
|
|
|
|
|
// axios.js
|
|
|
|
|
|
const pendingMap = new Map()
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 生成每个请求唯一的键
|
|
|
|
|
|
* @param {*} config
|
|
|
|
|
|
* @returns string
|
|
|
|
|
|
*/
|
|
|
|
|
|
function getPendingKey(config: any) {
|
|
|
|
|
|
const { url, method, params } = config
|
|
|
|
|
|
let { data } = config
|
|
|
|
|
|
if (typeof data === 'string') data = JSON.parse(data) // response里面返回的config.data是个字符串对象
|
|
|
|
|
|
return [url, method, JSON.stringify(params), JSON.stringify(data)].join('&')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 储存每个请求唯一值, 也就是cancel()方法, 用于取消请求
|
|
|
|
|
|
* @param {*} config
|
|
|
|
|
|
*/
|
|
|
|
|
|
function addPending(config: any) {
|
|
|
|
|
|
const pendingKey = getPendingKey(config)
|
|
|
|
|
|
config.cancelToken =
|
|
|
|
|
|
config.cancelToken ||
|
|
|
|
|
|
new axios.CancelToken((cancel) => {
|
|
|
|
|
|
if (!pendingMap.has(pendingKey)) {
|
|
|
|
|
|
pendingMap.set(pendingKey, cancel)
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 删除重复的请求
|
|
|
|
|
|
* @param {*} config
|
|
|
|
|
|
*/
|
|
|
|
|
|
function removePending(config: any) {
|
|
|
|
|
|
const pendingKey = getPendingKey(config)
|
|
|
|
|
|
if (pendingMap.has(pendingKey)) {
|
|
|
|
|
|
const cancelToken = pendingMap.get(pendingKey)
|
|
|
|
|
|
cancelToken(pendingKey)
|
|
|
|
|
|
pendingMap.delete(pendingKey)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// ----------------------------------loading的函数-------------------------------
|
2025-10-23 14:14:25 +08:00
|
|
|
|
const LoadingInstance: { _count: number } = {
|
2025-10-09 09:29:36 +08:00
|
|
|
|
_count: 0
|
|
|
|
|
|
}
|
|
|
|
|
|
function openLoading(loadingDom: any) {
|
2025-10-27 11:43:07 +08:00
|
|
|
|
useOverallStore().setLoading(true)
|
2025-10-09 09:29:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
function closeLoading() {
|
|
|
|
|
|
if (LoadingInstance._count > 0) LoadingInstance._count--
|
|
|
|
|
|
if (LoadingInstance._count === 0) {
|
2025-10-27 11:43:07 +08:00
|
|
|
|
useOverallStore().setLoading(false)
|
2025-10-09 09:29:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default service
|