@zhangqingcq/plug-r-qw
Version:
A JS lib base on Vue and View-design, you can achieve some complex functions with simple code after install this lib.
401 lines (388 loc) • 10.5 kB
JavaScript
/**
* created 2019.04.01
* @author Ricky <zhangqingcq@foxmail.com>
*/
import axios from 'axios'
import messageBox from './messageBox.js'
import _ from 'lodash'
import { t } from '../locale/index'
import { counts } from './spin'
const host = window.location.origin
// 创建自定义对象
let service = axios.create({
baseURL: host,
withCredentials: true // 允许携带cookie
})
function notInitYet() {
console.info(
'store为空,请在安装插件时传入store实例,vuex:Vue.use(plugRQw,{store}),Pinia:Vue.use(plugRQw,{useStore})'
)
}
/**
* 拦截器,在发起请求前调用
*/
service.interceptors.request.use(
(q) => {
return q
},
(e) => {
return Promise.reject(e)
}
)
function logoutHandle() {
if (service.store) {
if (typeof service.store === 'function') {
const store = service.store()
if (store.logout) {
store.logout()
}
} else {
service.store.dispatch('logout')
}
} else {
notInitYet()
}
}
/**
* 拦截器,在请求返回时调用
*/
service.interceptors.response.use(
(r) => {
if (r?.data?.code === 403 || r?.data?.code === 409) {
messageBox({
content: t('r.http.' + r.data.code),
onOk: logoutHandle
})
}
return r
},
(e) => {
if (e?.response?.status === 403 || e?.response?.status === 409) {
messageBox({
content: t('r.http.' + e.response.status),
onOk: logoutHandle
})
}
console.warn('请求出错:', e)
return Promise.reject(e)
}
)
/**
* 封装请求结果和错误处理
*/
function checkResult(r, msg, rPath, config) {
if (config?.spin) {
counts(false)
}
let y = true
let d = r?.data
if (d) {
rPath = rPath ? rPath : []
for (let e of rPath) {
d = d[e]
y = y && d
}
if (y) {
return d
}
msg && console.warn(msg)
return false
}
msg && console.warn(msg)
return false
}
function handleRequest(method, url, data, msg, rPath, config, isUrlData) {
return new Promise((s, j) => {
switch (method) {
case 'get':
service
.get(url, { params: data })
.then((r) => {
let d = checkResult(r, msg, rPath, config)
if (d) {
s(d)
} else {
j(r)
}
})
.catch((e) => {
checkResult({}, msg, rPath, config)
j(e)
})
break
case 'delete':
let keyT = isUrlData ? 'params' : 'data'
service
.delete(url, { [keyT]: data })
.then((r) => {
let d = checkResult(r, msg, rPath, config)
if (d) {
s(d)
} else {
j(r)
}
})
.catch((e) => {
checkResult({}, msg, rPath, config)
j(e)
})
break
case 'post':
service
.post(url, data, config)
.then((r) => {
let d = checkResult(r, msg, rPath, config)
if (d) {
s(d)
} else {
j(r)
}
})
.catch((e) => {
checkResult({}, msg, rPath, config)
j(e)
})
break
case 'put':
service
.put(url, data, config)
.then((r) => {
let d = checkResult(r, msg, rPath, config)
if (d) {
s(d)
} else {
j(r)
}
})
.catch((e) => {
checkResult({}, msg, rPath, config)
j(e)
})
break
default:
}
})
}
/**
* 检查请求传入的各个参数
* @param method 请求方法
* @param url 地址
* @param data 餐宿
* @param msg 错误信息
* @param rPath 返回数据路径(提取)
* @param config 请求配置
* @param isUrlData delete方法传参模式 true:params,false:data
* @returns {Promise<*>}
*/
function checkRequest(method, url, data, msg, rPath, config = {}, isUrlData) {
return new Promise((s, j) => {
if (url) {
if (config?.spin) {
counts(true)
}
let url_ = url
if (window?.g) {
/*所有特定缩写字母开头的地址,都会被改变加上config.js(public里的全局配置文件,在index.html引入,在打包后通过更改该文件用于不
同环境的部署)里配置的地址变成绝对地址,如:
config.js里配置了 window.g={mgrURL:'http://mgr.myweb.com'}
请求地址 ‘/mgr/file’ 会被改变为 'http://mgr.myweb.com/file'
*/
let httpEnv = Object.keys(window.g)
.filter((e) => e?.indexOf?.('URL') > -1)
.map((e) => e?.replace?.('URL', ''))
for (let e of httpEnv) {
let regExp = new RegExp('^/' + e + '(?=/.*$)', 'i')
if (regExp.test(url) && window.g[e + 'URL']) {
url_ = window.g[e + 'URL'] + url.replace(regExp, '')
break
}
}
}
let data_
if (config?.headers?.['Content-Type'] === 'multipart/form-data') {
data_ = data
} else {
if (Array.isArray(data)) {
data_ = []
} else {
data_ = {}
}
if (data && !_.isEmpty(data)) {
if (Array.isArray(data)) {
for (let e of data) {
if (e || e === 0 || e === false || (e === '' && !config.noEmptyStr)) {
data_.push(e)
}
}
} else {
for (let key in data) {
if (
data.hasOwnProperty(key) &&
(data[key] || data[key] === 0 || data[key] === false || (data[key] === '' && !config.noEmptyStr))
) {
data_[key] = data[key]
}
}
}
}
}
let method_ = method.toLowerCase()
handleRequest(method_, url_, data_, msg, rPath, config, isUrlData)
.then((r) => {
s(r)
})
.catch((e) => {
j(e)
})
} else {
console.error('没有请求地址:url')
j('没有请求地址:url')
}
})
}
/**
* @description 基于axios封装的请求插件,引入库时使用this.$fetch时直接调用以下方法,例如:this.$fetch.get("/getData",{id:1}),
* 单独引入时遵循Es Modules规范即可
* @class
*/
export default {
/**
* @description 初始化该请求插件,单独引入的话调用一次后,方可实现spin等功能,默认在该库安装时已自动化初始化了该请求插件
* @function
* @param {object} store 项目中vuex的store
*/
init(store) {
service.store = store
},
/**
* post 请求
* @function
* @param {string} url 请求地址
* @param {object} data 请求数据
* @param {string} msg 错误信息,在控制台输出,方便调试,不用可以不传,例如:
* @example this.$fetch.post("/getDataB",{name:'ricky'},"获取数据B失败")
* @param {Array.<string>} rPath 请求结果提取路径,如:[data,list]表示data.list,如不需过滤可不传
* @param {object} config 请求配置 如请求过程需要遮罩层,设置 spin:true即可
* @return {Promise<object>}
* @example this.$fetch.post("/getData",{id:1},null,['result','list'])
* .then(r=>{
* console.log(r)
* r相当于:data.result.list,data是网络请求结果
* })
*
* 注意:
* 请求最多支持5个入参,最少一个(url),依次为:url,data,msg,rPath,config。如果要传靠后的入参,但不想传前面的,应该这样传:
* this.$fetch.post("/setData",{},null,[],{
* headers: {
* 'Content-Type': 'multipart/form-data'
* },
* spin:true
* }
* )
*/
post(url, data = {}, msg, rPath, config) {
return new Promise((s, j) => {
checkRequest('post', url, data, msg, rPath, config)
.then((r) => {
s(r)
})
.catch((e) => {
j(e)
})
})
},
/**
* put请求
* @param {string} url 请求地址
* @param {object} data 请求数据
* @param {string} msg 错误信息,在控制台输出,方便调试,不用可以不传
* @param {Array.<string>} rPath 请求结果提取路径
* @param {object} config 请求配置 如请求过程需要遮罩层,设置 spin:true即可
* @return {Promise<unknown>}
*/
put(url, data = {}, msg, rPath, config) {
return new Promise((s, j) => {
checkRequest('put', url, data, msg, rPath, config)
.then((r) => {
s(r)
})
.catch((e) => {
j(e)
})
})
},
/**
* get请求
* @param {string} url 请求地址
* @param {object} data 请求数据
* @param {string} msg 错误信息,在控制台输出,方便调试,不用可以不传
* @param {Array.<string>} rPath 请求结果提取路径
* @param {object} config 请求配置 如请求过程需要遮罩层,设置 spin:true即可
* @return {Promise<unknown>}
* PS: get请求时(delete请求同理),可以把请求参数写在url里,也可以写在data里,注意写在data里时,data是对象
* 以请求'/devices',找到id=2,name='meter'举例:
* 只传url时,url = '/devices?id=2&name=meter'
* url和data都传时,url = '/devices',data={id:2,name:'meter'}
*/
get(url, data = {}, msg, rPath, config) {
return new Promise((s, j) => {
checkRequest('get', url, data, msg, rPath, config)
.then((r) => {
s(r)
})
.catch((e) => {
j(e)
})
})
},
/**
* delete 请求
* @param {string} url 请求地址
* @param {object} data 请求数据
* @param {string} msg 错误信息,在控制台输出,方便调试,不用可以不传
* @param {Array.<string>} rPath 请求结果提取路径
* @param {object} config 请求配置 如请求过程需要遮罩层,设置 spin:true即可
* @param isUrlData 传参模式 true:params,false:data
* @return {Promise<unknown>}
*/
delete(url, data = {}, msg, rPath, config, isUrlData = true) {
return new Promise((s, j) => {
checkRequest('delete', url, data, msg, rPath, config, isUrlData)
.then((r) => {
s(r)
})
.catch((e) => {
j(e)
})
})
},
/**
* 并发请求 例如:
* @example this.$fetch.all(
* [
* this.$fetch.get("/getData"),
* this.$fetch.post("/getDataB",{name:'ricky'})
* ]
* )
*/
all: axios.all,
/**
* 并发请求结果分离 例如:
* @example this.$fetch.all(
* [
* this.$fetch.get("/getData"),
* this.$fetch.post("/getDataB",{name:'ricky'})
* ]
* )
* .then(
* this.$fetch.spread((result1,result2)=>{
* console.log(result1,result2)
* })
* )
*/
spread: axios.spread,
/**
* 该请求插件暴露给外界的配置对象,为axios.create创建的实例对象,使用方法见axios官方网站
*/
config: service
}