You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
469 lines
13 KiB
469 lines
13 KiB
'use strict'
|
|
|
|
//引入axios
|
|
import axios from 'axios'
|
|
import QS from 'qs'
|
|
import router from '@/router'
|
|
import config from './config'
|
|
import utils from './utils'
|
|
import { useAppStore } from '@/store/app.js'
|
|
import { showToast, showConfirmDialog, allowMultipleToast, setToastDefaultOptions } from 'vant'
|
|
|
|
// 惰性获取 Pinia store(替代原 Vuex 的 import store from "@/store/index")
|
|
const appStore = () => useAppStore()
|
|
|
|
allowMultipleToast()
|
|
setToastDefaultOptions({ forbidClick: true })
|
|
|
|
const base = {
|
|
baseUrl: config.baseUrl,
|
|
timeout: 300000,
|
|
}
|
|
|
|
//关闭页面
|
|
const closeWindow = () => {
|
|
var userAgent = navigator.userAgent
|
|
if (userAgent.indexOf('Firefox') != -1 || userAgent.indexOf('Chrome') != -1) {
|
|
window.location.href = 'about:blank'
|
|
window.close()
|
|
} else {
|
|
window.opener = null
|
|
window.open('', '_self')
|
|
window.close()
|
|
}
|
|
|
|
// 微信中关闭
|
|
if (WeixinJSBridge) {
|
|
WeixinJSBridge.call('closeWindow')
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 提示函数
|
|
* 禁止点击蒙层、显示3秒后关闭
|
|
*/
|
|
const toast = (msg) => {
|
|
showToast({
|
|
message: msg,
|
|
duration: 4000,
|
|
forbidClick: true,
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 跳转登录页
|
|
* 携带当前页面路由,以期在登录页面完成登录后返回当前页面
|
|
*/
|
|
const toLogin = () => {
|
|
router.replace({
|
|
path: '/liics/login',
|
|
query: {
|
|
redirect: router.currentRoute.fullPath,
|
|
},
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 请求失败后的错误统一处理
|
|
* @param {Number} status 请求失败的状态码
|
|
*/
|
|
const errorHandle = (status, msg) => {
|
|
// 状态码判断
|
|
switch (status) {
|
|
//未登录状态,跳转登录页 跳转登录
|
|
case 401:
|
|
// toLogin();
|
|
// 清除token
|
|
toast('【401】当前会话超时,请刷新页面')
|
|
appStore().del_token()
|
|
sessionStorage.removeItem('token')
|
|
break
|
|
// 403 token过期
|
|
// 清除token并跳转登录页
|
|
case 403:
|
|
toast('【403】当前会话超时,请刷新页面')
|
|
// 清除token
|
|
appStore().del_token()
|
|
sessionStorage.removeItem('token')
|
|
setTimeout(() => {
|
|
// toLogin();
|
|
}, 1000)
|
|
break
|
|
// 404请求不存在
|
|
case 404:
|
|
toast('哎呦~404了~休息一下')
|
|
break
|
|
case 408:
|
|
toast('【408】请求超时')
|
|
break
|
|
case 500:
|
|
toast('【500】当前网络不给力,请检查你的网络设置')
|
|
break
|
|
case 503:
|
|
toast('【503】当前服务器不可用,请稍后重试')
|
|
break
|
|
// 其他错误,直接抛出错误提示
|
|
default:
|
|
toast(`连接错误${msg}`)
|
|
}
|
|
}
|
|
|
|
// 请求超时时间
|
|
axios.defaults.timeout = base.timeout
|
|
|
|
//设置默认请求头
|
|
// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
|
|
axios.defaults.headers.post['Content-Type'] = 'application/json'
|
|
|
|
// 请求拦截器
|
|
axios.interceptors.request.use(
|
|
(config) => {
|
|
// 每次发送请求之前判断是否存在token,如果存在,则统一在http请求的header都加上token,不用每次请求都手动添加了
|
|
// 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断
|
|
const token = appStore().token
|
|
// console.log("https===token:", token)
|
|
token && (config.headers.token = token)
|
|
return config
|
|
},
|
|
(error) => {
|
|
return Promise.reject(error)
|
|
},
|
|
)
|
|
|
|
// 响应拦截器
|
|
axios.interceptors.response.use(
|
|
// 请求成功
|
|
(res) => {
|
|
if (res.data.code === 10001) {
|
|
appStore().del_token()
|
|
sessionStorage.removeItem('token') // 删除已经失效或过期的token(不删除也可以,因为登录后覆盖)
|
|
|
|
// 如果没有展示返回头部的话去掉弹窗按钮
|
|
if (appStore().notitle === '1') {
|
|
toast('当前会话已结束,请刷新页面或关闭页面重新进入')
|
|
return Promise.resolve(res)
|
|
}
|
|
|
|
showConfirmDialog({
|
|
title: '提示',
|
|
message: '当前会话已结束,请刷新页面或关闭页面重新进入',
|
|
confirmButtonText: '取消',
|
|
cancelButtonText: '确认',
|
|
confirmButtonColor: '#000000',
|
|
cancelButtonColor: '#000000',
|
|
})
|
|
.then(() => {
|
|
// on cancel (现在是右边的取消按钮)
|
|
// utils.closeWindow();
|
|
// router.replace({
|
|
// path: '/404' // 到登录页重新获取token
|
|
// })
|
|
})
|
|
.catch(() => {
|
|
// on confirm (现在是左边的确认按钮)
|
|
//确认重新刷新页面获取token
|
|
// window.location.reload();
|
|
utils.AppReloadHtml()
|
|
})
|
|
|
|
return Promise.resolve(res)
|
|
}
|
|
|
|
res.status === 200 ? Promise.resolve(res) : Promise.reject(res)
|
|
|
|
return res
|
|
},
|
|
// 服务器状态码不是200的情况
|
|
// 请求失败
|
|
async (error) => {
|
|
const { response } = error
|
|
if (response) {
|
|
//过滤排队接口弹窗问题
|
|
if (
|
|
response.config.url.indexOf('HumanChat/queueNumbers') != -1 ||
|
|
response.config.url.indexOf('HumanChat/msgCallBack') != -1
|
|
) {
|
|
return Promise.reject(response)
|
|
}
|
|
|
|
if (response.data.code === 10001) {
|
|
appStore().del_token()
|
|
sessionStorage.removeItem('token') // 删除已经失效或过期的token(不删除也可以,因为登录后覆盖)
|
|
|
|
// 如果没有展示返回头部的话去掉弹窗按钮
|
|
if (appStore().notitle === '1') {
|
|
toast('当前会话已结束,请刷新页面或关闭页面重新进入')
|
|
return Promise.reject(response)
|
|
}
|
|
|
|
showConfirmDialog({
|
|
title: '提示',
|
|
message: '当前会话已结束,请刷新页面或关闭页面重新进入',
|
|
confirmButtonText: '取消',
|
|
cancelButtonText: '确认',
|
|
confirmButtonColor: '#000000',
|
|
cancelButtonColor: '#000000',
|
|
})
|
|
.then(() => {
|
|
// on cancel (现在是右边的取消按钮)
|
|
// utils.closeWindow();
|
|
// router.replace({
|
|
// path: '/404' // 到登录页重新获取token
|
|
// })
|
|
})
|
|
.catch(() => {
|
|
// on confirm (现在是左边的确认按钮)
|
|
//确认重新刷新页面获取token
|
|
// window.location.reload();
|
|
utils.AppReloadHtml()
|
|
})
|
|
|
|
return Promise.reject(response)
|
|
}
|
|
|
|
// 请求已发出,但是不在2xx的范围
|
|
errorHandle(response.status, response.statusText)
|
|
return Promise.reject(response)
|
|
} else {
|
|
// 处理断网的情况
|
|
// eg:请求超时或断网时,更新state的network状态
|
|
// network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏
|
|
// 关于断网组件中的刷新重新获取数据,会在断网组件中说明
|
|
// store.commit('changeNetwork', false);
|
|
if (error?.message?.includes('timeout')) {
|
|
// 判断请求异常信息中是否含有超时timeout字符串
|
|
toast('请求超时,稍后重试!')
|
|
return Promise.reject(error)
|
|
}
|
|
|
|
toast('当前网络不给力,请检查你的网络设置')
|
|
return Promise.reject(error)
|
|
}
|
|
},
|
|
)
|
|
|
|
/**
|
|
* get方法,对应get请求
|
|
* @param {String} url [请求的url地址]
|
|
* @param {Object} params [请求时携带的参数]
|
|
*/
|
|
export function Get(url, params) {
|
|
return new Promise((resolve, reject) => {
|
|
url = base.baseUrl + url
|
|
|
|
axios
|
|
.get(url, QS.stringify(params))
|
|
.then((res) => {
|
|
resolve(res.data)
|
|
})
|
|
.catch((err) => {
|
|
reject(err.status)
|
|
})
|
|
})
|
|
}
|
|
|
|
/**
|
|
* post方法,对应post请求
|
|
* @param {String} url [请求的url地址]
|
|
* @param {Object} params [请求时携带的参数]
|
|
*/
|
|
export function Post(url, params) {
|
|
return new Promise((resolve, reject) => {
|
|
url = base.baseUrl + url
|
|
console.log('url', url, base);
|
|
axios
|
|
.post(url, params)
|
|
.then((res) => {
|
|
resolve(res.data)
|
|
})
|
|
.catch((err) => {
|
|
reject(err.status)
|
|
})
|
|
})
|
|
}
|
|
|
|
/**
|
|
* post方法,对应post请求
|
|
* @param {String} url [请求的url地址]
|
|
* @param {Object} params [请求时携带的参数]
|
|
*/
|
|
export function fetchPost(url, params) {
|
|
return new Promise((resolve, reject) => {
|
|
url = base.baseUrl + url
|
|
|
|
axios
|
|
.post(url, params, {
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
token: appStore().token,
|
|
},
|
|
})
|
|
.then((res) => {
|
|
resolve(res.data)
|
|
})
|
|
.catch((err) => {
|
|
reject(err.status)
|
|
})
|
|
})
|
|
}
|
|
|
|
/**
|
|
* post方法,对应post请求 上传图片专用
|
|
* @param {String} url [请求的url地址]
|
|
* @param {Object} params [请求时携带的参数]
|
|
*/
|
|
export function upLoadImgHttp(url, params) {
|
|
return new Promise((resolve, reject) => {
|
|
url = base.baseUrl + url
|
|
const instance = axios.create({
|
|
withCredentials: true,
|
|
})
|
|
|
|
instance
|
|
.post(url, params, {
|
|
headers: {
|
|
'Content-Type': 'multipart/form-data',
|
|
token: appStore().token,
|
|
},
|
|
})
|
|
.then((res) => {
|
|
resolve(res.data)
|
|
})
|
|
.catch((err) => {
|
|
reject(err.status)
|
|
})
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 获取图片数据(支持base64格式)
|
|
* @param {String} url [请求的url地址]
|
|
* @param {Object} params [请求时携带的参数]
|
|
* @param {Object} options [额外配置选项]
|
|
*/
|
|
export function fetchImageData(url, params, options = {}) {
|
|
return new Promise((resolve, reject) => {
|
|
url = base.baseUrl + url
|
|
|
|
const { timeout = 10000 } = options
|
|
|
|
const instance = axios.create({
|
|
timeout,
|
|
withCredentials: true,
|
|
})
|
|
|
|
instance
|
|
.post(url, params, {
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
token: appStore().token,
|
|
},
|
|
})
|
|
.then((res) => {
|
|
// 检查响应格式
|
|
if (res.data.code !== 0) {
|
|
reject(new Error(res.data.msg || 'Request failed'))
|
|
return
|
|
}
|
|
|
|
const imageData = res.data.data
|
|
if (!imageData || !imageData.content) {
|
|
reject(new Error('Invalid response: missing image content'))
|
|
return
|
|
}
|
|
|
|
// 验证文件扩展名是否为图片格式
|
|
const validImageExts = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'bmp']
|
|
const fileExt = imageData.fileNameExt?.toLowerCase()
|
|
if (!validImageExts.includes(fileExt)) {
|
|
reject(new Error(`Unsupported image format: ${fileExt}`))
|
|
return
|
|
}
|
|
|
|
resolve({
|
|
fileName: imageData.fileName,
|
|
fileCrc: imageData.fileCrc,
|
|
fileNameExt: imageData.fileNameExt,
|
|
content: imageData.content,
|
|
// 构建完整的data URL
|
|
dataUrl: `data:image/${fileExt};base64,${imageData.content}`,
|
|
})
|
|
})
|
|
.catch((err) => {
|
|
reject(err)
|
|
})
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 获取图片文件流(保持向后兼容)
|
|
* @deprecated 使用 fetchImageData 替代
|
|
*/
|
|
export function fetchImageStream(url, params, options = {}) {
|
|
return fetchImageData(url, params, options).then((imageData) => {
|
|
// 将base64转换为blob以保持兼容性
|
|
return base64ToBlob(imageData.content, `image/${imageData.fileNameExt}`)
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 将base64字符串转换为Blob对象
|
|
* @param {String} base64Data - base64编码的数据(不包含前缀)
|
|
* @param {String} contentType - MIME类型
|
|
* @returns {Blob} Blob对象
|
|
*/
|
|
export function base64ToBlob(base64Data, contentType = 'image/png') {
|
|
try {
|
|
// 解码base64数据
|
|
const byteCharacters = atob(base64Data)
|
|
const byteNumbers = new Array(byteCharacters.length)
|
|
|
|
for (let i = 0; i < byteCharacters.length; i++) {
|
|
byteNumbers[i] = byteCharacters.charCodeAt(i)
|
|
}
|
|
|
|
const byteArray = new Uint8Array(byteNumbers)
|
|
return new Blob([byteArray], { type: contentType })
|
|
} catch (error) {
|
|
throw new Error(`Failed to convert base64 to blob: ${error.message}`)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 通用文件下载方法
|
|
* @param {String} url [请求的url地址]
|
|
* @param {Object} params [请求时携带的参数]
|
|
* @param {Object} options [配置选项]
|
|
*/
|
|
export function downloadFile(url, params, options = {}) {
|
|
return new Promise((resolve, reject) => {
|
|
url = base.baseUrl + url
|
|
|
|
const { timeout = 30000, responseType = 'blob', method = 'POST' } = options
|
|
|
|
const config = {
|
|
url,
|
|
method,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
token: appStore().token,
|
|
},
|
|
responseType,
|
|
timeout,
|
|
}
|
|
|
|
if (method.toUpperCase() === 'POST') {
|
|
config.data = params
|
|
} else {
|
|
config.params = params
|
|
}
|
|
|
|
axios(config)
|
|
.then((res) => {
|
|
resolve(res.data)
|
|
})
|
|
.catch((err) => {
|
|
reject(err)
|
|
})
|
|
})
|
|
}
|
|
|