vue中大文件上传至AWS s3组件
<template> <div class="minioBox"> <el-button v-if="model === 'button' && fileList.length < maxLen" style=" margin-right: 10px; color: #3f51b5; font-size: 14px; line-height: 20px; " :disabled="disabled" @click="getFileName" size="mini" type="text" >+上传</el-button > <el-button v-if="model === 'text' && fileList.length < maxLen" style=" marginleft: 20px; color: #909399; font-size: 13px; line-height: 20px; " :disabled="disabled" @click="getFileName" class="el-icon-circle-plus-outline" size="mini" type="text" >上传文件</el-button > <input :accept="fileTypeList.join(',')" type="file" multiple="multiple" ref="minIoFile" v-show="false" @change="getFile" /> <ul class="uploadFileList"> <li v-for="(item, index) of fileList" :key="index" style="display: flex"> <span>{{ index + 1 }}.</span> <el-select v-model="item.dataStream" size="mini" style="width: 100px; margin: 0 20px" v-if="updateComponent && isUpDataStream" placeholder="数据流" @change="changeItem" > <el-option v-for="(stream, key) in streamList" :key="stream + key" :label="stream" :value="stream" > </el-option> </el-select> <span class="subString">{{ item.name.length > 10 ? item.name.substring(0, 10) + "..." : item.name }}</span > <span>({{ (item.size / 1024 / 1024).toFixed(2) }}M)</span> <span v-if="item.percent === 100" style="color: #4052b5" ><i class="el-icon-success"></i>上传成功</span > <div v-if="!isUpload" class="floatRight" style="float: right"> <i class="el-icon-close" style="cursor: pointer" @click="deleteMinioFile(index)" ></i> </div> </li> </ul> </div> </template> <script> import AWS from "aws-sdk"; export default { props: { model: { type: String, default: "button", }, maxLen: { type: Number, default: 2, }, progress: { type: Boolean, default: false, }, fileTypeList: { type: Array, default: [".*"], }, disabled: { type: Boolean, default: false, }, isUpDataStream: { type: Boolean, default: false, }, }, data() { return { streamList: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], fileList: [], fileCopyList: [], fileUp: false, isUpload: false, updateComponent: true, uploadList: [], timer: null, updateObject: {}, usedTime: 0, uploadTimer: null, loadedTotal: 0, fileTotal: 0, s3: {}, dataInfo: { accessKeyId: JSON.parse(localStorage.getItem("dataInfo")).ak, secretAccessKey: JSON.parse(localStorage.getItem("dataInfo")).sk, endpoint: JSON.parse(localStorage.getItem("dataInfo")).point, s3ForcePathStyle: JSON.parse(localStorage.getItem("dataInfo")) .s3ForcePathStyle, signatureVersion: "v4", }, }; }, created() {}, methods: { changeItem(item, index) { this.updateComponent = false; setTimeout(() => { this.updateComponent = true; }, 0); }, selectLen() { let _vm = this; return new Promise((resolve, reject) => { resolve(_vm.fileList.length); }); }, upload(obj) { if (this.isUpDataStream) { let hasStream = true; this.fileList.forEach((item) => { if (!item.dataStream) { hasStream = false; } }); if (!hasStream) { this.$message.warning("请选择数据流"); this.$emit("hasStream", true); return; } } this.dataInfo = { accessKeyId: JSON.parse(localStorage.getItem("dataInfo")).ak, secretAccessKey: JSON.parse(localStorage.getItem("dataInfo")).sk, endpoint: JSON.parse(localStorage.getItem("dataInfo")).point, s3ForcePathStyle: JSON.parse(localStorage.getItem("dataInfo")) .s3ForcePathStyle, signatureVersion: "v4", }; this.s3 = new AWS.S3(this.dataInfo); if (this.fileList.length === 0) { let nullFile = { type: obj, list: false, }; this.$emit("uploadSuccess", nullFile); } this.updateObject = obj; this.uploadList = []; this.isUpload = true; this.timer = setInterval(() => { this.fileUp = !this.fileUp; }, 0); this.fileList.forEach((item) => { this.fileTotal += item.size; }); this.fileList.map((item, index) => { this.uploadMinIo(item, index); }); }, clearfield() { this.fileList = []; this.uploadList = []; this.isUpload = false; }, deleteMinioFile(index) { this.fileList.splice(index, 1); this.$refs.minIoFile.value = ""; }, getFileName() { let inputDOM = this.$refs.minIoFile; inputDOM.click(); }, getFile(event) { let files = this.$refs.minIoFile.files; let fileSwitch = true; if (files.length > 0) { for (let i = 0; i < files.length; i++) { if ((files[i].size / 1024 / 1024 / 1024).toFixed(2) > 6400) { this.$message({ message: `${files.name}超过文件的最大长度`, type: "warning", }); fileSwitch = false; } } if (fileSwitch) { for (let i = 0; i < files.length; i++) { if (this.fileList.length < this.maxLen) { this.fileList.push(files[i]); // let obj = { // name: files[i].name, // dataStream: "", // percent: 0, // size: files[i].size, // }; // this.fileCopyList.push(obj); this.$emit("fileList", this.fileList); } else { if (this.maxLen != 1 && this.maxLen != 6) { this.$message.warning(`最多只能够添加6个文件`); return; } else { this.$message.warning(`最多只能够添加${this.maxLen}个文件`); return; } } } } } }, uploadMinIo(file, index) { let vm = this; vm.uploadTimer = setInterval(() => { vm.usedTime += 1; }, 1000); vm.fileUp = true; let YY = new Date().getFullYear(); let MM = new Date().getMonth() + 1; let DD = new Date().getDate(); let fileName = file.name; let uuid = vm.generateUUID(); if (file) { let params = { Bucket: JSON.parse(localStorage.getItem("dataInfo")) .bucketName /* required */, Key: `${YY}/${MM}/${DD}/${uuid}/${fileName}` /* required */, Body: file, }; this.s3 .upload(params, function (err, data) { clearInterval(vm.uploadTimer); if (err) { vm.$emit("uploadFail", err); } else { let fileObj = { dataFile: file.name, dataType: file.type, dataAddr: data.Location, dataKey: data.Key, bucket: data.Bucket, dataSize: file.size, dataStream: file.dataStream, }; vm.uploadList.push(fileObj); if (vm.uploadList.length === vm.fileList.length) { let time = setTimeout(() => { clearInterval(vm.timer); vm.fileUp = true; clearTimeout(time); }, 500); let obj = { type: vm.updateObject, list: vm.uploadList, }; vm.$emit("uploadSuccess", obj); } } }) .on("httpUploadProgress", (e) => { let per = parseInt(e.loaded, 10) / parseInt(e.total, 10); per = Number((per * 100).toFixed(0)); file.percent = per; file.loaded = e.loaded; let uploadData = { per: per, time: vm.usedTime, }; file.uploadData = uploadData; vm.getUploadTime(); }); } }, getUploadTime() { this.loadedTotal = 0; this.fileList.forEach((item) => { if (item.loaded) { this.loadedTotal += parseInt(item.loaded); } }); let need = 0; let per = (this.loadedTotal / this.fileTotal).toFixed(2) * 100; need = ((this.usedTime / (per / 100)) * (1 - per / 100)).toFixed(2); let neew = this.getRevTime(parseInt(need)); let obj = { per: parseInt(per), needTime: neew, }; this.$emit("uploadProgress", obj); }, getRevTime(time) { if (time / 3600 > 24) { return `大于一天`; } else if (time / 3600 > 1) { let hh = Math.floor(time / 3600); let mm = Math.floor((time % 3600) / 60); return `大约需要${hh}时${mm}分`; } else if (time / 60 > 1) { let mm = Math.floor(time / 60); let ss = Math.floor(time % 60); return `大约需要${mm}分${ss}秒`; } else { return `大约需要${time}秒`; } }, generateUUID() { var d = new Date().getTime(); if (window.performance && typeof window.performance.now === "function") { d += performance.now(); // use high-precision timer if available } var uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace( /[xy]/g, function (c) { var r = (d + Math.random() * 16) % 16 | 0; d = Math.floor(d / 16); return (c === "x" ? r : (r & 0x3) | 0x8).toString(16); } ); return uuid; }, }, }; </script> <style lang="scss" scoped> .minioBox { color: #000000; padding: 0px; width: 90%; line-height: 20px; min-height: 40px; .uploadFileList { width: 100%; list-style: none; margin-top: 5px; padding: 0; li { height: 40px; line-height: 26px; margin: 0px !important; span { vertical-align: top; } .subString { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; width: 40%; display: inline-block; } i { margin: 5px 5px 0 0; } .el-icon-close, .el-icon-upload-success { float: right; } .upload-success { color: green; } .upload-fail { color: red; } } li:hover { background-color: #f5f7fa; } li:first-child { margin-top: 10px; } /deep/ .progress { margin-top: 2px; width: 200px; height: 14px; margin-bottom: 10px; overflow: hidden; background-color: #f5f5f5; border-radius: 4px; -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); display: inline-block; .progress-bar { background-color: rgb(92, 184, 92); background-image: linear-gradient( 45deg, rgba(255, 255, 255, 0.14902) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.14902) 50%, rgba(255, 255, 255, 0.14902) 75%, transparent 75%, transparent ); background-size: 40px 40px; box-shadow: rgba(0, 0, 0, 0.14902) 0px -1px 0px 0px inset; box-sizing: border-box; color: rgb(255, 255, 255); display: block; float: left; font-size: 12px; height: 20px; line-height: 20px; text-align: center; transition-delay: 0s; transition-duration: 0.6s; transition-property: width; transition-timing-function: ease; width: 266.188px; } } } } </style>