/** * 封装axios的类 * nh 2021.12.23 */ import axios from "axios"; import vueStore from "@/store"; import { logicConfig } from "@/logicConfig"; import { toolUtils } from "@/utils/toolUtils"; import SparkMD5 from 'spark-md5'; var CancelToken = axios.CancelToken; var cancel; // 创建axios实例 const axiosservice = axios.create({ timeout: 3000000, // 请求超时时间 cancelToken: new CancelToken(function executor(c) { // executor 函数接收一个 cancel 函数作为参数 cancel = c; }), }); axiosservice.interceptors.request.use( (config) => { return config; }, (error) => { return Promise.reject(error); } ); axiosservice.interceptors.response.use( function (res) { //在这里对返回的数据进行处理 let resp = res.data; return res; }, function (err) { console.error("axios interceptors err = ", err); return Promise.reject(err); } ); export class axiosUtils { /** * get请求 * @param url * @param data * @returns */ protected async getRequest(url: string, data: any) { try { var urlArr = url.split("?"); var urlPrefix = urlArr[0]; var urlParamStr = urlArr[1] || ""; var _newParamStr = toolUtils.objectKeyToUrlParam(data); var newUrl = urlPrefix + '?' + _newParamStr + '&' + urlParamStr; let response = await this.customRequest(newUrl, {}, {}, "get"); return response; } catch (err) { throw err; } } /** * post请求 * @param url * @param data * @returns */ protected async postRequest(url: string, data: any) { try { let response = await this.customRequest(url, {}, data, "post"); return response; } catch (err) { throw err; } } /** * 自定义请求 * @param url * @param headers * @param data * @param method get | post 默认post * @returns */ protected async customRequest( url: string, headers: any, data: any, method: string = "post" ) { try { //headers里放入 groupCode、projectId 为了兼顾老ADM的写法,以后可删除 headers = headers || {}; headers.groupCode = headers.groupCode || vueStore.state.selectProject.groupCode; headers.projectId = headers.projectId || vueStore.state.selectProject.id; var urlArr = url.split("?"); var urlPrefix = urlArr[0]; var urlParamStr = urlArr[1] || ""; if (urlParamStr.indexOf("projectId=") == -1) { urlParamStr = "projectId=" + vueStore.state.selectProject.id + "&" + urlParamStr; } if (urlParamStr.indexOf("groupCode=") == -1) { urlParamStr = "groupCode=" + vueStore.state.selectProject.groupCode + "&" + urlParamStr; } url = urlPrefix + "?" + urlParamStr; let response = await axiosservice({ url, headers: headers || {}, data, method: method == "post" ? "post" : "get", }); return response.data; } catch (err) { // throw err; console.error(err); return toolUtils.resultConstructor(logicConfig.resultObj.failure, null, '请求异常,' + err.message); } } /** * 上传文件 * @param _paramobj 格式如下: * { * fileServiceUrl 文件服务地址 * uploadProgressCall 上传进度回调函数,函数参数为object,格式如下:{fileName:'文件名称',uploadedTotal:1},uploadedTotal某个文件总共上传的字节数 * oneUploadedCall 每上传完一个后的回调函数,函数参数为object,格式如下:{fileName:'文件名称',fileId:'文件ID'} * userId:'不传时,默认会取vuex中user.id', * files 数组或者object,示例 * { * groupCode:'不传时,默认会取vuex中selectProject.groupCode', * projectId:'不传时,默认会取vuex中selectProject.id', * fileName:'文件名称', * fileBucket:'存储空间名称,可以不传', * file:文件信息,假设有一个input type为file id为txtFile的标签,那么file为document.getElementById('txtFile').files[0] * } * } * @returns */ protected async uploadFiles(_paramobj: any) { //注意,这里的this 指向的是实例化的子类 var _this = this; let userId = _paramobj.userId || vueStore.state.user.id; let fileServiceUrl = _paramobj.fileServiceUrl; let files = _paramobj.files; try { let waitFiles = files instanceof Array == true ? files : [files]; //上传成功的文件数量 let uploadedCount = 0; for (let i = 0; i < waitFiles.length; i++) { let _currFileObj = waitFiles[i]; //获取文件md5 let fileContentMd5 = await getFileContentMd5(_currFileObj); //获取文件上传地址 let getUploadResult = await getUploadUrl(fileContentMd5 as string, _currFileObj); switch (getUploadResult.result) { case logicConfig.resultObj.success: let getUploadData = getUploadResult.data || {}; //uploadCode 200 代表已经上传过了; 201 代表需上传 switch (getUploadData.uploadCode) { case 201: //获取文件地址上传成功时进行上传 let uploadUrl = ((getUploadData.content || [])[0] || {}).uploadUrl; if (!uploadUrl) return toolUtils.resultConstructor(logicConfig.resultObj.failure, null, '未获取到文件' + _currFileObj.fileName + '的上传地址'); //开始上传 await upload(uploadUrl, _currFileObj.file, function (progressObj) { if (typeof _paramobj.uploadProgressCall == 'function') { let uploadedFileSize = progressObj.loaded / progressObj.total * _currFileObj.file.size; _paramobj.uploadProgressCall({ uploadedTotal: uploadedFileSize, fileName: _currFileObj.fileName }); } }); case 200: ++uploadedCount; if (typeof _paramobj.oneUploadedCall == 'function') { _paramobj.oneUploadedCall({ fileName: _currFileObj.fileName, fileId: getUploadData.id }); } break; } break; default: return toolUtils.resultConstructor(logicConfig.resultObj.failure, null, '获取文件' + _currFileObj.fileName + '的上传地址时出错:' + getUploadResult.message); } if (uploadedCount == waitFiles.length) return toolUtils.resultConstructor(logicConfig.resultObj.success, null, null); } } catch (error) { console.error(error); return toolUtils.resultConstructor(logicConfig.resultObj.failure, null, error.message); } //获取文件内容的md5值 function getFileContentMd5(_fileObj) { return new Promise((resolve, reject) => { let file = _fileObj.file; let blobSlice = File.prototype.slice; let chunkSize = 2097152; let chunks = Math.ceil(file.size / chunkSize); let currentChunk = 0; let spark = new SparkMD5.ArrayBuffer(); let fileReader = new FileReader(); fileReader.onload = function (e) { spark.append(e.target.result); // Append array buffer currentChunk++; if (currentChunk < chunks) { loadNext(); } else { let fileContentMd5 = spark.end(); console.info('computed hash', fileContentMd5); // Compute hash //文件md5获取完成后,调用后台接口获取上传地址 // let getUploadResult = await getUploadUrl(fileContentMd5, _fileObj.fileName, file.size); resolve(fileContentMd5); } }; fileReader.onerror = function (e) { let errStr = '文件:' + _fileObj.fileName + '读取错误:'; console.error(e); reject(errStr); }; function loadNext() { var start = currentChunk * chunkSize, end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize; fileReader.readAsArrayBuffer(blobSlice.call(file, start, end)); } loadNext(); }); }; //获取文件上传地址 async function getUploadUrl(fileContentMd5: string, _fileObj: any) { let fileName = _fileObj.fileName; let fileSize = _fileObj.file.size; let projectId = _fileObj.projectId || vueStore.state.selectProject.id; let groupCode = _fileObj.groupCode || vueStore.state.selectProject.groupCode; //应用ID暂时用不上 let appId = ''; let getUploadUrl = toolUtils.getBaseHttpUrl(fileServiceUrl, 'file/initSingleUpload') + '?userId=' + userId + '&projectId=' + projectId + '&groupCode=' + groupCode + '&appId='; let paramObj = { fileMd5: fileContentMd5, fileName: fileName, fileBucket: (window as any).__systemConf.baseRouteUrl, fileSize: fileSize }; return await _this.customRequest(getUploadUrl, null, paramObj, 'post'); }; //上传 async function upload(uploadUrl, file, uploadProgressCall) { return new Promise((resolve, reject) => { var formData = new FormData(); formData.append('file', file); axios.put(uploadUrl, formData, { onUploadProgress: uploadProgressCall }).then(function (res) { resolve(res); }).catch(function (error) { reject(error); }); }); } }; }