上传
赞
踩
实现功能:
1.对上传的zip压缩包进行解压。
2.解析excel页签中内容,用于列表数据展示。
3.解决文件名中带有汉字时解析乱码问题。
4.上传excel附件,用于预览。
5.采用input中type="file"来实现上述功能
1.html
<div @click="upload">上传</div> <!-- 加一层if判断的原因:防止上传一次之后,在没有刷新的前提下,再次点击上传,不触发上传功能。 --> <div v-if="uploadShowFlag"> <input type="file" @change="performanceUploadProcess" ref="inputer" v-show="false" /> </div> <!-- 是否确认上传弹框 --> <!-- 此处使用的是Ant Design Vue 组件--> <a-modal v-model="determine " title="上传确认" @ok="sure" @cancel="clockConfirm" > <p>获取文件信息成功,点击确定将进行上传</p> </a-modal>
2.js
npm i jszip
npm i xlsx
npm i iconv-lite //解决文件名乱码
import XLSX from "xlsx";
import JsZip from "jszip";
import {uploadFile,configFileReader,arrayBufferToBase64,dataURLtoFile} from './index'
import iconv from "iconv-lite"
data() {
return {
uploadListZip: [],//压缩包解析后的excel汇总数据上传
uploadShowFlag: false,//上传按钮触发
determine: false,//是否确认上传弹框
zipList: [],//压缩包解析前文件列表
flagLength:'',//用于记录异步解读的条数
upFlagSum:0,//用于计数当前解读的文件为第几条
}
},
methods: { //1.用VUE按钮代替input原生按钮并触发 folderButtonClick(){ //每次点击上传时,初始化数据。 this.uploadShowFlag = true; this.resultList = []; this.uploadListZip = []; this.zipList = []; this.flagLength = ""; this.upFlagSum = 0; //因为之前加了if判断,属于动态创建销毁input,所以需要使用nextTick进行处理 this.$nextTick(()=>{ this.$refs.inputer.click(); }) }, //2.判断文件类型 performanceUploadProcess() { const inputDOM = this.$refs.inputer; const fileName = inputDOM.files[0].name; const fileType = fileName.substr(fileName.lastIndexOf(".") + 1); if (fileType === "zip") { this.zipXlsxUpload(); } else { this.$message.error("上传文件类型错误,请重新上传"); } }, //3.上传ZIP压缩包,读取并处理其中XLSX数据相关方法-- zipXlsxUpload() { const inputDOM = this.$refs.inputer; var zip = new JsZip(); //解压zip zip.loadAsync(inputDOM.files[0], { //解决文件名乱码问题 decodeFileName: function (bytes) { return iconv.decode(bytes, 'gbk'); } }).then((file) => { //excel文件列表 this.zipList = file.files; //摘除非excel数据 let arr =[]; for (let key in this.zipList) { if (/\.(xlsx)$/.test(key)) { arr.push(this.zipList[key]) } } const asyncReaderList = arr.filter((r) => !r.dir && r.name.indexOf("MACOSX") === -1) //因为id只存在于文件名,所以解析前进行需要的数据拼接 let asyncReaderListCopy = []; asyncReaderList.forEach(item =>{ let obj ={ // 员工Id格式:文件夹名/12345678姓名.xlsx employeeId : /\/(\d{8})(.*)\.xlsx/.exec(item.name)[1], value : zip.file(item.name).async("uint8array"), name : item.name } asyncReaderListCopy.push(obj) }) //用于reader.onload异步调用计数 this.flagLength = asyncReaderListCopy.length; asyncReaderListCopy.forEach(zipFile=>{ //用于取到promise中的数据 Promise.resolve(zipFile.value).then((item)=>{ //1>用于附件上传,预览功能 let base = arrayBufferToBase64(item); // Base64 转 File 对象 const result = dataURLtoFile(base, zipFile.name); // console.log(result,'最终解压后的File对象') this.resultList.push(result); //2>用于读取每个excel页签里的内容 const reader = new FileReader(zipFile.name); reader.onload = (e) => { this.onReaderLoad(e,zipFile.employeeId); }; reader.readAsBinaryString(new Blob([item])); }) }) }).catch((err) => { // 请求失败 this.$message.error(err) }); }, //4取出XLSX文件数据 onReaderLoad(e,employeeId) { this.upFlagSum ++; //等待所有数据转换完成后在打开弹框确认上传 if(this.flagLength == this.upFlagSum){ this.determine = true; //打开预览模态框 } let excelData = e.content; //设置时间读取格式1>.{ type: "binary" ,cellDates:true,cellText:false} const workbook = XLSX.read(excelData, { type: "binary" ,cellDates:true,cellText:false}); if (workbook.Sheets) { const worksheet = workbook.Sheets[workbook.SheetNames[0]]; //设置时间读取格式2>.{ raw: false,dateNF: 'yyyy/mm/dd'} const data = XLSX.utils.sheet_to_json(worksheet, { header: 1 ,raw: false,dateNF: 'yyyy/mm/dd'}); //将读取的数据存入对象 let entity = { id:employeeId,//取自文件名的id name: data[2][3],//姓名 evaluationDate: data .filter((r) => r.length === 9 && r[6] === "日期:") .map((r) => r[8])[0],//日期 ( ... 更多数据 ) }; //将读取的数据,存入数组中,用于保存 this.uploadListZip.push(entity); } }, //取消 clockConfirm(){ this.uploadShowFlag = false; }, //确定 pfMarkConfirm() { this.uploadShowFlag = false; this.determine = false; //调取保存和上传接口 }, }, mounted() { //记得初始化哦 configFileReader(); }
3.index.js(摘取的可以公用的方法)
//初始化解读文档 export function configFileReader() { FileReader.prototype.readAsBinaryString = function (fileData) { var binary = ""; var pt = this; var reader = new FileReader(); reader.onload = function () { var bytes = new Uint8Array(reader.result); var length = bytes.byteLength; for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); } pt.content = binary; pt.onload(pt); //页面内data取pt.content文件内容 }; reader.readAsArrayBuffer(fileData); }; } //uint8array转base64 export function arrayBufferToBase64(array) { array = new Uint8Array(array); var length = array.byteLength; var table = ['A','B','C','D','E','F','G','H', 'I','J','K','L','M','N','O','P', 'Q','R','S','T','U','V','W','X', 'Y','Z','a','b','c','d','e','f', 'g','h','i','j','k','l','m','n', 'o','p','q','r','s','t','u','v', 'w','x','y','z','0','1','2','3', '4','5','6','7','8','9','+','/']; var base64Str = ''; for(var i = 0; length - i >= 3; i += 3) { var num1 = array[i]; var num2 = array[i + 1]; var num3 = array[i + 2]; base64Str += table[num1 >>> 2] + table[((num1 & 0b11) << 4) | (num2 >>> 4)] + table[((num2 & 0b1111) << 2) | (num3 >>> 6)] + table[num3 & 0b111111]; } var lastByte = length - i; if(lastByte === 1) { let lastNum1 = array[i]; base64Str += table[lastNum1 >>> 2] + table[((lastNum1 & 0b11) << 4)] + '=='; } else if(lastByte === 2){ let lastNum1 = array[i]; var lastNum2 = array[i + 1]; base64Str += table[lastNum1 >>> 2] + table[((lastNum1 & 0b11) << 4) | (lastNum2 >>> 4)] + table[(lastNum2 & 0b1111) << 2] + '='; } return base64Str; } //base64流 export function dataURLtoFile(dataURL, fileName, fileType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') { /** * 注意:【不同文件不同类型】,例如【图片类型】就是`data:image/png;base64,${dataURL}`.split(',') * 下面的是【excel文件(.xlsx尾缀)】的文件类型拼接 */ const arr = `data:${fileType};base64,${dataURL}`.split(',') const mime = arr[0].match(/:(.*?);/)[1] const bstr = atob(arr[1]) let n = bstr.length const u8arr = new Uint8Array(n) while (n--) { u8arr[n] = bstr.charCodeAt(n) } let blob = new File([u8arr], fileName, { type: mime }) return blob }
如果您有更好的想法,欢迎留言讨论,共同进步!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。