前言
最近的项目中需求需要将表格数据导入导出,基于vue-element-admin有这个组件功能外,我们还要做一些简单的数据格式化处理
分析
表格中除了简单的添加功能,有时管理一次性需要导入导出多份数据,这个样子一次次添加是很麻烦的,需求就产生了
- 实现 1,后端处理:前端只需要将excel数据上传,后端接受业务做数据处理
2,前端处理:
注意:这个 Excel 文件不是用户想传什么就传什么的, Excel 文件格式、字段是提前定义好的,用户需要按照格式、字段填充数据,进行上传
前端需要做的就是数据格式化好再上传或者接收,Excel 的导入导出都是依赖于js-xlsx插件来实现的,在 js-xlsx的基础上又封装了Export2Excel.js来方便导出数据
- vue-element-admin 先分析下人家的源码
<upload-excel-component :on-success="handleSuccess" :before-upload="beforeUpload" />
这个是人家封装好的组件,其中两个钩子是on-success:上传成功,在里面执行上传成功以后的逻辑处理,before-upload:上传之前进行验证、文件格式、文件的大小等
用户点击按钮后,触发的实际是**input隐藏域**的click事件,当上传文件后,触发隐藏域的change事件后
handleClick(e) {
console.log(e)
// 通过事件对象获取到上传的文件信息
const files = e.target.files
// 获取到上传的文件
const rawFile = files[0] // only use files[0]
// 开始判断是否选择了文件
if (!rawFile) return
this.upload(rawFile)
}
通过事件对象获取到上传的文件,这里还不能直接做数据处理,需要嵌套调用来判断上传的文件符不符合规范,比如文件大小,格式等
upload(rawFile) {
this.$refs['excel-upload-input'].value = null // fix can't select the same excel
// beforeUpload:是父级传递方法,进行上传之前逻辑的处理
// 例如:判断文件格式是否正确、判断文件大小
if (!this.beforeUpload) {
this.readerData(rawFile)
return
}
// 父级开始进行逻辑处理,返回 true 或者 false
const before = this.beforeUpload(rawFile)
// 如果返回 true,说明逻辑通过
if (before) {
this.readerData(rawFile)
}
}
接着通过xlsx插件的方法读取文件处理成我们需要的表头和表格数据体
generateData({ header, results }) {
// 接收 表头 和 具体的数据,赋值给 data 中的状态
this.excelData.header = header
this.excelData.results = results
// 开始判断父级是否传递了 onSuccess 事件,如果父级传递了事件,开始将 表头 和 具体的数据 传递给父级
this.onSuccess && this.onSuccess(this.excelData)
}
以上是在官网上粘贴,有兴趣的可以去官网阅读gitee.com/julywind/vu…
枚举数据处理
- 导入 此处就以自己的项目为例了,通过插件处理后的数据如下
表头:['姓名', '手机号', '入职日期', '转正日期', '工号', '部门']
数据体:
[
{入职时间:45166,姓名:'阿克尚',工号:'1001',手机号:'13333333333',转正日期:46123,部门:'艾欧尼亚'}
...
]
// 格式化results
function transExcel(results) {
// 定义原始枚举对象
const userRelations = {
'入职日期': 'timeOfEntry',
'手机号': 'mobile',
'姓名': 'username',
'转正日期': 'correctionTime',
'工号': 'workNumber',
'部门': 'departmentName',
'聘用形式': 'formOfEmployment'
}
return results.map(item => {
const obj = {}
// 得到原数组中每一项对象的key组成的数组
const transKey = Object.keys(item)
// 遍历数组枚举得到obj的key
transKey.forEach(key => {
const objKey = userRelations[key]
// 判断值是否为转正和入职时间转换为时间戳
if (objKey === 'timeOfEntry' || objKey === 'correctionTime') {
obj[objKey] = new Date(formatExcelDate(item[key])) // 这里是表格事件转时间戳的一个方法
} else {
// 当前每一项的值赋值给obj的值
obj[objKey] = item[key]
}
})
return obj
})
}
` 返回符合后端格式数据
- 导出
导出除了
xlsx还基于Export2Excel.js
import('@/vendor/Export2Excel').then(excel => {
excel.export_json_to_excel({
header: tHeader, //表头 必填
data, //具体数据 必填
filename: 'excel-list', //非必填
autoWidth: true, //非必填
bookType: 'xlsx' //非必填
})
})
function transData(data) {
// 准备枚举的对象
const map = {
'id': '编号',
'password': '密码',
'mobile': '手机号',
'username': '姓名',
'timeOfEntry': '入职日期',
'formOfEmployment': '聘用形式',
'correctionTime': '转正日期',
'workNumber': '工号',
'departmentName': '部门',
'staffPhoto': '头像地址'
}
const headerKey = Object.keys(data[0])
const headers = headerKey.map(item => {
return map[item]
})
const results = data.map(item => {
return Object.values(item)
})
return { headers, results }
}
上面提到的时间处理这里补充下 1、excel的日期是以1900-1-0开始计算的 2、js的Date是以 1970-1-1 08:00:00 开始的
function formatExcelDate(numb, format = '/') {
const time = new Date((numb - 25567) * 24 * 3600000 - 5 * 60 * 1000 - 43 * 1000 - 24 * 3600000 - 8 * 3600000)
time.setYear(time.getFullYear())
const year = time.getFullYear() + ''
const month = time.getMonth() + 1 + ''
const date = time.getDate() + ''
if (format && format.length === 1) {
return year + format + month + format + date
}
return year + (month < 10 ? '0' + month : month) + (date < 10 ? '0' + date : date)
}
通过枚举一一对应的关系,我们顺利的数据转换,方便调用API
结语
写的不好,有错误的地方烦请各位大佬多多指教,感恩家人感恩🙏 🚩祝各位一路顺风,顶峰相见