Commit 3eb11e2658e9cbe112793dd189833ab1aabb3b95
1 parent
9adc84c3
refactor: refactor axios
Showing
49 changed files
with
314 additions
and
412 deletions
yudao-ui-admin-vue3/src/api/bpm/form/index.ts
yudao-ui-admin-vue3/src/api/bpm/leave/index.ts
yudao-ui-admin-vue3/src/api/bpm/model/index.ts
yudao-ui-admin-vue3/src/api/bpm/processInstance/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import { ProcessInstanceVO } from './types' |
| 3 | -const request = useAxios() | |
| 4 | 3 | |
| 5 | 4 | export const getMyProcessInstancePageApi = async (params) => { |
| 6 | 5 | return await request.get({ url: '/bpm/process-instance/my-page', params }) | ... | ... |
yudao-ui-admin-vue3/src/api/bpm/task/index.ts
yudao-ui-admin-vue3/src/api/bpm/taskAssignRule/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import { TaskAssignVO } from './types' |
| 3 | -const request = useAxios() | |
| 4 | 3 | |
| 5 | 4 | export const getTaskAssignRuleList = async (params) => { |
| 6 | 5 | return await request.get({ url: '/bpm/task-assign-rule/list', params }) | ... | ... |
yudao-ui-admin-vue3/src/api/bpm/userGroup/index.ts
yudao-ui-admin-vue3/src/api/infra/apiAccessLog/index.ts
yudao-ui-admin-vue3/src/api/infra/apiErrorLog/index.ts
yudao-ui-admin-vue3/src/api/infra/codegen/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { CodegenUpdateReqVO, CodegenCreateListReqVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询列表代码生成表定义 |
| 7 | 5 | export const getCodegenTablePageApi = (params) => { |
| 8 | 6 | return request.get({ url: '/infra/codegen/table/page', params }) | ... | ... |
yudao-ui-admin-vue3/src/api/infra/config/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { ConfigVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询参数列表 |
| 7 | 5 | export const getConfigPageApi = (params) => { |
| 8 | 6 | return request.get({ url: '/infra/config/page', params }) | ... | ... |
yudao-ui-admin-vue3/src/api/infra/dataSourceConfig/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { DataSourceConfigVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询数据源配置列表 |
| 7 | 5 | export const getDataSourceConfigListApi = () => { |
| 8 | 6 | return request.get({ url: '/infra/data-source-config/list' }) | ... | ... |
yudao-ui-admin-vue3/src/api/infra/dbDoc/index.ts
yudao-ui-admin-vue3/src/api/infra/fileConfig/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { FileConfigVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询文件配置列表 |
| 7 | 5 | export const getFileConfigPageApi = (params) => { |
| 8 | 6 | return request.get({ url: '/infra/file-config/page', params }) | ... | ... |
yudao-ui-admin-vue3/src/api/infra/fileList/index.ts
yudao-ui-admin-vue3/src/api/infra/job/index.ts
yudao-ui-admin-vue3/src/api/infra/jobLog/index.ts
yudao-ui-admin-vue3/src/api/infra/redis/index.ts
yudao-ui-admin-vue3/src/api/login/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import { getRefreshToken } from '@/utils/auth' |
| 3 | 3 | import type { UserLoginVO } from './types' |
| 4 | 4 | |
| 5 | -const request = useAxios() | |
| 6 | - | |
| 7 | 5 | export interface CodeImgResult { |
| 8 | 6 | captchaOnOff: boolean |
| 9 | 7 | img: string | ... | ... |
yudao-ui-admin-vue3/src/api/pay/app/index.ts
yudao-ui-admin-vue3/src/api/pay/channel/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { ChannelVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询列表支付渠道 |
| 7 | 5 | export const getChannelPageApi = (params) => { |
| 8 | 6 | return request.get({ url: '/pay/channel/page', params }) | ... | ... |
yudao-ui-admin-vue3/src/api/pay/merchant/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { MerchantVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询列表支付商户 |
| 7 | 5 | export const getMerchantPageApi = (params) => { |
| 8 | 6 | return request.get({ url: '/pay/merchant/page', params }) | ... | ... |
yudao-ui-admin-vue3/src/api/pay/order/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { OrderVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询列表支付订单 |
| 7 | 5 | export const getOrderPageApi = async (params) => { |
| 8 | 6 | return await request.get({ url: '/pay/order/page', params }) | ... | ... |
yudao-ui-admin-vue3/src/api/pay/refund/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { RefundVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询列表退款订单 |
| 7 | 5 | export const getRefundPageApi = (params) => { |
| 8 | 6 | return request.get({ url: '/pay/refund/page', params }) | ... | ... |
yudao-ui-admin-vue3/src/api/system/dept/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { DeptVO, DeptListReqVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询部门(精简)列表 |
| 7 | 5 | export const listSimpleDeptApi = () => { |
| 8 | 6 | return request.get({ url: '/system/dept/list-all-simple' }) | ... | ... |
yudao-ui-admin-vue3/src/api/system/dict/dict.data.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { DictDataVO, DictDataPageReqVO, DictDataExportReqVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询字典数据(精简)列表 |
| 7 | 5 | export const listSimpleDictDataApi = () => { |
| 8 | 6 | return request.get({ url: '/system/dict-data/list-all-simple' }) | ... | ... |
yudao-ui-admin-vue3/src/api/system/dict/dict.type.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { DictTypeVO, DictTypePageReqVO, DictTypeExportReqVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询字典(精简)列表 |
| 7 | 5 | export const listSimpleDictTypeApi = () => { |
| 8 | 6 | return request.get({ url: '/system/dict-type/list-all-simple' }) | ... | ... |
yudao-ui-admin-vue3/src/api/system/errorCode/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { ErrorCodeVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询错误码列表 |
| 7 | 5 | export const getErrorCodePageApi = (params) => { |
| 8 | 6 | return request.get({ url: '/system/error-code/page', params }) | ... | ... |
yudao-ui-admin-vue3/src/api/system/loginLog/index.ts
yudao-ui-admin-vue3/src/api/system/menu/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { MenuVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询菜单(精简)列表 |
| 7 | 5 | export const listSimpleMenusApi = () => { |
| 8 | 6 | return request.get({ url: '/system/menu/list-all-simple' }) | ... | ... |
yudao-ui-admin-vue3/src/api/system/notice/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { NoticeVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询公告列表 |
| 7 | 5 | export const getNoticePageApi = (params) => { |
| 8 | 6 | return request.get({ url: '/system/notice/page', params }) | ... | ... |
yudao-ui-admin-vue3/src/api/system/oauth2/client.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import { OAuth2ClientVo } from './client.types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询 OAuth2列表 |
| 7 | 5 | export const getOAuth2ClientPageApi = (params) => { |
| 8 | 6 | return request.get({ url: '/system/oauth2-client/page', params }) | ... | ... |
yudao-ui-admin-vue3/src/api/system/oauth2/token.ts
yudao-ui-admin-vue3/src/api/system/operatelog/index.ts
yudao-ui-admin-vue3/src/api/system/permission/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { |
| 3 | 3 | PermissionAssignRoleDataScopeReqVO, |
| 4 | 4 | PermissionAssignRoleMenuReqVO, |
| 5 | 5 | PermissionAssignUserRoleReqVO |
| 6 | 6 | } from './types' |
| 7 | 7 | |
| 8 | -const request = useAxios() | |
| 9 | - | |
| 10 | 8 | // 查询角色拥有的菜单权限 |
| 11 | 9 | export const listRoleMenusApi = async (roleId: number) => { |
| 12 | 10 | return await request.get({ url: '/system/permission/list-role-resources?roleId=' + roleId }) | ... | ... |
yudao-ui-admin-vue3/src/api/system/post/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { PostVO, PostPageReqVO, PostExportReqVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询岗位列表 |
| 7 | 5 | export const getPostPageApi = async (params: PostPageReqVO) => { |
| 8 | 6 | return await request.get({ url: '/system/post/page', params }) | ... | ... |
yudao-ui-admin-vue3/src/api/system/role/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { RoleVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询角色列表 |
| 7 | 5 | export const getRolePageApi = async (params) => { |
| 8 | 6 | return await request.get({ url: '/system/role/page', params }) | ... | ... |
yudao-ui-admin-vue3/src/api/system/sensitiveWord/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { SensitiveWordVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询敏感词列表 |
| 7 | 5 | export const getSensitiveWordPageApi = (params) => { |
| 8 | 6 | return request.get({ url: '/system/sensitive-word/page', params }) | ... | ... |
yudao-ui-admin-vue3/src/api/system/sms/smsChannel/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { SmsChannelVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询短信渠道列表 |
| 7 | 5 | export const getSmsChannelPageApi = (params) => { |
| 8 | 6 | return request.get({ url: '/system/sms-channel/page', params }) | ... | ... |
yudao-ui-admin-vue3/src/api/system/sms/smsLog/index.ts
yudao-ui-admin-vue3/src/api/system/sms/smsTemplate/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { SmsTemplateVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询短信模板列表 |
| 7 | 5 | export const getSmsTemplatePageApi = (params) => { |
| 8 | 6 | return request.get({ url: '/system/sms-template/page', params }) | ... | ... |
yudao-ui-admin-vue3/src/api/system/tenant/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { TenantVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询租户列表 |
| 7 | 5 | export const getTenantPageApi = (params) => { |
| 8 | 6 | return request.get({ url: '/system/tenant/page', params }) | ... | ... |
yudao-ui-admin-vue3/src/api/system/tenantPackage/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { TenantPackageVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询租户套餐列表 |
| 7 | 5 | export const getTenantPackageTypePageApi = (params) => { |
| 8 | 6 | return request.get({ url: '/system/tenant-package/page', params }) | ... | ... |
yudao-ui-admin-vue3/src/api/system/user/index.ts
| 1 | -import { useAxios } from '@/hooks/web/useAxios' | |
| 1 | +import request from '@/config/axios' | |
| 2 | 2 | import type { UserVO } from './types' |
| 3 | 3 | |
| 4 | -const request = useAxios() | |
| 5 | - | |
| 6 | 4 | // 查询用户管理列表 |
| 7 | 5 | export const getUserPageApi = (params) => { |
| 8 | 6 | return request.get({ url: '/system/user/page', params }) | ... | ... |
yudao-ui-admin-vue3/src/api/system/user/profile/index.ts
yudao-ui-admin-vue3/src/config/axios/index.ts
| 1 | -import axios, { | |
| 2 | - AxiosInstance, | |
| 3 | - AxiosRequestConfig, | |
| 4 | - AxiosRequestHeaders, | |
| 5 | - AxiosResponse, | |
| 6 | - AxiosError | |
| 7 | -} from 'axios' | |
| 8 | -import { ElMessage, ElMessageBox, ElNotification } from 'element-plus' | |
| 9 | -import qs from 'qs' | |
| 10 | -import { config } from '@/config/axios/config' | |
| 11 | -import { getAccessToken, getRefreshToken, getTenantId, removeToken, setToken } from '@/utils/auth' | |
| 12 | -import errorCode from './errorCode' | |
| 13 | -import { useI18n } from '@/hooks/web/useI18n' | |
| 14 | -import { resetRouter } from '@/router' | |
| 15 | -import { useCache } from '@/hooks/web/useCache' | |
| 1 | +import { service } from './service' | |
| 16 | 2 | |
| 17 | -const tenantEnable = import.meta.env.VITE_APP_TENANT_ENABLE | |
| 18 | -const { result_code, base_url, request_timeout } = config | |
| 3 | +import { config } from './config' | |
| 19 | 4 | |
| 20 | -// 需要忽略的提示。忽略后,自动 Promise.reject('error') | |
| 21 | -const ignoreMsgs = [ | |
| 22 | - '无效的刷新令牌', // 刷新令牌被删除时,不用提示 | |
| 23 | - '刷新令牌已过期' // 使用刷新令牌,刷新获取新的访问令牌时,结果因为过期失败,此时需要忽略。否则,会导致继续 401,无法跳转到登出界面 | |
| 24 | -] | |
| 25 | -// 是否显示重新登录 | |
| 26 | -export const isRelogin = { show: false } | |
| 27 | -// Axios 无感知刷新令牌,参考 https://www.dashingdog.cn/article/11 与 https://segmentfault.com/a/1190000020210980 实现 | |
| 28 | -// 请求队列 | |
| 29 | -let requestList: any[] = [] | |
| 30 | -// 是否正在刷新中 | |
| 31 | -let isRefreshToken = false | |
| 5 | +const { default_headers } = config | |
| 32 | 6 | |
| 33 | -// 创建axios实例 | |
| 34 | -const service: AxiosInstance = axios.create({ | |
| 35 | - baseURL: base_url, // api 的 base_url | |
| 36 | - timeout: request_timeout, // 请求超时时间 | |
| 37 | - withCredentials: false // 禁用 Cookie 等信息 | |
| 38 | -}) | |
| 39 | - | |
| 40 | -// request拦截器 | |
| 41 | -service.interceptors.request.use( | |
| 42 | - (config: AxiosRequestConfig) => { | |
| 43 | - // 是否需要设置 token | |
| 44 | - const isToken = (config!.headers || {}).isToken === false | |
| 45 | - if (getAccessToken() && !isToken) { | |
| 46 | - ;(config as Recordable).headers.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token | |
| 47 | - } | |
| 48 | - // 设置租户 | |
| 49 | - if (tenantEnable) { | |
| 50 | - const tenantId = getTenantId() | |
| 51 | - if (tenantId) (config as Recordable).headers.common['tenant-id'] = tenantId | |
| 52 | - } | |
| 53 | - const params = config.params || {} | |
| 54 | - const data = config.data || false | |
| 55 | - if ( | |
| 56 | - config.method?.toUpperCase() === 'POST' && | |
| 57 | - (config.headers as AxiosRequestHeaders)['Content-Type'] === | |
| 58 | - 'application/x-www-form-urlencoded' | |
| 59 | - ) { | |
| 60 | - config.data = qs.stringify(data) | |
| 61 | - } | |
| 62 | - // get参数编码 | |
| 63 | - if (config.method?.toUpperCase() === 'GET' && params) { | |
| 64 | - let url = config.url + '?' | |
| 65 | - for (const propName of Object.keys(params)) { | |
| 66 | - const value = params[propName] | |
| 67 | - if (value !== void 0 && value !== null && typeof value !== 'undefined') { | |
| 68 | - if (typeof value === 'object') { | |
| 69 | - for (const val of Object.keys(value)) { | |
| 70 | - const params = propName + '[' + val + ']' | |
| 71 | - const subPart = encodeURIComponent(params) + '=' | |
| 72 | - url += subPart + encodeURIComponent(value[val]) + '&' | |
| 73 | - } | |
| 74 | - } else { | |
| 75 | - url += `${propName}=${encodeURIComponent(value)}&` | |
| 76 | - } | |
| 77 | - } | |
| 78 | - } | |
| 79 | - // 给 get 请求加上时间戳参数,避免从缓存中拿数据 | |
| 80 | - // const now = new Date().getTime() | |
| 81 | - // params = params.substring(0, url.length - 1) + `?_t=${now}` | |
| 82 | - url = url.slice(0, -1) | |
| 83 | - config.params = {} | |
| 84 | - config.url = url | |
| 85 | - } | |
| 86 | - return config | |
| 7 | +const request = (option: any) => { | |
| 8 | + const { url, method, params, data, headersType, responseType } = option | |
| 9 | + return service({ | |
| 10 | + url: url, | |
| 11 | + method, | |
| 12 | + params, | |
| 13 | + data, | |
| 14 | + responseType: responseType, | |
| 15 | + headers: { | |
| 16 | + 'Content-Type': headersType || default_headers | |
| 17 | + } | |
| 18 | + }) | |
| 19 | +} | |
| 20 | +export default { | |
| 21 | + get: async <T = any>(option: any) => { | |
| 22 | + const res = await request({ method: 'GET', ...option }) | |
| 23 | + return res.data as unknown as T | |
| 87 | 24 | }, |
| 88 | - (error: AxiosError) => { | |
| 89 | - // Do something with request error | |
| 90 | - console.log(error) // for debug | |
| 91 | - Promise.reject(error) | |
| 92 | - } | |
| 93 | -) | |
| 94 | - | |
| 95 | -// response 拦截器 | |
| 96 | -service.interceptors.response.use( | |
| 97 | - async (response: AxiosResponse<Recordable>) => { | |
| 98 | - const { data } = response | |
| 99 | - const config = response.config | |
| 100 | - if (!data) { | |
| 101 | - // 返回“[HTTP]请求没有返回值”; | |
| 102 | - throw new Error() | |
| 103 | - } | |
| 104 | - const { t } = useI18n() | |
| 105 | - // 未设置状态码则默认成功状态 | |
| 106 | - const code = data.code || result_code | |
| 107 | - // 二进制数据则直接返回 | |
| 108 | - if ( | |
| 109 | - response.request.responseType === 'blob' || | |
| 110 | - response.request.responseType === 'arraybuffer' | |
| 111 | - ) { | |
| 112 | - return response.data | |
| 113 | - } | |
| 114 | - // 获取错误信息 | |
| 115 | - const msg = data.msg || errorCode[code] || errorCode['default'] | |
| 116 | - if (ignoreMsgs.indexOf(msg) !== -1) { | |
| 117 | - // 如果是忽略的错误码,直接返回 msg 异常 | |
| 118 | - return Promise.reject(msg) | |
| 119 | - } else if (code === 401) { | |
| 120 | - // 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了 | |
| 121 | - if (!isRefreshToken) { | |
| 122 | - isRefreshToken = true | |
| 123 | - // 1. 如果获取不到刷新令牌,则只能执行登出操作 | |
| 124 | - if (!getRefreshToken()) { | |
| 125 | - return handleAuthorized() | |
| 126 | - } | |
| 127 | - // 2. 进行刷新访问令牌 | |
| 128 | - try { | |
| 129 | - const refreshTokenRes = await refreshToken() | |
| 130 | - // 2.1 刷新成功,则回放队列的请求 + 当前请求 | |
| 131 | - setToken(refreshTokenRes.data.data) | |
| 132 | - config.headers!.Authorization = 'Bearer ' + getAccessToken() | |
| 133 | - requestList.forEach((cb: any) => { | |
| 134 | - cb() | |
| 135 | - }) | |
| 136 | - requestList = [] | |
| 137 | - return service(config) | |
| 138 | - } catch (e) { | |
| 139 | - // 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。 | |
| 140 | - // 2.2 刷新失败,只回放队列的请求 | |
| 141 | - requestList.forEach((cb: any) => { | |
| 142 | - cb() | |
| 143 | - }) | |
| 144 | - // 提示是否要登出。即不回放当前请求!不然会形成递归 | |
| 145 | - return handleAuthorized() | |
| 146 | - } finally { | |
| 147 | - requestList = [] | |
| 148 | - isRefreshToken = false | |
| 149 | - } | |
| 150 | - } else { | |
| 151 | - // 添加到队列,等待刷新获取到新的令牌 | |
| 152 | - return new Promise((resolve) => { | |
| 153 | - requestList.push(() => { | |
| 154 | - config.headers!.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token 请根据实际情况自行修改 | |
| 155 | - resolve(service(config)) | |
| 156 | - }) | |
| 157 | - }) | |
| 158 | - } | |
| 159 | - } else if (code === 500) { | |
| 160 | - ElMessage.error(t('sys.api.errMsg500')) | |
| 161 | - return Promise.reject(new Error(msg)) | |
| 162 | - } else if (code === 901) { | |
| 163 | - ElMessage.error( | |
| 164 | - '<div>' + | |
| 165 | - t('sys.api.errMsg901') + | |
| 166 | - '</div>' + | |
| 167 | - '<div> </div>' + | |
| 168 | - '<div>参考 https://doc.iocoder.cn/ 教程</div>' + | |
| 169 | - '<div> </div>' + | |
| 170 | - '<div>5 分钟搭建本地环境</div>' | |
| 171 | - ) | |
| 172 | - return Promise.reject(new Error(msg)) | |
| 173 | - } else if (code !== 200) { | |
| 174 | - if (msg === '无效的刷新令牌') { | |
| 175 | - // hard coding:忽略这个提示,直接登出 | |
| 176 | - console.log(msg) | |
| 177 | - } else { | |
| 178 | - ElNotification.error({ | |
| 179 | - title: msg | |
| 180 | - }) | |
| 181 | - } | |
| 182 | - return Promise.reject('error') | |
| 183 | - } else { | |
| 184 | - return data | |
| 185 | - } | |
| 25 | + post: async <T = any>(option: any) => { | |
| 26 | + const res = await request({ method: 'POST', ...option }) | |
| 27 | + return res.data as unknown as T | |
| 186 | 28 | }, |
| 187 | - (error: AxiosError) => { | |
| 188 | - console.log('err' + error) // for debug | |
| 189 | - let { message } = error | |
| 190 | - const { t } = useI18n() | |
| 191 | - if (message === 'Network Error') { | |
| 192 | - message = t('sys.api.errorMessage') | |
| 193 | - } else if (message.includes('timeout')) { | |
| 194 | - message = t('sys.api.apiTimeoutMessage') | |
| 195 | - } else if (message.includes('Request failed with status code')) { | |
| 196 | - message = t('sys.api.apiRequestFailed') + message.substr(message.length - 3) | |
| 197 | - } | |
| 198 | - ElMessage.error(message) | |
| 199 | - return Promise.reject(error) | |
| 200 | - } | |
| 201 | -) | |
| 202 | - | |
| 203 | -const refreshToken = async () => { | |
| 204 | - return await axios.post(base_url + '/system/auth/refresh-token?refreshToken=' + getRefreshToken()) | |
| 205 | -} | |
| 206 | -const handleAuthorized = () => { | |
| 207 | - const { t } = useI18n() | |
| 208 | - if (!isRelogin.show) { | |
| 209 | - isRelogin.show = true | |
| 210 | - ElMessageBox.confirm(t('sys.api.timeoutMessage'), t('common.confirmTitle'), { | |
| 211 | - confirmButtonText: t('login.relogin'), | |
| 212 | - cancelButtonText: t('common.cancel'), | |
| 213 | - type: 'warning' | |
| 214 | - }) | |
| 215 | - .then(() => { | |
| 216 | - const { wsCache } = useCache() | |
| 217 | - resetRouter() // 重置静态路由表 | |
| 218 | - wsCache.clear() | |
| 219 | - removeToken() | |
| 220 | - isRelogin.show = false | |
| 221 | - window.location.href = '/' | |
| 222 | - }) | |
| 223 | - .catch(() => { | |
| 224 | - isRelogin.show = false | |
| 225 | - }) | |
| 29 | + delete: async <T = any>(option: any) => { | |
| 30 | + const res = await request({ method: 'DELETE', ...option }) | |
| 31 | + return res.data as unknown as T | |
| 32 | + }, | |
| 33 | + put: async <T = any>(option: any) => { | |
| 34 | + const res = await request({ method: 'PUT', ...option }) | |
| 35 | + return res.data as unknown as T | |
| 36 | + }, | |
| 37 | + download: async <T = any>(option: any) => { | |
| 38 | + const res = await request({ method: 'GET', responseType: 'blob', ...option }) | |
| 39 | + return res as unknown as Promise<T> | |
| 40 | + }, | |
| 41 | + upload: async <T = any>(option: any) => { | |
| 42 | + option.headersType = 'multipart/form-data' | |
| 43 | + const res = await request({ method: 'PUT', ...option }) | |
| 44 | + return res as unknown as Promise<T> | |
| 226 | 45 | } |
| 227 | - return Promise.reject(t('sys.api.timeoutMessage')) | |
| 228 | 46 | } |
| 229 | -export { service } | ... | ... |
yudao-ui-admin-vue3/src/config/axios/service.ts
0 → 100644
| 1 | +import axios, { | |
| 2 | + AxiosInstance, | |
| 3 | + AxiosRequestConfig, | |
| 4 | + AxiosRequestHeaders, | |
| 5 | + AxiosResponse, | |
| 6 | + AxiosError | |
| 7 | +} from 'axios' | |
| 8 | +import { ElMessage, ElMessageBox, ElNotification } from 'element-plus' | |
| 9 | +import qs from 'qs' | |
| 10 | +import { config } from '@/config/axios/config' | |
| 11 | +import { getAccessToken, getRefreshToken, getTenantId, removeToken, setToken } from '@/utils/auth' | |
| 12 | +import errorCode from './errorCode' | |
| 13 | +import { useI18n } from '@/hooks/web/useI18n' | |
| 14 | +import { resetRouter } from '@/router' | |
| 15 | +import { useCache } from '@/hooks/web/useCache' | |
| 16 | + | |
| 17 | +const tenantEnable = import.meta.env.VITE_APP_TENANT_ENABLE | |
| 18 | +const { result_code, base_url, request_timeout } = config | |
| 19 | + | |
| 20 | +// 需要忽略的提示。忽略后,自动 Promise.reject('error') | |
| 21 | +const ignoreMsgs = [ | |
| 22 | + '无效的刷新令牌', // 刷新令牌被删除时,不用提示 | |
| 23 | + '刷新令牌已过期' // 使用刷新令牌,刷新获取新的访问令牌时,结果因为过期失败,此时需要忽略。否则,会导致继续 401,无法跳转到登出界面 | |
| 24 | +] | |
| 25 | +// 是否显示重新登录 | |
| 26 | +export const isRelogin = { show: false } | |
| 27 | +// Axios 无感知刷新令牌,参考 https://www.dashingdog.cn/article/11 与 https://segmentfault.com/a/1190000020210980 实现 | |
| 28 | +// 请求队列 | |
| 29 | +let requestList: any[] = [] | |
| 30 | +// 是否正在刷新中 | |
| 31 | +let isRefreshToken = false | |
| 32 | + | |
| 33 | +// 创建axios实例 | |
| 34 | +const service: AxiosInstance = axios.create({ | |
| 35 | + baseURL: base_url, // api 的 base_url | |
| 36 | + timeout: request_timeout, // 请求超时时间 | |
| 37 | + withCredentials: false // 禁用 Cookie 等信息 | |
| 38 | +}) | |
| 39 | + | |
| 40 | +// request拦截器 | |
| 41 | +service.interceptors.request.use( | |
| 42 | + (config: AxiosRequestConfig) => { | |
| 43 | + // 是否需要设置 token | |
| 44 | + const isToken = (config!.headers || {}).isToken === false | |
| 45 | + if (getAccessToken() && !isToken) { | |
| 46 | + ;(config as Recordable).headers.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token | |
| 47 | + } | |
| 48 | + // 设置租户 | |
| 49 | + if (tenantEnable) { | |
| 50 | + const tenantId = getTenantId() | |
| 51 | + if (tenantId) (config as Recordable).headers.common['tenant-id'] = tenantId | |
| 52 | + } | |
| 53 | + const params = config.params || {} | |
| 54 | + const data = config.data || false | |
| 55 | + if ( | |
| 56 | + config.method?.toUpperCase() === 'POST' && | |
| 57 | + (config.headers as AxiosRequestHeaders)['Content-Type'] === | |
| 58 | + 'application/x-www-form-urlencoded' | |
| 59 | + ) { | |
| 60 | + config.data = qs.stringify(data) | |
| 61 | + } | |
| 62 | + // get参数编码 | |
| 63 | + if (config.method?.toUpperCase() === 'GET' && params) { | |
| 64 | + let url = config.url + '?' | |
| 65 | + for (const propName of Object.keys(params)) { | |
| 66 | + const value = params[propName] | |
| 67 | + if (value !== void 0 && value !== null && typeof value !== 'undefined') { | |
| 68 | + if (typeof value === 'object') { | |
| 69 | + for (const val of Object.keys(value)) { | |
| 70 | + const params = propName + '[' + val + ']' | |
| 71 | + const subPart = encodeURIComponent(params) + '=' | |
| 72 | + url += subPart + encodeURIComponent(value[val]) + '&' | |
| 73 | + } | |
| 74 | + } else { | |
| 75 | + url += `${propName}=${encodeURIComponent(value)}&` | |
| 76 | + } | |
| 77 | + } | |
| 78 | + } | |
| 79 | + // 给 get 请求加上时间戳参数,避免从缓存中拿数据 | |
| 80 | + // const now = new Date().getTime() | |
| 81 | + // params = params.substring(0, url.length - 1) + `?_t=${now}` | |
| 82 | + url = url.slice(0, -1) | |
| 83 | + config.params = {} | |
| 84 | + config.url = url | |
| 85 | + } | |
| 86 | + return config | |
| 87 | + }, | |
| 88 | + (error: AxiosError) => { | |
| 89 | + // Do something with request error | |
| 90 | + console.log(error) // for debug | |
| 91 | + Promise.reject(error) | |
| 92 | + } | |
| 93 | +) | |
| 94 | + | |
| 95 | +// response 拦截器 | |
| 96 | +service.interceptors.response.use( | |
| 97 | + async (response: AxiosResponse<Recordable>) => { | |
| 98 | + const { data } = response | |
| 99 | + const config = response.config | |
| 100 | + if (!data) { | |
| 101 | + // 返回“[HTTP]请求没有返回值”; | |
| 102 | + throw new Error() | |
| 103 | + } | |
| 104 | + const { t } = useI18n() | |
| 105 | + // 未设置状态码则默认成功状态 | |
| 106 | + const code = data.code || result_code | |
| 107 | + // 二进制数据则直接返回 | |
| 108 | + if ( | |
| 109 | + response.request.responseType === 'blob' || | |
| 110 | + response.request.responseType === 'arraybuffer' | |
| 111 | + ) { | |
| 112 | + return response.data | |
| 113 | + } | |
| 114 | + // 获取错误信息 | |
| 115 | + const msg = data.msg || errorCode[code] || errorCode['default'] | |
| 116 | + if (ignoreMsgs.indexOf(msg) !== -1) { | |
| 117 | + // 如果是忽略的错误码,直接返回 msg 异常 | |
| 118 | + return Promise.reject(msg) | |
| 119 | + } else if (code === 401) { | |
| 120 | + // 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了 | |
| 121 | + if (!isRefreshToken) { | |
| 122 | + isRefreshToken = true | |
| 123 | + // 1. 如果获取不到刷新令牌,则只能执行登出操作 | |
| 124 | + if (!getRefreshToken()) { | |
| 125 | + return handleAuthorized() | |
| 126 | + } | |
| 127 | + // 2. 进行刷新访问令牌 | |
| 128 | + try { | |
| 129 | + const refreshTokenRes = await refreshToken() | |
| 130 | + // 2.1 刷新成功,则回放队列的请求 + 当前请求 | |
| 131 | + setToken(refreshTokenRes.data.data) | |
| 132 | + config.headers!.Authorization = 'Bearer ' + getAccessToken() | |
| 133 | + requestList.forEach((cb: any) => { | |
| 134 | + cb() | |
| 135 | + }) | |
| 136 | + requestList = [] | |
| 137 | + return service(config) | |
| 138 | + } catch (e) { | |
| 139 | + // 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。 | |
| 140 | + // 2.2 刷新失败,只回放队列的请求 | |
| 141 | + requestList.forEach((cb: any) => { | |
| 142 | + cb() | |
| 143 | + }) | |
| 144 | + // 提示是否要登出。即不回放当前请求!不然会形成递归 | |
| 145 | + return handleAuthorized() | |
| 146 | + } finally { | |
| 147 | + requestList = [] | |
| 148 | + isRefreshToken = false | |
| 149 | + } | |
| 150 | + } else { | |
| 151 | + // 添加到队列,等待刷新获取到新的令牌 | |
| 152 | + return new Promise((resolve) => { | |
| 153 | + requestList.push(() => { | |
| 154 | + config.headers!.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token 请根据实际情况自行修改 | |
| 155 | + resolve(service(config)) | |
| 156 | + }) | |
| 157 | + }) | |
| 158 | + } | |
| 159 | + } else if (code === 500) { | |
| 160 | + ElMessage.error(t('sys.api.errMsg500')) | |
| 161 | + return Promise.reject(new Error(msg)) | |
| 162 | + } else if (code === 901) { | |
| 163 | + ElMessage.error( | |
| 164 | + '<div>' + | |
| 165 | + t('sys.api.errMsg901') + | |
| 166 | + '</div>' + | |
| 167 | + '<div> </div>' + | |
| 168 | + '<div>参考 https://doc.iocoder.cn/ 教程</div>' + | |
| 169 | + '<div> </div>' + | |
| 170 | + '<div>5 分钟搭建本地环境</div>' | |
| 171 | + ) | |
| 172 | + return Promise.reject(new Error(msg)) | |
| 173 | + } else if (code !== 200) { | |
| 174 | + if (msg === '无效的刷新令牌') { | |
| 175 | + // hard coding:忽略这个提示,直接登出 | |
| 176 | + console.log(msg) | |
| 177 | + } else { | |
| 178 | + ElNotification.error({ | |
| 179 | + title: msg | |
| 180 | + }) | |
| 181 | + } | |
| 182 | + return Promise.reject('error') | |
| 183 | + } else { | |
| 184 | + return data | |
| 185 | + } | |
| 186 | + }, | |
| 187 | + (error: AxiosError) => { | |
| 188 | + console.log('err' + error) // for debug | |
| 189 | + let { message } = error | |
| 190 | + const { t } = useI18n() | |
| 191 | + if (message === 'Network Error') { | |
| 192 | + message = t('sys.api.errorMessage') | |
| 193 | + } else if (message.includes('timeout')) { | |
| 194 | + message = t('sys.api.apiTimeoutMessage') | |
| 195 | + } else if (message.includes('Request failed with status code')) { | |
| 196 | + message = t('sys.api.apiRequestFailed') + message.substr(message.length - 3) | |
| 197 | + } | |
| 198 | + ElMessage.error(message) | |
| 199 | + return Promise.reject(error) | |
| 200 | + } | |
| 201 | +) | |
| 202 | + | |
| 203 | +const refreshToken = async () => { | |
| 204 | + return await axios.post(base_url + '/system/auth/refresh-token?refreshToken=' + getRefreshToken()) | |
| 205 | +} | |
| 206 | +const handleAuthorized = () => { | |
| 207 | + const { t } = useI18n() | |
| 208 | + if (!isRelogin.show) { | |
| 209 | + isRelogin.show = true | |
| 210 | + ElMessageBox.confirm(t('sys.api.timeoutMessage'), t('common.confirmTitle'), { | |
| 211 | + confirmButtonText: t('login.relogin'), | |
| 212 | + cancelButtonText: t('common.cancel'), | |
| 213 | + type: 'warning' | |
| 214 | + }) | |
| 215 | + .then(() => { | |
| 216 | + const { wsCache } = useCache() | |
| 217 | + resetRouter() // 重置静态路由表 | |
| 218 | + wsCache.clear() | |
| 219 | + removeToken() | |
| 220 | + isRelogin.show = false | |
| 221 | + window.location.href = '/' | |
| 222 | + }) | |
| 223 | + .catch(() => { | |
| 224 | + isRelogin.show = false | |
| 225 | + }) | |
| 226 | + } | |
| 227 | + return Promise.reject(t('sys.api.timeoutMessage')) | |
| 228 | +} | |
| 229 | +export { service } | ... | ... |
yudao-ui-admin-vue3/src/hooks/web/useAxios.ts deleted
| 1 | -import { service } from '@/config/axios' | |
| 2 | - | |
| 3 | -import { config } from '@/config/axios/config' | |
| 4 | - | |
| 5 | -const { default_headers } = config | |
| 6 | - | |
| 7 | -const request = (option: AxiosConfig) => { | |
| 8 | - const { url, method, params, data, headersType, responseType } = option | |
| 9 | - return service({ | |
| 10 | - url: url, | |
| 11 | - method, | |
| 12 | - params, | |
| 13 | - data, | |
| 14 | - responseType: responseType, | |
| 15 | - headers: { | |
| 16 | - 'Content-Type': headersType || default_headers | |
| 17 | - } | |
| 18 | - }) | |
| 19 | -} | |
| 20 | - | |
| 21 | -async function getFn<T = any>(option: AxiosConfig): Promise<T> { | |
| 22 | - const res = await request({ method: 'GET', ...option }) | |
| 23 | - return res.data | |
| 24 | -} | |
| 25 | - | |
| 26 | -async function postFn<T = any>(option: AxiosConfig): Promise<T> { | |
| 27 | - const res = await request({ method: 'POST', ...option }) | |
| 28 | - return res.data | |
| 29 | -} | |
| 30 | - | |
| 31 | -async function deleteFn<T = any>(option: AxiosConfig): Promise<T> { | |
| 32 | - const res = await request({ method: 'DELETE', ...option }) | |
| 33 | - return res.data | |
| 34 | -} | |
| 35 | - | |
| 36 | -async function putFn<T = any>(option: AxiosConfig): Promise<T> { | |
| 37 | - const res = await request({ method: 'PUT', ...option }) | |
| 38 | - return res.data | |
| 39 | -} | |
| 40 | -async function downloadFn<T = any>(option: AxiosConfig): Promise<T> { | |
| 41 | - const res = await request({ method: 'GET', responseType: 'blob', ...option }) | |
| 42 | - return res as unknown as Promise<T> | |
| 43 | -} | |
| 44 | - | |
| 45 | -async function uploadFn<T = any>(option: AxiosConfig): Promise<T> { | |
| 46 | - option.headersType = 'multipart/form-data' | |
| 47 | - const res = await request({ method: 'PUT', ...option }) | |
| 48 | - return res as unknown as Promise<T> | |
| 49 | -} | |
| 50 | - | |
| 51 | -export const useAxios = () => { | |
| 52 | - return { | |
| 53 | - get: getFn, | |
| 54 | - post: postFn, | |
| 55 | - delete: deleteFn, | |
| 56 | - put: putFn, | |
| 57 | - download: downloadFn, | |
| 58 | - upload: uploadFn | |
| 59 | - } | |
| 60 | -} |
yudao-ui-admin-vue3/src/router/index.ts
| ... | ... | @@ -10,7 +10,7 @@ import { usePermissionStoreWithOut } from '@/store/modules/permission' |
| 10 | 10 | import { useDictStoreWithOut } from '@/store/modules/dict' |
| 11 | 11 | import { useUserStoreWithOut } from '@/store/modules/user' |
| 12 | 12 | import { listSimpleDictDataApi } from '@/api/system/dict/dict.data' |
| 13 | -import { isRelogin } from '@/config/axios' | |
| 13 | +import { isRelogin } from '@/config/axios/service' | |
| 14 | 14 | import { getInfoApi } from '@/api/login' |
| 15 | 15 | |
| 16 | 16 | const { start, done } = useNProgress() | ... | ... |