excel文件上传,我这里面整理了两种方案
第一种:前端读取excel文件,然后封装数据,传给后端,后端直接写入数据库
第二种:前端传formData数据,后端获取到之后读取数据,然后写入数据库
以下是实现的代码逻辑,我这里面专门封装了一个文件上传的组件
<template><div class="fileBox"><input type="file" ref="upload" @change='exportData' accept=".xls,.xlsx" class="outputlist_upload"><el-button type="primary" >{{fileObj.title}}</el-button></div>
</template>
<script>
import XLSX from 'xlsx'
export default {name: "inputExcel",props:{fileObj:{type:Object,default:()=>{return {title:"导入",type:""}}}},data() {return {}},methods:{exportData(event) {if(!event.currentTarget.files.length) { return;}if(this.fileObj.type == 'dispose'){this.exdis(event)}else{this.upData(event)}},// 上传文件流upData(event){let file = event.target.files[0]// this.files = file;console.log(event,file)const extension = file.name.split('.')[1] === 'xls'const extension2 = file.name.split('.')[1] === 'xlsx'const isLt2M = file.size / 1024 / 1024 < 5if (!extension && !extension2) {this.$message.warning('上传模板只能是 xls、xlsx格式!')return}if (!isLt2M) {this.$message.warning('上传模板大小不能超过 5MB!')return}let fileName = file.name;let fileFormData = new FormData();fileFormData.append('file', file);//filename是键,file是值,就是要传的文件,test.zip是要传的文件名this.$emit('fileUpdataFlow',fileFormData)},// 直接转成json上传exdis(event){const that = this;// 拿取文件对象var f = event.currentTarget.files[0];// 用FileReader来读取var reader = new FileReader();// 重写FileReader上的readAsBinaryString方法FileReader.prototype.readAsBinaryString = function(f) {var binary = "";var wb; // 读取完成的数据var outdata; // 你需要的数据var reader = new FileReader();reader.onload = function(e) {// 读取成Uint8Array,再转换为Unicode编码(Unicode占两个字节)var bytes = new Uint8Array(reader.result);var length = bytes.byteLength;for (var i = 0; i < length; i++) {binary += String.fromCharCode(bytes[i]);}// 接下来就是xlsx了,具体可看apiwb = XLSX.read(binary, {type: "binary"});outdata = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);// 自定义方法向父组件传递数据that.$emit("getResult", outdata);};reader.readAsArrayBuffer(f);};reader.readAsBinaryString(f);}}
}
</script>
<style lang="scss" scoped>.fileBox{position: relative;.outputlist_upload{position: absolute;top: 0;left: 0;width:100%;height:40px;opacity: 0;cursor: pointer;}}
</style>
把结果$emit到父组件里面,父组件去处理
getResult(data){var data1 = []for(var i = 0 ; i < data.length;i++){data1.push({job_number:data[i]['工号'],login_name:data[i]['邮箱'],real_name:data[i]['姓名'],password:hex_md5('123456') ,mail:data[i]['邮箱'],phone_number:data[i]['手机号']})}let paramsPkg = {fun: "/users/toLead",method: "post",data:{list:data1},};this.$store.dispatch("getHttpData", {paramsPkg}).then(json => {if (json.code == this.$config.successCode) {this.$message({type: 'success',message: `成功导入${json.data.total}条!`});this.handleCurrentChange(1)}})},fileUpdataFlow(data){let paramsPkg = {fun: "/users/toLeadFlow",method: "post",headers: "multipart/form-data;boundary="+new Date().getTime(),data:data,};this.$store.dispatch("getHttpData", {paramsPkg}).then(json => {if (json.code == this.$config.successCode) {console.log(json)this.$message({type: 'success',message: `成功导入${json.data.total}条!`});this.handleCurrentChange(1)}})},
前端处理的情况下,我这边引入了XLSX组件,如果是直接传formData数据的时候需要注意修改Content-Type头,我这里是把axios二次封装了,要注意Content-Type需要写成 "multipart/form-data;boundary="+new Date().getTime(),并且在封装的时候不要走请求拦截器的二次封装JSON,
后端使用node处理
var multer = require('connect-multiparty')
var XLSX= require('xlsx');
const multiparMiddleware = multer()// 批量导入 如果存在相同用户则忽略
router.post('/toLeadFlow',multiparMiddleware,async function(req, res, next) {let excelData = []; //用来保存let reqData = [];const workbook = XLSX.readFile(req.files.file.path);const sheetNames = workbook.SheetNames; for (var sheet in workbook.Sheets) {if (workbook.Sheets.hasOwnProperty(sheet)) {//fromTo = workbook.Sheets[sheet]['!ref'];//解析excel文件得到数据excelData = excelData.concat(XLSX.utils.sheet_to_json(workbook.Sheets[sheet]));}}for(var i=0;i < excelData.length;i++){reqData.push({id:await utils.uuidGenerate(),role_id:0,job_number:excelData[i]['工号'],login_name:excelData[i]['邮箱'],real_name:excelData[i]['姓名'],password:'123456',mail:excelData[i]['邮箱'],phone_number:excelData[i]['手机号']})}//数据处理结束调用sql语句,并且反回前台
});
这里引入了connect-multiparty模块专门用来解析文件,然后使用xlsx模块,读取excel文件,最后正常写入数据库就好