Electron+Vue+ElementUI excel文件合并
一、需求
excel表格式如上,前面14行的数据不要,最后一行不要,只要中间标题以及内容,多个表合并成一个excel:如下
二、效果
上部分:上次ecxel文件,上传完之后,点击合并按钮开始合并
下部分:打印日志,包括:错误日志,成功日志
桌面就会出现一个以当前日期命名的excel合并文件。
当然,如果你传入的格式不对,则会提示你格式错误,如下:
三、代码
目录结构:
该项目的主要难点就是一个,如何前后端通信,
1)在background.js 使用ipcMain监听通信
- 在mupload.vue组件中使用electron的ipcRenderer,发送通信
如下:
<template>
<div
class="mupload"
v-loading="loading.staus"
element-loading-text="拼命加载中"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.8)"
>
<el-upload
action="#"
class="upload-component"
drag
multiple
:file-list="fileList"
:auto-upload="false"
:on-remove="handleRemove"
:on-change="handleChange"
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">
将文件拖到此处,或<em>点击此处</em>
</div>
</el-upload>
<el-button
class="mupload-button"
style="margin-left: 10px"
size="small"
type="success"
@click="submitUpload"
>点击合并</el-button
>
</div>
</template>
<script>
// import { Upload } from "element-ui";
const { ipcRenderer } = require("electron");
import log from "electron-log";
// import { mapState } from "vuex";
export default {
components: {
// Upload,
},
data() {
return {
fileList: [],
// loading: false
};
},
methods: {
handleChange(file, fileList) {
this.fileList = fileList;
},
handleRemove(file, fileList) {
this.fileList = fileList;
},
submitUpload(e) {
let fileList = this.fileList;
if (fileList.length == 0) {
this.$message.error("请上传文件");
return;
}
fileList = fileList.map((v) => v.raw.path);
this.$store.dispatch("changeLoading", {
staus: true,
clean: false,
});
log.info(`文件导入中... <br />`);
ipcRenderer.send("uploadChooseExcel", fileList);
},
downloadFile() {
// 下载合并文件
}
},
computed: {
...Vuex.mapState(["loading",'loading']),
},
watch: {
'loading.clean'(newVal,oldVal) {
if(newVal) {
this.fileList = []
}
}
}
};
</script>
<style>
.mupload {
display: flex;
justify-content: center;
}
.el-upload-list {
height: 200px;
overflow-y: auto;
}
.mupload-button {
height: 30px;
margin-top: 70px !important;
}
</style>
上面的文件中使用:ipcRenderer.send(“uploadChooseExcel”, fileList); 发送文件列表。
import { ipcMain } from "electron";
const fs = require('fs');
const path = require('path');
const xlsx = require('node-xlsx');
import log from 'electron-log';
import { formatDate } from '@/utils';
var lists = [];
var oPath = __dirname.slice(0, __dirname.indexOf('dist_electron'))
log.transports.file.resolvePath = () => path.resolve(`${oPath}/log/${formatDate(new Date(), 'yyyy-MM-dd')}.log`);
log.transports.console.level = 'silly';
export const getExcel = (webContents) => {
ipcMain.on("uploadChooseExcel", function (event, arg) {
fileDisplay(arg)
});
};
const fileDisplay = files => {
log.info(`读取配置中...<br />`)
files.forEach((filename, index) => {
log.info(`读取文件${filename}<br />`)
fs.stat(filename, (eror, stats) => {
if (eror) return log.error(`Error:(spec)${eror} <br />`);
const isFile = stats.isFile();
const isDir = stats.isDirectory();
if (isFile) {
if (filename.includes('.xls') || filename.includes('xlsx')) {
var data = xlsx.parse(filename);
var list1 = data[0].data
let excelHeader = [
'保单号',
'批单号',
'类别',
'期次',
'险种',
'客户',
'业务员',
'个团',
'新旧车',
'合作网点',
'含税保费',
'净保费',
'出单时间',
'保费收入',
'原比例%',
'本次比例%',
'本次手续费/经纪费(人民币)',
'手续费增值税',
'合计支付含增值税金额'
]
let configPath = path.join(oPath, `/config.txt`)
fs.exists(configPath, (exists) => {
if (!exists) {
var filePath = path.join(oPath, `/config.txt`);
fs.writeFileSync(filePath, excelHeader);
createMerge(list1, excelHeader, index, files, filename)
return
}
fs.readFile(configPath, (err, data) => {
var string = data.toString()
var arr = [];
if (string) {
arr = string.split(',').map(v => v.trim());
}
createMerge(list1, arr.length == 0 ? excelHeader : arr, index, files, filename)
})
})
} else {
log.error(`${filename}:不是excel文件 <br />`)
}
}
if (isDir) fileDisplay(filename);
})
});
}
function getNowMonths() {
let timeOne = new Date();
let year = timeOne.getFullYear();
let month = timeOne.getMonth() + 1;
let day = timeOne.getDate();
month = month < 10 ? "0" + month : month;
day = day < 10 ? "0" + day : day;
const NOW_MONTHS_AGO = `${year}-${month}-${day}`;
return NOW_MONTHS_AGO;
}
function createMerge(list, excelHeader, index, files, filename) {
let sum = 0, isTrue = false, lineNum = 0;
for (let i = 0; i < list.length; i++) {
if (isTrue) break
if (excelHeader.length != list[i].length) {
continue;
}
for (let j = 0; j < list[i].length; j++) {
if (excelHeader[j] == list[i][j]) {
lineNum = i
isTrue = true
sum++;
}
}
}
if (sum != excelHeader.length) {
return log.error(`${filename}:表头与规定的格式不匹配 <br />`);
}
var tempList = list.slice(lineNum + 1, list.length - 1);
lists = lists.concat(tempList)
if (index == files.length - 1) {
try {
lists.unshift(excelHeader)
const options = {}
var desktop = `${require('os').homedir()}\\Desktop`
var buffer = xlsx.build([{ name: 'sheet1', data: lists }], options);
var date = getNowMonths()
var filePath = path.join(desktop, `/${date}.xlsx`);
fs.writeFileSync(filePath, buffer, { 'flag': 'w' });
log.info(`合并文件成功,文件储存在桌面,路径为:${require('os').homedir()}\\Desktop\\${date}.xlsx <br />`)
} catch (err) {
if (err.errno == -4082) {
log.error(`上传失败,上一个合并的文件正在打开,请关闭之后再重新上传待合并文件 <br />`)
}
}
lists = [];
isTrue = false
}
}
大概主要的就是这些,其实还是有很多优化的,后续会优化一下。
四、后续
噢,对了,还有一个设置表头的功能
log.error(上传失败,上一个合并的文件正在打开,请关闭之后再重新上传待合并文件 <br /> ) } } lists = []; isTrue = false } }
大概主要的就是这些,其实还是有很多优化的,后续会优化一下。
#### 四、后续
噢,对了,还有一个设置表头的功能
[外链图片转存中...(img-dRD6tXcl-1662538336371)]
[外链图片转存中...(img-yOUqn6PP-1662538336371)]
该功能就是excel默认表头,可以手动设置,一次设置,后面就按照设置的来,其实就是设置了一个txt文件,从该文件进行读取而已。
|