refactor: refactor axios

This commit is contained in:
xingyu4j 2022-11-03 16:55:01 +08:00
parent 9adc84c396
commit 3eb11e2658
49 changed files with 314 additions and 412 deletions
yudao-ui-admin-vue3/src
api
bpm
form
leave
model
processInstance
task
taskAssignRule
userGroup
infra
apiAccessLog
apiErrorLog
codegen
config
dataSourceConfig
dbDoc
fileConfig
fileList
job
jobLog
redis
login
pay
app
channel
merchant
order
refund
system
dept
dict
errorCode
loginLog
menu
notice
oauth2
operatelog
permission
post
role
sensitiveWord
sms
smsChannel
smsLog
smsTemplate
tenant
tenantPackage
user
config/axios
hooks/web
router

View File

@ -1,6 +1,5 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import { FormVO } from './types'
const request = useAxios()
// 创建工作流的表单定义
export const createFormApi = async (data: FormVO) => {

View File

@ -1,6 +1,5 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import { LeaveVO } from './types'
const request = useAxios()
// 创建请假申请
export const createLeaveApi = async (data: LeaveVO) => {

View File

@ -1,6 +1,5 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import { ModelVO } from './types'
const request = useAxios()
export const getModelPageApi = async (params) => {
return await request.get({ url: '/bpm/model/page', params })

View File

@ -1,6 +1,5 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import { ProcessInstanceVO } from './types'
const request = useAxios()
export const getMyProcessInstancePageApi = async (params) => {
return await request.get({ url: '/bpm/process-instance/my-page', params })

View File

@ -1,6 +1,4 @@
import { useAxios } from '@/hooks/web/useAxios'
const request = useAxios()
import request from '@/config/axios'
export const getTodoTaskPage = async (params) => {
return await request.get({ url: '/bpm/task/todo-page', params })

View File

@ -1,6 +1,5 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import { TaskAssignVO } from './types'
const request = useAxios()
export const getTaskAssignRuleList = async (params) => {
return await request.get({ url: '/bpm/task-assign-rule/list', params })

View File

@ -1,6 +1,5 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import { UserGroupVO } from './types'
const request = useAxios()
// 创建用户组
export const createUserGroupApi = async (data: UserGroupVO) => {

View File

@ -1,6 +1,4 @@
import { useAxios } from '@/hooks/web/useAxios'
const request = useAxios()
import request from '@/config/axios'
// 查询列表API 访问日志
export const getApiAccessLogPageApi = (params) => {

View File

@ -1,6 +1,4 @@
import { useAxios } from '@/hooks/web/useAxios'
const request = useAxios()
import request from '@/config/axios'
// 查询列表API 访问日志
export const getApiErrorLogPageApi = (params) => {

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { CodegenUpdateReqVO, CodegenCreateListReqVO } from './types'
const request = useAxios()
// 查询列表代码生成表定义
export const getCodegenTablePageApi = (params) => {
return request.get({ url: '/infra/codegen/table/page', params })

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { ConfigVO } from './types'
const request = useAxios()
// 查询参数列表
export const getConfigPageApi = (params) => {
return request.get({ url: '/infra/config/page', params })

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { DataSourceConfigVO } from './types'
const request = useAxios()
// 查询数据源配置列表
export const getDataSourceConfigListApi = () => {
return request.get({ url: '/infra/data-source-config/list' })

View File

@ -1,6 +1,4 @@
import { useAxios } from '@/hooks/web/useAxios'
const request = useAxios()
import request from '@/config/axios'
// 导出Html
export const exportHtmlApi = () => {

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { FileConfigVO } from './types'
const request = useAxios()
// 查询文件配置列表
export const getFileConfigPageApi = (params) => {
return request.get({ url: '/infra/file-config/page', params })

View File

@ -1,6 +1,4 @@
import { useAxios } from '@/hooks/web/useAxios'
const request = useAxios()
import request from '@/config/axios'
// 查询文件列表
export const getFilePageApi = (params) => {

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { JobVO } from './types'
const request = useAxios()
// 任务列表
export const getJobPageApi = (params) => {
return request.get({ url: '/infra/job/page', params })

View File

@ -1,6 +1,4 @@
import { useAxios } from '@/hooks/web/useAxios'
const request = useAxios()
import request from '@/config/axios'
// 任务日志列表
export const getJobLogPageApi = (params) => {

View File

@ -1,6 +1,4 @@
import { useAxios } from '@/hooks/web/useAxios'
const request = useAxios()
import request from '@/config/axios'
/**
* redis

View File

@ -1,9 +1,7 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import { getRefreshToken } from '@/utils/auth'
import type { UserLoginVO } from './types'
const request = useAxios()
export interface CodeImgResult {
captchaOnOff: boolean
img: string

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { AppVO } from './types'
const request = useAxios()
// 查询列表支付应用
export const getAppPageApi = (params) => {
return request.get({ url: '/pay/app/page', params })

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { ChannelVO } from './types'
const request = useAxios()
// 查询列表支付渠道
export const getChannelPageApi = (params) => {
return request.get({ url: '/pay/channel/page', params })

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { MerchantVO } from './types'
const request = useAxios()
// 查询列表支付商户
export const getMerchantPageApi = (params) => {
return request.get({ url: '/pay/merchant/page', params })

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { OrderVO } from './types'
const request = useAxios()
// 查询列表支付订单
export const getOrderPageApi = async (params) => {
return await request.get({ url: '/pay/order/page', params })

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { RefundVO } from './types'
const request = useAxios()
// 查询列表退款订单
export const getRefundPageApi = (params) => {
return request.get({ url: '/pay/refund/page', params })

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { DeptVO, DeptListReqVO } from './types'
const request = useAxios()
// 查询部门(精简)列表
export const listSimpleDeptApi = () => {
return request.get({ url: '/system/dept/list-all-simple' })

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { DictDataVO, DictDataPageReqVO, DictDataExportReqVO } from './types'
const request = useAxios()
// 查询字典数据(精简)列表
export const listSimpleDictDataApi = () => {
return request.get({ url: '/system/dict-data/list-all-simple' })

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { DictTypeVO, DictTypePageReqVO, DictTypeExportReqVO } from './types'
const request = useAxios()
// 查询字典(精简)列表
export const listSimpleDictTypeApi = () => {
return request.get({ url: '/system/dict-type/list-all-simple' })

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { ErrorCodeVO } from './types'
const request = useAxios()
// 查询错误码列表
export const getErrorCodePageApi = (params) => {
return request.get({ url: '/system/error-code/page', params })

View File

@ -1,6 +1,4 @@
import { useAxios } from '@/hooks/web/useAxios'
const request = useAxios()
import request from '@/config/axios'
// 查询登录日志列表
export const getLoginLogPageApi = (params) => {

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { MenuVO } from './types'
const request = useAxios()
// 查询菜单(精简)列表
export const listSimpleMenusApi = () => {
return request.get({ url: '/system/menu/list-all-simple' })

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { NoticeVO } from './types'
const request = useAxios()
// 查询公告列表
export const getNoticePageApi = (params) => {
return request.get({ url: '/system/notice/page', params })

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import { OAuth2ClientVo } from './client.types'
const request = useAxios()
// 查询 OAuth2列表
export const getOAuth2ClientPageApi = (params) => {
return request.get({ url: '/system/oauth2-client/page', params })

View File

@ -1,6 +1,4 @@
import { useAxios } from '@/hooks/web/useAxios'
const request = useAxios()
import request from '@/config/axios'
// 查询 token列表
export const getAccessTokenPageApi = (params) => {

View File

@ -1,6 +1,4 @@
import { useAxios } from '@/hooks/web/useAxios'
const request = useAxios()
import request from '@/config/axios'
// 查询操作日志列表
export const getOperateLogPageApi = (params) => {

View File

@ -1,12 +1,10 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type {
PermissionAssignRoleDataScopeReqVO,
PermissionAssignRoleMenuReqVO,
PermissionAssignUserRoleReqVO
} from './types'
const request = useAxios()
// 查询角色拥有的菜单权限
export const listRoleMenusApi = async (roleId: number) => {
return await request.get({ url: '/system/permission/list-role-resources?roleId=' + roleId })

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { PostVO, PostPageReqVO, PostExportReqVO } from './types'
const request = useAxios()
// 查询岗位列表
export const getPostPageApi = async (params: PostPageReqVO) => {
return await request.get({ url: '/system/post/page', params })

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { RoleVO } from './types'
const request = useAxios()
// 查询角色列表
export const getRolePageApi = async (params) => {
return await request.get({ url: '/system/role/page', params })

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { SensitiveWordVO } from './types'
const request = useAxios()
// 查询敏感词列表
export const getSensitiveWordPageApi = (params) => {
return request.get({ url: '/system/sensitive-word/page', params })

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { SmsChannelVO } from './types'
const request = useAxios()
// 查询短信渠道列表
export const getSmsChannelPageApi = (params) => {
return request.get({ url: '/system/sms-channel/page', params })

View File

@ -1,6 +1,4 @@
import { useAxios } from '@/hooks/web/useAxios'
const request = useAxios()
import request from '@/config/axios'
// 查询短信日志列表
export const getSmsLogPageApi = (params) => {

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { SmsTemplateVO } from './types'
const request = useAxios()
// 查询短信模板列表
export const getSmsTemplatePageApi = (params) => {
return request.get({ url: '/system/sms-template/page', params })

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { TenantVO } from './types'
const request = useAxios()
// 查询租户列表
export const getTenantPageApi = (params) => {
return request.get({ url: '/system/tenant/page', params })

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { TenantPackageVO } from './types'
const request = useAxios()
// 查询租户套餐列表
export const getTenantPackageTypePageApi = (params) => {
return request.get({ url: '/system/tenant-package/page', params })

View File

@ -1,8 +1,6 @@
import { useAxios } from '@/hooks/web/useAxios'
import request from '@/config/axios'
import type { UserVO } from './types'
const request = useAxios()
// 查询用户管理列表
export const getUserPageApi = (params) => {
return request.get({ url: '/system/user/page', params })

View File

@ -1,6 +1,4 @@
import { useAxios } from '@/hooks/web/useAxios'
const request = useAxios()
import request from '@/config/axios'
// 查询用户个人信息
export const getUserProfileApi = () => {

View File

@ -1,229 +1,46 @@
import axios, {
AxiosInstance,
AxiosRequestConfig,
AxiosRequestHeaders,
AxiosResponse,
AxiosError
} from 'axios'
import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
import qs from 'qs'
import { config } from '@/config/axios/config'
import { getAccessToken, getRefreshToken, getTenantId, removeToken, setToken } from '@/utils/auth'
import errorCode from './errorCode'
import { useI18n } from '@/hooks/web/useI18n'
import { resetRouter } from '@/router'
import { useCache } from '@/hooks/web/useCache'
import { service } from './service'
const tenantEnable = import.meta.env.VITE_APP_TENANT_ENABLE
const { result_code, base_url, request_timeout } = config
import { config } from './config'
// 需要忽略的提示。忽略后,自动 Promise.reject('error')
const ignoreMsgs = [
'无效的刷新令牌', // 刷新令牌被删除时,不用提示
'刷新令牌已过期' // 使用刷新令牌,刷新获取新的访问令牌时,结果因为过期失败,此时需要忽略。否则,会导致继续 401无法跳转到登出界面
]
// 是否显示重新登录
export const isRelogin = { show: false }
// Axios 无感知刷新令牌,参考 https://www.dashingdog.cn/article/11 与 https://segmentfault.com/a/1190000020210980 实现
// 请求队列
let requestList: any[] = []
// 是否正在刷新中
let isRefreshToken = false
const { default_headers } = config
// 创建axios实例
const service: AxiosInstance = axios.create({
baseURL: base_url, // api 的 base_url
timeout: request_timeout, // 请求超时时间
withCredentials: false // 禁用 Cookie 等信息
})
// request拦截器
service.interceptors.request.use(
(config: AxiosRequestConfig) => {
// 是否需要设置 token
const isToken = (config!.headers || {}).isToken === false
if (getAccessToken() && !isToken) {
;(config as Recordable).headers.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token
const request = (option: any) => {
const { url, method, params, data, headersType, responseType } = option
return service({
url: url,
method,
params,
data,
responseType: responseType,
headers: {
'Content-Type': headersType || default_headers
}
// 设置租户
if (tenantEnable) {
const tenantId = getTenantId()
if (tenantId) (config as Recordable).headers.common['tenant-id'] = tenantId
}
const params = config.params || {}
const data = config.data || false
if (
config.method?.toUpperCase() === 'POST' &&
(config.headers as AxiosRequestHeaders)['Content-Type'] ===
'application/x-www-form-urlencoded'
) {
config.data = qs.stringify(data)
}
// get参数编码
if (config.method?.toUpperCase() === 'GET' && params) {
let url = config.url + '?'
for (const propName of Object.keys(params)) {
const value = params[propName]
if (value !== void 0 && value !== null && typeof value !== 'undefined') {
if (typeof value === 'object') {
for (const val of Object.keys(value)) {
const params = propName + '[' + val + ']'
const subPart = encodeURIComponent(params) + '='
url += subPart + encodeURIComponent(value[val]) + '&'
}
} else {
url += `${propName}=${encodeURIComponent(value)}&`
}
}
}
// 给 get 请求加上时间戳参数,避免从缓存中拿数据
// const now = new Date().getTime()
// params = params.substring(0, url.length - 1) + `?_t=${now}`
url = url.slice(0, -1)
config.params = {}
config.url = url
}
return config
},
(error: AxiosError) => {
// Do something with request error
console.log(error) // for debug
Promise.reject(error)
}
)
// response 拦截器
service.interceptors.response.use(
async (response: AxiosResponse<Recordable>) => {
const { data } = response
const config = response.config
if (!data) {
// 返回“[HTTP]请求没有返回值”;
throw new Error()
}
const { t } = useI18n()
// 未设置状态码则默认成功状态
const code = data.code || result_code
// 二进制数据则直接返回
if (
response.request.responseType === 'blob' ||
response.request.responseType === 'arraybuffer'
) {
return response.data
}
// 获取错误信息
const msg = data.msg || errorCode[code] || errorCode['default']
if (ignoreMsgs.indexOf(msg) !== -1) {
// 如果是忽略的错误码,直接返回 msg 异常
return Promise.reject(msg)
} else if (code === 401) {
// 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了
if (!isRefreshToken) {
isRefreshToken = true
// 1. 如果获取不到刷新令牌,则只能执行登出操作
if (!getRefreshToken()) {
return handleAuthorized()
}
// 2. 进行刷新访问令牌
try {
const refreshTokenRes = await refreshToken()
// 2.1 刷新成功,则回放队列的请求 + 当前请求
setToken(refreshTokenRes.data.data)
config.headers!.Authorization = 'Bearer ' + getAccessToken()
requestList.forEach((cb: any) => {
cb()
})
requestList = []
return service(config)
} catch (e) {
// 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。
// 2.2 刷新失败,只回放队列的请求
requestList.forEach((cb: any) => {
cb()
})
// 提示是否要登出。即不回放当前请求!不然会形成递归
return handleAuthorized()
} finally {
requestList = []
isRefreshToken = false
}
} else {
// 添加到队列,等待刷新获取到新的令牌
return new Promise((resolve) => {
requestList.push(() => {
config.headers!.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token 请根据实际情况自行修改
resolve(service(config))
})
})
}
} else if (code === 500) {
ElMessage.error(t('sys.api.errMsg500'))
return Promise.reject(new Error(msg))
} else if (code === 901) {
ElMessage.error(
'<div>' +
t('sys.api.errMsg901') +
'</div>' +
'<div> &nbsp; </div>' +
'<div>参考 https://doc.iocoder.cn/ 教程</div>' +
'<div> &nbsp; </div>' +
'<div>5 分钟搭建本地环境</div>'
)
return Promise.reject(new Error(msg))
} else if (code !== 200) {
if (msg === '无效的刷新令牌') {
// hard coding忽略这个提示直接登出
console.log(msg)
} else {
ElNotification.error({
title: msg
})
}
return Promise.reject('error')
} else {
return data
}
},
(error: AxiosError) => {
console.log('err' + error) // for debug
let { message } = error
const { t } = useI18n()
if (message === 'Network Error') {
message = t('sys.api.errorMessage')
} else if (message.includes('timeout')) {
message = t('sys.api.apiTimeoutMessage')
} else if (message.includes('Request failed with status code')) {
message = t('sys.api.apiRequestFailed') + message.substr(message.length - 3)
}
ElMessage.error(message)
return Promise.reject(error)
}
)
const refreshToken = async () => {
return await axios.post(base_url + '/system/auth/refresh-token?refreshToken=' + getRefreshToken())
})
}
const handleAuthorized = () => {
const { t } = useI18n()
if (!isRelogin.show) {
isRelogin.show = true
ElMessageBox.confirm(t('sys.api.timeoutMessage'), t('common.confirmTitle'), {
confirmButtonText: t('login.relogin'),
cancelButtonText: t('common.cancel'),
type: 'warning'
})
.then(() => {
const { wsCache } = useCache()
resetRouter() // 重置静态路由表
wsCache.clear()
removeToken()
isRelogin.show = false
window.location.href = '/'
})
.catch(() => {
isRelogin.show = false
})
export default {
get: async <T = any>(option: any) => {
const res = await request({ method: 'GET', ...option })
return res.data as unknown as T
},
post: async <T = any>(option: any) => {
const res = await request({ method: 'POST', ...option })
return res.data as unknown as T
},
delete: async <T = any>(option: any) => {
const res = await request({ method: 'DELETE', ...option })
return res.data as unknown as T
},
put: async <T = any>(option: any) => {
const res = await request({ method: 'PUT', ...option })
return res.data as unknown as T
},
download: async <T = any>(option: any) => {
const res = await request({ method: 'GET', responseType: 'blob', ...option })
return res as unknown as Promise<T>
},
upload: async <T = any>(option: any) => {
option.headersType = 'multipart/form-data'
const res = await request({ method: 'PUT', ...option })
return res as unknown as Promise<T>
}
return Promise.reject(t('sys.api.timeoutMessage'))
}
export { service }

View File

@ -0,0 +1,229 @@
import axios, {
AxiosInstance,
AxiosRequestConfig,
AxiosRequestHeaders,
AxiosResponse,
AxiosError
} from 'axios'
import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
import qs from 'qs'
import { config } from '@/config/axios/config'
import { getAccessToken, getRefreshToken, getTenantId, removeToken, setToken } from '@/utils/auth'
import errorCode from './errorCode'
import { useI18n } from '@/hooks/web/useI18n'
import { resetRouter } from '@/router'
import { useCache } from '@/hooks/web/useCache'
const tenantEnable = import.meta.env.VITE_APP_TENANT_ENABLE
const { result_code, base_url, request_timeout } = config
// 需要忽略的提示。忽略后,自动 Promise.reject('error')
const ignoreMsgs = [
'无效的刷新令牌', // 刷新令牌被删除时,不用提示
'刷新令牌已过期' // 使用刷新令牌,刷新获取新的访问令牌时,结果因为过期失败,此时需要忽略。否则,会导致继续 401无法跳转到登出界面
]
// 是否显示重新登录
export const isRelogin = { show: false }
// Axios 无感知刷新令牌,参考 https://www.dashingdog.cn/article/11 与 https://segmentfault.com/a/1190000020210980 实现
// 请求队列
let requestList: any[] = []
// 是否正在刷新中
let isRefreshToken = false
// 创建axios实例
const service: AxiosInstance = axios.create({
baseURL: base_url, // api 的 base_url
timeout: request_timeout, // 请求超时时间
withCredentials: false // 禁用 Cookie 等信息
})
// request拦截器
service.interceptors.request.use(
(config: AxiosRequestConfig) => {
// 是否需要设置 token
const isToken = (config!.headers || {}).isToken === false
if (getAccessToken() && !isToken) {
;(config as Recordable).headers.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token
}
// 设置租户
if (tenantEnable) {
const tenantId = getTenantId()
if (tenantId) (config as Recordable).headers.common['tenant-id'] = tenantId
}
const params = config.params || {}
const data = config.data || false
if (
config.method?.toUpperCase() === 'POST' &&
(config.headers as AxiosRequestHeaders)['Content-Type'] ===
'application/x-www-form-urlencoded'
) {
config.data = qs.stringify(data)
}
// get参数编码
if (config.method?.toUpperCase() === 'GET' && params) {
let url = config.url + '?'
for (const propName of Object.keys(params)) {
const value = params[propName]
if (value !== void 0 && value !== null && typeof value !== 'undefined') {
if (typeof value === 'object') {
for (const val of Object.keys(value)) {
const params = propName + '[' + val + ']'
const subPart = encodeURIComponent(params) + '='
url += subPart + encodeURIComponent(value[val]) + '&'
}
} else {
url += `${propName}=${encodeURIComponent(value)}&`
}
}
}
// 给 get 请求加上时间戳参数,避免从缓存中拿数据
// const now = new Date().getTime()
// params = params.substring(0, url.length - 1) + `?_t=${now}`
url = url.slice(0, -1)
config.params = {}
config.url = url
}
return config
},
(error: AxiosError) => {
// Do something with request error
console.log(error) // for debug
Promise.reject(error)
}
)
// response 拦截器
service.interceptors.response.use(
async (response: AxiosResponse<Recordable>) => {
const { data } = response
const config = response.config
if (!data) {
// 返回“[HTTP]请求没有返回值”;
throw new Error()
}
const { t } = useI18n()
// 未设置状态码则默认成功状态
const code = data.code || result_code
// 二进制数据则直接返回
if (
response.request.responseType === 'blob' ||
response.request.responseType === 'arraybuffer'
) {
return response.data
}
// 获取错误信息
const msg = data.msg || errorCode[code] || errorCode['default']
if (ignoreMsgs.indexOf(msg) !== -1) {
// 如果是忽略的错误码,直接返回 msg 异常
return Promise.reject(msg)
} else if (code === 401) {
// 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了
if (!isRefreshToken) {
isRefreshToken = true
// 1. 如果获取不到刷新令牌,则只能执行登出操作
if (!getRefreshToken()) {
return handleAuthorized()
}
// 2. 进行刷新访问令牌
try {
const refreshTokenRes = await refreshToken()
// 2.1 刷新成功,则回放队列的请求 + 当前请求
setToken(refreshTokenRes.data.data)
config.headers!.Authorization = 'Bearer ' + getAccessToken()
requestList.forEach((cb: any) => {
cb()
})
requestList = []
return service(config)
} catch (e) {
// 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。
// 2.2 刷新失败,只回放队列的请求
requestList.forEach((cb: any) => {
cb()
})
// 提示是否要登出。即不回放当前请求!不然会形成递归
return handleAuthorized()
} finally {
requestList = []
isRefreshToken = false
}
} else {
// 添加到队列,等待刷新获取到新的令牌
return new Promise((resolve) => {
requestList.push(() => {
config.headers!.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token 请根据实际情况自行修改
resolve(service(config))
})
})
}
} else if (code === 500) {
ElMessage.error(t('sys.api.errMsg500'))
return Promise.reject(new Error(msg))
} else if (code === 901) {
ElMessage.error(
'<div>' +
t('sys.api.errMsg901') +
'</div>' +
'<div> &nbsp; </div>' +
'<div>参考 https://doc.iocoder.cn/ 教程</div>' +
'<div> &nbsp; </div>' +
'<div>5 分钟搭建本地环境</div>'
)
return Promise.reject(new Error(msg))
} else if (code !== 200) {
if (msg === '无效的刷新令牌') {
// hard coding忽略这个提示直接登出
console.log(msg)
} else {
ElNotification.error({
title: msg
})
}
return Promise.reject('error')
} else {
return data
}
},
(error: AxiosError) => {
console.log('err' + error) // for debug
let { message } = error
const { t } = useI18n()
if (message === 'Network Error') {
message = t('sys.api.errorMessage')
} else if (message.includes('timeout')) {
message = t('sys.api.apiTimeoutMessage')
} else if (message.includes('Request failed with status code')) {
message = t('sys.api.apiRequestFailed') + message.substr(message.length - 3)
}
ElMessage.error(message)
return Promise.reject(error)
}
)
const refreshToken = async () => {
return await axios.post(base_url + '/system/auth/refresh-token?refreshToken=' + getRefreshToken())
}
const handleAuthorized = () => {
const { t } = useI18n()
if (!isRelogin.show) {
isRelogin.show = true
ElMessageBox.confirm(t('sys.api.timeoutMessage'), t('common.confirmTitle'), {
confirmButtonText: t('login.relogin'),
cancelButtonText: t('common.cancel'),
type: 'warning'
})
.then(() => {
const { wsCache } = useCache()
resetRouter() // 重置静态路由表
wsCache.clear()
removeToken()
isRelogin.show = false
window.location.href = '/'
})
.catch(() => {
isRelogin.show = false
})
}
return Promise.reject(t('sys.api.timeoutMessage'))
}
export { service }

View File

@ -1,60 +0,0 @@
import { service } from '@/config/axios'
import { config } from '@/config/axios/config'
const { default_headers } = config
const request = (option: AxiosConfig) => {
const { url, method, params, data, headersType, responseType } = option
return service({
url: url,
method,
params,
data,
responseType: responseType,
headers: {
'Content-Type': headersType || default_headers
}
})
}
async function getFn<T = any>(option: AxiosConfig): Promise<T> {
const res = await request({ method: 'GET', ...option })
return res.data
}
async function postFn<T = any>(option: AxiosConfig): Promise<T> {
const res = await request({ method: 'POST', ...option })
return res.data
}
async function deleteFn<T = any>(option: AxiosConfig): Promise<T> {
const res = await request({ method: 'DELETE', ...option })
return res.data
}
async function putFn<T = any>(option: AxiosConfig): Promise<T> {
const res = await request({ method: 'PUT', ...option })
return res.data
}
async function downloadFn<T = any>(option: AxiosConfig): Promise<T> {
const res = await request({ method: 'GET', responseType: 'blob', ...option })
return res as unknown as Promise<T>
}
async function uploadFn<T = any>(option: AxiosConfig): Promise<T> {
option.headersType = 'multipart/form-data'
const res = await request({ method: 'PUT', ...option })
return res as unknown as Promise<T>
}
export const useAxios = () => {
return {
get: getFn,
post: postFn,
delete: deleteFn,
put: putFn,
download: downloadFn,
upload: uploadFn
}
}

View File

@ -10,7 +10,7 @@ import { usePermissionStoreWithOut } from '@/store/modules/permission'
import { useDictStoreWithOut } from '@/store/modules/dict'
import { useUserStoreWithOut } from '@/store/modules/user'
import { listSimpleDictDataApi } from '@/api/system/dict/dict.data'
import { isRelogin } from '@/config/axios'
import { isRelogin } from '@/config/axios/service'
import { getInfoApi } from '@/api/login'
const { start, done } = useNProgress()