Appearance
接口模块
api使用方法原理
🐾🐾基于axios封装的请求库
install(app: App) { //安装方法
app.provide(QAPI_INJECT_KEY, this)
app.config.globalProperties.$http = this.$http
const module: Map = this._options.module ? { ...this._options.module, ...BuiltModuleActons } : { ...BuiltModuleActons }
instllBuiltModuleActons(this, module)
}
export function createApi(options: AxiosRequestCustomConfig) { //实例方法
return new Request(options)
}
export function useHttp<T>(key: InjectionKey<T> | string | null = null) { //使用方法
return inject(key !== null ? key : QAPI_INJECT_KEY) as Request
}//对象TS
import { AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios'
//定义扩展接口类型
export interface requestInterceptors {
//// 请求拦截
requestInterceptors?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig
requestInterceptorsCatch?: (err: Map) => Map
// // 响应拦截
responseInterceptors?: (config: AxiosResponse) => AxiosResponse
responseInterceptorsCatch?: (err: Map) => Map
}
//继承axiso请求配置,加上模块和白名单
export interface AxiosRequestCustomConfig extends AxiosRequestConfig {
module?: object //接口模块
interceptors?: requestInterceptors
responseInterceptorsCatchMsgFun?: (err: Map) => boolean //响应错误
requestInterceptorsCatchMsgFun?: (err: Map) => boolean //请求错误
isOpenShowErrorOneTip?: boolean
responseInterceptorsAtfterCatchMsgFun?: (err: Map) => boolean //响应成功,但是接口code5xx或者4xx提示
}
class Request{ //实例对象ts
....
}通过在app事后使用use安装该包,并且export使用方法和实例方法
api配置
main.ts
js
...
import qApiPlugin from './utils/qApiPlugin' //在utils工具库实例化api包
...
app.use(qApiPlugin)qApiPlugin.ts
api使用展示
1.0)在V6环境下使用
js
//在setup组件函数下使用
<script setup lang="ts">
...
import qqtApi from '@qqt-product/api'
...
const qhttp: qqtApi.Request = qqtApi.useHttp()
...
//method:get/post/delete..
//config ==axois conifg //config可以是axios里面的配置包括参考axios官方文档
qhttp.[method]({
[...config]
url:xxxx,
data/parmas
})
<script>
//在setup()使用
<script lang="ts">
...
import qqtApi from '@qqt-product/api'
...
export default defineComponent({
...
const qhttp: qqtApi.Request = qqtApi.useHttp()
...
return {
qhttp
}
})
<script>1.1)在V6环境下使用registerModuleAction
api包对比v5来说,多了一个核心api接口封装
基于v5整理了一些核心模块的接口统一放到了module里面包括:
login--登录模块
permission--用户权限模块
roles--角色模块
schedule--日历模块
system--系统信息模块
user--用户模块使用
//在setup组件函数下使用(仅仅展示在steup使用,其他方式参考上面)
<script setup lang="ts">
...
import qqtApi from '@qqt-product/api'
...
const qhttp: qqtApi.Request = qqtApi.useHttp()
...
//模块/名称
qhttp.registerModuleAction('login/getEncryptedKey')
//名称- 里面已经做了处理,如果直接使用接口名称必须要存在不存在报错
qhttp.registerModuleAction('getEncryptedKey')
qhttp.registerModuleAction('login', {
data: {
loginType: null,
elsAccount: '',
subAccount: '',
password: '',
keyId: '',
},
})
})
<script>2.0)其他包用,基于引入到V6
仅仅展示setup组件函数
<script lang="ts" setup>
//TS
export interface RequestConfig extends MapObjectNoneType {
baseURL?: string
headers?: object
timeout?: number
url?: string
params?: object
data?: object
}
export interface ResponseData extends MapObjectNoneType {
code?: number
message?: string
result?: any
success?: boolean
}
export interface HttpClient {
get(config: RequestConfig): Promise<ResponseData>
post(config: RequestConfig): Promise<ResponseData>
}
import {inject } from 'vue'
const qHttp = inject('http') as HttpClient
<script>3.0)下载需要调整或者需要配置更多请求项目
qHttp[acType]({
url: exportXlsUrl,
params: params,
data: params,
responseType: 'blob',
})
.then((data) => {
// responseType为blob的请求,统一获取错误信息
if (data.type === 'application/json') {
const fileReader = new FileReader()
fileReader.onloadend = () => {
const jsonData = JSON.parse(fileReader.result as string)
message.error(jsonData.message)
}
fileReader.readAsText(data as Blob)
return
}
if (!data) {
message.error('文件下载失败')
return
}
// if ('msSaveBlob' in window.navigator) {
// window.navigator.msSaveBlob(new Blob([data as Blob]), fileName + '.xls')
// } else {
const url = window.URL.createObjectURL(new Blob([data as Blob]))
const link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', `${fileName}.${type}`)
document.body.appendChild(link)
link.click()
document.body.removeChild(link) //下载完成移除元素
window.URL.revokeObjectURL(url) //释放掉blob对象
// }
})
.finally(() => {
// confirmLoading.value = false
afterCallback && afterCallback()
})其他配置
1)配置自定义接口模块(示例)
//创建一个customModule文件放自定义的接口模块
//列子-custom.ts 文件
import type { ApiModuleStyle } from '../types/index'
import qqtApi from '../../lib/index'
export default <ApiModuleStyle>{
name: 'LoginModule',
actions: {
getEncryptedKey: (http: qqtApi.Request, data: unknown) => {
...
},
login: (http: qqtApi.Request, data: unknown) => {
...
},
loginByToken: (http: qqtApi.Request, params: unknown) => {
...
},
phoneLogin: (http: qqtApi.Request, data: unknown) => {
...
},
getSmsCaptcha: (http: qqtApi.Request, data: unknown) => {
...
},
getInfo: (http: qqtApi.Request, params: unknown) => {
...
},
getUserInfo: (http: qqtApi.Request, params: unknown) => {
...
},
},
}
//utils下的qApiPlugin.ts引入该文件
//import custom from './custom'
qqtApi.createApi({
module:{custom}
})2)多个错误只提示一个弹窗
//继承axiso请求配置
export interface AxiosRequestCustomConfig extends AxiosRequestConfig {
module?: object //接口模块
interceptors?: requestInterceptors
responseInterceptorsCatchMsgFun?: (err: unknown) => boolean //响应错误
requestInterceptorsCatchMsgFun?: (err: unknown) => boolean //请求错误
isOpenShowErrorOneTip?: boolean
responseInterceptorsAtfterCatchMsgFun?: (err: unknown) => boolean //响应成功,但是接口code5xx或者4xx提示
}isOpenShowErrorOneTip:true的时候必须配置responseInterceptorsCatchMsgFun,requestInterceptorsCatchMsgFun,responseInterceptorsAtfterCatchMsgFun
建议响应拦截和请求拦截的报错放到对应的这个3个函数里面函数并返回Boolen类型
qqtApi.createApi({
isOpenShowErrorOneTip: true,
responseInterceptorsCatchMsgFun: (err) => {return Funerr(err)},
requestInterceptorsCatchMsgFun: (err)=>{
return true
}
responseInterceptorsAtfterCatchMsgFun:(result: any) =>{
return resErr(result.data )
}
})3)520或者530报错后,取消后面的接口请求(最新V7)
api包
request.ts 优化
export class Request {
$http: AxiosInstance
source = axios.CancelToken.source()
interceptors: requestInterceptors | undefined
_options: AxiosRequestCustomConfig
_actions: Map = Object.create(null)
apiSets: Map = Object.create(null)
....
//再次封装request方法
request<Map>(config: AxiosRequestConfig): Promise<Map> {
if (this.interceptors?.requestInterceptors) {
config = this.interceptors.requestInterceptors({
...config,
cancelToken: this.source.token,//(新增)
headers: config.headers as AxiosRequestHeaders,
})
}
return this.$http.request<any, Map>(config)
}
}SMR
qApiPlugin.ts调整
function Funerr(error: MapObject) {
const token = getUserStoreToken()
if (error.response) {
switch (error.response.status) {
case 403:
message.warning(srmI18n('拒绝访问'))
break
case 520:
if (token) {
clearUserStore()
api.source && api.source.cancel()//(新增)
message.warning(
{
content: srmI18n('很抱歉,登录已过期,请重新登录!'),
},
2000,
)
}
break
case 404:
message.warning(srmI18n('很抱歉,资源未找到!'))
break
case 504:
message.warning(srmI18n('网络超时'))
break
case 401:
message.warning(srmI18n('网络超时'))
break
default:
message.warning(srmI18n('网络超时'))
break
}
}
return Promise.reject(error)
}
function loginAgainByCode(code: number) {
const tips = code === 520 ? srmI18n('很抱歉,登录已过期,请重新登录!') : srmI18n('当前用户已被登出,请重新登录!')
checkedWhileListAddress().then((res) => {
if (!res) {
const { setLogout } = useUserStore()
setLogout().then(() => {
api.source && api.source.cancel()//(新增)
})
if (RESPONSE_520_OR_530) {
Modal.info({
title: srmI18n('系统提示'),
content: tips,
okText: srmI18n('关闭'),
onOk() {
window.location.reload()
},
})
RESPONSE_520_OR_530 = false
}
}
})
}