vue系列---【vue+webuploader实现文件分块上传】
html部分
<template> <div class="Upload"> <div class="data-content" id="content"> <div class="loanManagement_content"> <h1 class="mb35">上传文件</h1> <div class="upload-file-flex mb35"> <i>数据类型:</i> <el-radio-group v-model="uploadType" id="uploadFileType" @change="uploadTypeFn(uploadType)" > <el-radio :label="1">图片</el-radio> <el-radio :label="2">音频</el-radio> <el-radio :label="3">文本</el-radio> <el-radio :label="4">视频</el-radio> <el-radio :label="6">点云</el-radio> </el-radio-group> </div> <div class="upload-file-flex mb35"> <i>限制扩展名:</i> <div v-html="limitType[uploadType].type"></div> </div> <div id="uploader"> <div class="btns clearfix mgT20 mgB20"> <div id="picker" class="disInline float-left mgR10"></div> <el-button class="disInline float-left" size="small" :disabled="isDisabled" type="primary" id="ctlBtn" @click="handleStartUpload" >开始上传</el-button > </div> <!--用来存放文件信息--> <div id="thelist" class="uploader-list"> <div class="item" v-for="item in uploadFileList" :key="item.id"> <div class="clearfix mgB10"> <span class="info">{{ item.name }}</span> <span class="state">{{ processName }}</span> <p class="remove-btn disInline el-icon-delete" :class="{ removeBtn: removeBtn }" ></p> </div> </div> </div> </div> </div> </div> </div> </template>
js部分
<script> import $ from "jquery"; // import WebUploader from "webuploader"; import XLSX from "xlsx"; import axios from "axios"; import Qs from "qs"; export default { name: "uploadFile", data() { return { removeBtn: false, uploadType: "2", limitType: { 1: { type: ".csv、.xlsx、.xls", accept: ".csv, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", checkType: "csv,xlsx,xls", }, 2: { type: ".csv、.xlsx、.xls", accept: ".csv, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", checkType: "csv,xlsx,xls", }, 3: { type: ".txt", accept: "text/plain", checkType: "txt", }, 4: { type: ".csv、.xlsx、.xls", accept: ".csv, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", checkType: "csv,xlsx,xls", }, 6: { type: ".csv、.xlsx、.xls", accept: ".csv, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", checkType: "csv,xlsx,xls", }, }, acceptTypeObj: { title: "Files", extensions: "csv,xlsx,xls", mimeTypes: ".csv, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", }, uploadCheckType: "csv,xlsx,xls", uploadCheckMimeTypes: "", fileLists: [], getFiles: "", //队列文件个数 fileName: "", //上传文件名称 id: "", //start接口返回数据集id ossKey: "", fileSize: "", uploadStatus: "", isDisabled: false, uploadFileList: [], processName: "等待上传", //上传过程名称 materialAmount: "", //数据量 isCheckFlag: false, //是否检查过文件名标识 uploader: null, }; }, mounted() { document.cookie = `pin=${this.getQueryString("user")};path=/;maxAge=${ 24 * 60 * 60 * 1000 }`; this.uploadType = 1; this.uploadFile(); }, methods: { getQueryString(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); var r = ('?' + window.location.href.split('?')[1]).substr(1).match(reg); if (r != null) return unescape(r[2]); return null; }, uploadTypeFn(n) { this.uploadCheckType = this.limitType[n].checkType; this.uploadCheckMimeTypes = this.limitType[n].accept; this.acceptTypeObj = { title: "Files", extensions: this.uploadCheckType, mimeTypes: this.uploadCheckMimeTypes, }; this.uploadFile(); }, handleStartUpload(file) { if (this.uploadStatus === 4) { //上传失败 this.showProgress(file, "FILE"); this.uploader.retry(); } else { if (this.getFiles.length == 0) { this.$message({ message: "请选择文件", type: "warning", }); return false; } this.checkFileName( () => { this.processName = "上传中..."; this.uploader.upload(); }, () => { this.closeUploader(); }, ); } }, //上传文件 uploadFile() { let _this = this; var $btn = $("#ctlBtn"); var $thelist = $("#thelist"); var chunkSize = 5242880; //当前状态 // var state = "pending"; // HOOK 这个必须要再uploader实例化前面 WebUploader.Uploader.register( { "before-send-file": "beforeSendFile", "before-send": "beforeSend", }, { beforeSendFile: function (file) { // Deferred对象在钩子回掉函数中经常要用到,用来处理需要等待的异步操作。 var task = new $.Deferred(); // 根据文件内容来查询MD5 if (file.md5 != null && file.md5 !== "") { // file.md5 = file.md5; file.uid = WebUploader.Base.guid(); task.resolve(); } else { _this.uploader .md5File(file) .progress(function () { // 及时显示进度 if (file.md5 != null && file.md5 !== "") { return; } }) .then(function (val) { // 完成 file.md5 = val; // 模拟用户id file.uid = WebUploader.Base.guid(); task.resolve(); }); } return $.when(task); }, beforeSend: function (block) { var task = new $.Deferred(); var file = block.file; var missChunks = file.missChunks; var blockChunk = block.chunk; if ( missChunks !== null && missChunks !== undefined && missChunks !== "" ) { var flag = true; for (var i = 0; i < missChunks.length; i++) { if (blockChunk == missChunks[i]) { flag = false; break; } } if (flag) { //是断点续传,但当前块不是缺少的块,不发送。 task.reject(); } else { task.resolve(); //是断点续传,当前块是缺少的块,发送 } } else { task.resolve(); //不是断点续传,直接发送d当前数据块。 } return $.when(task); }, }, ); // 实例化 this.uploader = WebUploader.create({ //指定选择文件的按钮容器 pick: { id: "#picker", innerHTML: "<div class='el-icon-upload2'>选择文件</div>", multiple: false, }, //文件上传请求的参数表,每次发送都会发送此对象中的参数。 formData: { uid: 0, md5: "", chunkSize: chunkSize, }, accept: _this.acceptTypeObj, //dnd: '#dndArea',//此项实现拖拽的功能 //paste: '#uploader', swf: "js/Uploader.swf", //是否要分片处理大文件上传 chunked: true, // 如果要分片,分多大一片? 默认大小为5M. chunkSize: chunkSize, //上传并发数。允许同时最大上传进程数 threads: 1, server: "/xxx/xxx/upload", // url //设置为 true 后,不需要手动调用上传,有文件选择即开始上传 auto: false, // 禁掉全局的拖拽功能。这样不会出现图片拖进页面的时候,把图片打开。 disableGlobalDnd: true, //验证文件总数量, 超出则不允许加入队列(同时上传的文件数)B fileNumLimit: 1, //验证文件总大小是否超出限制, 超出则不允许加入队列B fileSizeLimit: 8 * 1024 * 1024 * 1024, //验证单个文件大小是否超出限制, 超出则不允许加入队列B fileSingleSizeLimit: 500 * 1024 * 1024, resize: false, }); //文件被添加进队列前 // this.uploader.on("beforeFileQueued", function (file) { }); // 当有文件被添加进队列的时候 this.uploader.on("fileQueued", function (file) { _this.getFiles = _this.uploader.getFiles().length; _this.fileName = file.name; _this.fileSize = file.size; _this.uploadStatus = 1; _this.uploadFileList.push(file); _this.getCSV(file.source.source, file.ext, file.id); }); $thelist.on("click", ".remove-btn", function () { var fileItem = $(this).parent().parent(); // var id = $(fileItem).attr("id"); _this.uploader.removeFile(_this.uploadFileList, true); $(fileItem).fadeOut(function () { $(fileItem).remove(); }); _this.closeUploader(); }); //当某个文件的分块在发送前触发,主要用来询问是否要添加附带参数,大文件在开起分片上传的前提下此事件可能会触发多次。 this.uploader.on("uploadBeforeSend", function (obj, data) { _this.uploadStatus = 0; var file = obj.file; data.md5 = file.md5 || ""; data.uid = file.uid; data.relativepath = obj.file.source.source.webkitRelativePath ? obj.file.source.source.webkitRelativePath : ""; data.fileType = "1"; data.fileName = obj.file.source.source.webkitRelativePath ? obj.file.source.source.webkitRelativePath : ""; }); // 上传过程中触发,携带上传进度 percentage ,是一个数字 this.uploader.on("uploadProgress", function (file, percentage) { _this.getProgressBar(file, percentage, "FILE", "上传进度"); }); // 上传返回结果 this.uploader.on("uploadSuccess", (file, res) => { const { code, data } = res; if (code && code == 200) { if (data) { var ossKey = data.imageName; var md5 = data.ETag; var uploadId = ""; if (data.uploadId) { uploadId = res.uploadId; } _this.uploadStatus = 3; _this.uploadComplete(ossKey, md5, file.id, uploadId); } } // if (res.result) { // var ossKey = res.result.Key; // var md5 = res.data.ETag; // var uploadId = ""; // if (res.uploadId) { // uploadId = res.uploadId; // } // _this.uploadStatus = 3; // _this.uploadComplete(ossKey, md5, file.id, uploadId); // } this.processName = "上传成功"; this.removeBtn = true; // $("#" + file.id) // .find(".state") // .text(this.processName); // $("#" + file.id) // .find(".remove-btn") // .remove(); }); this.uploader.on("uploadError", function (file) { _this.uploadStatus = 4; $("#" + file.id) .find(".state") .text("上传出错"); $btn.html("重新上传"); _this.handleStartUpload(file); // $btn.unbind('click'); // $btn.on('click', function () { // _this.showProgress(file, 'FILE'); // uploader.retry(); // }); }); this.uploader.on("uploadComplete", function (file) { _this.fadeOutProgress(file, "FILE"); }); // 文件上传 // $btn.on('click', function () { // if (_this.getFiles.length == 0) { // _this.$message({ // message: '请选择文件', // type: 'warning' // }); // return false; // } // _this.checkFileName(function () { // _this.processName = '上传中...'; // uploader.upload(); // }, function () { // closeUploader(); // }); // // _this.processName = '上传成功'; // }); //类型变换时 $("#uploadFileType").on("change", function () { _this.closeUploader(); }); }, //删除已上传队列 closeUploader() { this.getFiles = ""; this.fileName = ""; this.isDisabled = false; // 移除所有缩略图并将上传文件移出上传序列 for (var i = 0; i < this.uploader.getFiles().length; i++) { // 将图片从上传序列移除 this.uploader.removeFile(this.uploadFileList); // 将图片从缩略图容器移除 var $li = $("#" + this.uploadFileList.id); $li.off().remove(); } // 重置文件总个数和总大小 this.fileCount = 0; this.fileSize = 0; // 重置uploader,目前只重置了文件队列 this.uploader.reset(); }, /** * 生成进度条封装方法 * @param file 文件 * @param percentage 进度值 * @param id_Prefix id前缀 * @param titleName 标题名 */ getProgressBar(file, percentage, id_Prefix, titleName) { var $li = $("#" + file.id), $percent = $li.find("#" + id_Prefix + "-progress-bar"); // 避免重复创建 if (!$percent.length) { $percent = $( '<div id="' + id_Prefix + '-progress" class="progress progress-striped active">' + '<div id="' + id_Prefix + '-progress-bar" class="progress-bar" role="progressbar" style="width: 0%">' + "</div>" + "</div>", ) .appendTo($li) .find("#" + id_Prefix + "-progress-bar"); } var progressPercentage = Math.round(percentage * 100) + "%"; $percent.css("width", progressPercentage); $percent.html(titleName + ":" + progressPercentage); }, /** * 隐藏进度条 * @param file 文件对象 * @param id_Prefix id前缀 */ fadeOutProgress(file, id_Prefix) { $("#" + file.id) .find("#" + id_Prefix + "-progress") .fadeOut(); }, showProgress(file, id_Prefix) { $("#" + file.id) .find("#" + id_Prefix + "-progress") .show(); }, //获取csv内容 getCSV(file, ext, id) { // var _this = this; var sum = 0; if (ext === "csv" || ext === "CSV") { if (file) { var reader = new FileReader(); if (typeof FileReader == "undefined") { this.$message({ message: "你的浏览器暂不支持该功能", type: "warning", }); return false; } reader.readAsText(file, "utf-8"); reader.onload = function () { var relArr = this.result.split("\n"); if (!$.isEmptyObject(relArr) && relArr.length > 1) { for (var key = 0; key < relArr.length; key++) { var values = relArr[key]; if (!$.isEmptyObject(values)) { sum++; } } } console.log("csv----->" + (sum - 1)); $("#" + id).attr("data-num", sum - 1); }; } } else if (ext === "xlsx" || ext === "XLSX" || ext === "xls") { var fileReader = new FileReader(); fileReader.onload = function (ev) { try { var data = ev.target.result, workbook = XLSX.read(data, { type: "binary", }); // 以二进制流方式读取得到整份excel表格对象 } catch (e) { this.$message({ message: "文件类型不正确", type: "warning", }); return; } // 表格的表格范围,可用于判断表头是否数量是否正确 var fromTo = null; // 遍历每张表读取 for (var sheet in workbook.Sheets) { // eslint-disable-next-line no-prototype-builtins if (workbook.Sheets.hasOwnProperty(sheet)) { fromTo = workbook.Sheets[sheet]["!ref"]; sum = XLSX.utils.sheet_to_json(workbook.Sheets[sheet]).length; console.log("excel-----> " + sum); $("#" + id).attr("data-num", sum); break; // 如果只取第一张表,就取消注释这行 } } console.log(fromTo); }; // 以二进制方式打开文件 fileReader.readAsBinaryString(file); } }, //检查文件名称是否重复 checkFileName(callback, callback2) { var url = "/xx/xxx/xxxx", data = {}, _this = this; data.fileName = _this.fileName; axios({ method: "post", url, data: Qs.stringify(data), headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", }, }).then((res) => { if (res.data.code == 200 && res.data.data == 0) { if (typeof callback == "function") { callback(); } if (!_this.isCheckFlag) { _this.uploadStart(); } _this.isDisabled = false; } else { _this.$message({ message: "文件名重复,请重新选择文件!", type: "error", }); _this.isDisabled = true; if (typeof callback2 == "function") { callback2(); } return false; } }); }, //开始上传调用后端接口 uploadStart() { var url = "/xxx/xxx/start", data = {}, _this = this; data.fileName = _this.fileName; data.fileType = _this.uploadType; data.dirFlag = 2; //文件夹标识:1,文件夹;2,文件 data.extensionName = _this.uploadCheckType; axios({ method: "post", url, data: Qs.stringify(data), headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", }, }).then((res) => { if (res.data.code == 200) { _this.id = res.data.data; _this.isCheckFlag = true; } else { _this.$message({ message: res.data.msg, type: "error", }); } }); // utils.promise(data, url, "post", "isAsync").done(function (res) { // if (res.code == 200) { // _this.id = res.data; // _this.isCheckFlag = true; // } else { // _this.$message({ // message: res.msg, // type: "error", // }); // } // }); }, //上传完成 uploadComplete(ossKey, md5, fileId, uploadId) { var url = "/xxx/xxx/uploadComplete", data = {}, _this = this; data.id = _this.id; data.osskey = ossKey; data.fileSize = _this.fileSize; data.uploadStatus = _this.uploadStatus; data.md5 = md5; data.materialAmount = $("#" + fileId).attr("data-num"); data.uploadId = uploadId; axios({ method: "post", url, data: Qs.stringify(data), headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", }, }).then((res) => { console.log(res,"res===="); if (res.data.code == 200) { _this.$message({ message: res.data.msg, type: "success", }); //清除文件列表页面页码缓存 sessionStorage.removeItem("/dataManage/data_lists/pageNo"); sessionStorage.removeItem("/dataManage/data_lists/pageSize"); setTimeout(() => { window.location.href = `${document.referrer}dataManage/data_lists#data`; }, 1000); } else { _this.$message({ message: res.data.msg, type: "error", }); //清除文件列表页面页码缓存 sessionStorage.removeItem("/dataManage/data_lists/pageNo"); sessionStorage.removeItem("/dataManage/data_lists/pageSize"); setTimeout(() => { window.location.href = `${document.referrer}dataManage/data_lists#data`; }, 1000); } }); // utils.promise(data, url, "post").done(function (res) { // if (res.code == 200) { // _this.$message({ // message: res.msg, // type: "success", // }); // } else { // _this.$message({ // message: res.msg, // type: "error", // }); // } // }); }, }, }; </script>
css部分
<style lang="scss"> @import "../assets/scss/resetElement.css"; .uploadFile { .removeBtn { display: none; } .loanManagement_content { margin: 20px; } .data-content { width: 1200px; margin: 0 auto; min-height: 700px; overflow: auto; background: #fff; position: relative; } .data-lists-content { width: 100% !important; padding: 30px !important; margin-left: 0 !important; } .mb20 { margin-bottom: 20px; } .mb35 { margin-bottom: 35px; } .upload-file-flex { display: flex; align-items: center; justify-content: start; } .upload-file-flex i { flex: 0 0 100px; font-style: normal; } .el-upload-list { width: 500px; } .el-progress-bar__outer { height: 6px !important; } .el-upload-list__item .el-icon-upload-success { font-size: 18px; } .el-upload-list__item-status-label { top: 3px !important; } .btns .webuploader-pick { display: inline-block; padding: 8px 15px; font-size: 12px; vertical-align: middle; background: #ffffff; border: 1px solid #dcdfe6; color: #606266; } .uploader-list .item { overflow: hidden; } .uploader-list .item .info { float: left; margin-right: 20px; font-weight: normal; font-size: 14px; } .uploader-list .item .state { float: left; margin-right: 20px; color: #aaa; } .uploader-list .item .remove-btn { vertical-align: middle; cursor: pointer; } } </style>