安装
npm i xlsx --D
引入
import XLSX from 'xlsx'
导入功能
commonjs(公共函数)
/*** 1、 String.fromCharCode(65 + i) + 1 : A1,B1,C1....* 2、 String.fromCharCode(65 + j) + (i + 2) A2,B2,C2...* A3,B3,C3...* 测试:* const headers = [{ key: 'date', title: '日期' }, { key: 'name', title: '名称' }]* const data = [{ date: '2019-05-31', name: 'megen.huang' }, { date: '2019-06-20', name: '小明' }]* console.log(exportJsonToExcel(headers, data))* 使用xlsx插件将json数据导出到Excel中----针对表格数据* @param {Array} headers 表头:[{key: 'date', title: '日期'}, {key: 'name', title: '名称'}]* @param {Array} data 表体数据:[{date: '2019-05-31', name: 'megen.huang'}, {date: '2019-06-20', name: '小明'}]* @param {String} fileName 导出的文件名称 :'export.xlsx'*/export function exportJsonToExcel (headers = [], data = [], fileName = 'export.xlsx') {// 先处理数据data = handleCSV(data)const _headers = headers.map((item, i) => Object.assign({}, { key: item.key, title: item.title, position: String.fromCharCode(65 + i) + 1 })).reduce((prev, next) => Object.assign({}, prev, { [next.position]: { key: next.key, v: next.title }}), {})const _data = data// 二维数组.map((item, i) => headers.map((key, j) => Object.assign({}, { content: item[key.key], position: String.fromCharCode(65 + j) + (i + 2) })))// 二维转一维.reduce((prev, next) => prev.concat(next))// 转成worksheet需要的数据结构.reduce((prev, next) => Object.assign({}, prev, { [next.position]: { v: next.content }}), {})// 合并 headers 和 dataconst output = Object.assign({}, _headers, _data)console.log('output', output)// 获取所有单元格的位置const outputPos = Object.keys(output)// 计算出范围 ,["A1",..., "H2"]const ref = `${outputPos[0]}:${outputPos[outputPos.length - 1]}`console.log('ref', ref)// 构建 workbook 对象const wb = {SheetNames: ['mySheet'],Sheets: {mySheet: Object.assign({},output,{'!ref': ref,'!cols': headers.map(item => ({ wpx: 120 }))// width in screen pixels})}}// 导出 ExcelXLSX.writeFile(wb, fileName)}// 防止CSV注入处理export function handleCSV (arr) {const reg = new RegExp('(^=|^-)')if (Array.isArray(arr) && arr.length > 0) {for (const item of arr) {Object.keys(item).forEach(key => {if (item[key] && reg.test(item[key])) {item[key] = '\'' + item[key]}})}}return arr}/*** 日期格式转换* `第一个参数为传入的以毫秒为单位的时间戳,第二个参数为格式,具体说明见代码;* 不传参则返回当前日期,则为“'yyyy年MM月dd日'”格式显示.`* @param {object} _date 日期* @param {string} _format 转换后的日期格式*/export function FormatDate (_date, _format) {if (_format && !_date) {return ''}var date = _date || new Date()var format = _format || 'yyyy/MM/dd'date = new Date(_date)var map = {M: date.getMonth() + 1, // 月份d: date.getDate(), // 日h: date.getHours(), // 小时m: date.getMinutes(), // 分s: date.getSeconds(), // 秒q: Math.floor((date.getMonth() + 3) / 3), // 季度S: date.getMilliseconds() // 毫秒}format = format.replace(/([yMdhmsqS])+/g, function (all, t) {var v = map[t]if (v !== undefined) {if (all.length > 1) {v = '0' + vv = v.substr(v.length - 2)}return v} else if (t === 'y') {return (date.getFullYear() + '').substr(4 - all.length)}return all})return format}
html
<template><div><!-- 这里使用了ElementUI的el-upload组件 --><el-uploadref="upload"class="upload-demo":action="''":multiple="false":show-file-list="false":limit="1":before-upload="beforeAvatarUpload":file-list="fileList">从Excel导入</el-upload></div></template>
js ```javascript import { exportJsonToExcel, deepClone, FormatDate } from ‘@/utils’ data(){ return { outJson: [], // 最后要发送给后台的json数据 // 导入表头必填字段
excelHeaderRequired: ['序号(必填)','子任务名称(必填)','子任务内容(必填)','执行人(必填)','预计开始时间(必填)','预计完成时间(必填)','紧急程度(必填)'],exportHeader: Object.freeze([{key: 'index', title: '序号' }, {key: 'workItem', title: '事项名称' }, {key: 'taskName', title: '子任务名称' }, {key: 'remark', title: '子任务内容' }, {key: 'executor', title: '执行人' }, {key: 'planStarttime', title: '预计开始时间' }, {key: 'planEndtime', title: '预计完成时间' }, {key: 'actualStarttime', title: '实际开始时间' }, {key: 'actualEndtime', title: '实际完成时间' }, {key: 'tagList', title: '标签' }, {key: 'orderNum', title: '紧急程度' }, {key: 'taskProgress', title: '工作进展' }]),order: Object.freeze({'紧急': 0,'一般': 1,'重要紧急': 2}),orderObj: Object.freeze({0: '紧急',1: '一般',2: '重要紧急'}),
}
}
methods:{
beforeAvatarUpload (file) {
if (!file) {
// 没有文件
return false
} else if (!/.(xls|xlsx)$/.test(file.name.toLowerCase())) {
// 格式根据自己需求定义
this.$message.error(‘上传格式不正确,请上传xls或者xlsx格式’)
return false
}
this.handleExcel(file)// 处理数据
this.$refs.upload.clearFiles()
},
handleExcel (file) {
// 表格导入
const files = file // excel文件
const fileReader = new FileReader()
fileReader.onload = ev => {
try {
const data = ev.target.result
const workbook = XLSX.read(data, {
type: ‘binary’,
cellDates: true
})
const wsname = workbook.SheetNames[0]// 取第一张表
const tempArr = XLSX.utils.sheet_to_json(workbook.Sheets[wsname]) // 生成json表格内容,如果某个字段列没有填,则解析出来就会没有该字段
console.log(‘解析出来的数据’, tempArr)
this.outJson = []
let isValidPass = true
for (const item of tempArr) {
console.log(‘几次’, item)
const obj = {}
const bool = this.validFieldRequired(item)
if (!bool) { // 如果不是true,说明有些必填字段没有填
isValidPass = false
break
}
const isValidSuccess = this.handleoutJson(item, obj)
if (!isValidSuccess) {
isValidPass = false
break
} else {
this.outJson.push(this.successObj)// this.outJson放的就是需要返回给后台的
}
}
if (isValidPass) {
// 如果this.outJson有数据说明已经全部校验成功可以传给后台了
batchSaveTask(this.outJson).then(res => {
this.$message.success(‘导入成功’)
this.init()
}).catch(e => {})
}
} catch (e) {
console.log(e)
return false
}
}
fileReader.readAsBinaryString(files)
},
// 校验必填字段的值是否存在
validFieldRequired (item) {
let boolean = true
for (const el of this.excelHeaderRequired) {
if (!Object.keys(item).includes(el)) {
this.$message.error(${el})
boolean = false
break
}
}
return boolean
},
// 将解析的json转为后台需要的字段
handleoutJson (item, obj) {
// if (item[‘事项名称(必填)’]) {
// }
this.successObj = {}
obj[‘matterId’] = this.$route.query.id
obj[‘taskName’] = item[‘子任务名称(必填)’].trim()
obj[‘remark’] = item[‘子任务内容(必填)’].trim()
// 人员的需要传三个参数
obj[‘executorAccount’] = item[‘执行人(必填)’].trim()
obj[‘executorId’] = ‘’
obj[‘executor’] = ‘’
if (!DataType(item[‘预计开始时间(必填)’], ‘date’)) {
this.$message.error(‘预计开始时间格式不符合’)
return false
}
if (!DataType(item[‘预计完成时间(必填)’], ‘date’)) {
this.$message.error(‘预计结束时间格式不符合’)
return false
}
if (item[‘预计开始时间(必填)’] > item[‘预计完成时间(必填)’]) {
this.$message.error(‘预计开始时间不能晚于预计结束时间’)
return false
} else {
// 需要对时间进行处理
obj[‘planStarttime’] = FormatDate(item[‘预计开始时间(必填)’], ‘yyyy-MM-dd hh:mm:ss’)
// 需要对时间进行处理
obj[‘planEndtime’] = FormatDate(item[‘预计完成时间(必填)’], ‘yyyy-MM-dd hh:mm:ss’)
}
console.log(item['预计开始时间(必填)'], item['预计完成时间(必填)'])if (item['紧急程度(必填)'] && Object.keys(this.order).includes(item['紧急程度(必填)'].trim())) {// 需要把汉字转成key传过去obj['orderNum'] = this.order[item['紧急程度(必填)'].trim()]} else {this.$message.error('任务等级不存在')return false}this.successObj = { ...obj }return true},
}
<a name="zIE4Q"></a>## 导出功能- js```javascript// 导出exportMatter (type, tag) {if (type === '1' && this.completeList.length > 0) {// 这里深copy防止污染原数据const arr = deepClone(this.completeList)// 需要处理数据const sourceData = arr.map((item, index) => {item['index'] = index + 1item['tagList'] = this.tagsText(item.tagList)item['orderNum'] = this.orderObj[item.orderNum]item['planStarttime'] = item.planStarttime ? FormatDate(item.planStarttime, 'yyyy/MM/dd hh:mm:ss') : ''item['planEndtime'] = item.planEndtime ? FormatDate(item.planEndtime, 'yyyy/MM/dd hh:mm:ss') : ''item['actualStarttime'] = item.actualStarttime ? FormatDate(item.actualStarttime, 'yyyy/MM/dd hh:mm:ss') : ''item['actualEndtime'] = item.planStarttime ? FormatDate(item.actualEndtime, 'yyyy/MM/dd hh:mm:ss') : ''Object.keys(item).forEach(key => {item[key] = item[key] === null ? '' : item[key]})return item})exportJsonToExcel(this.exportHeader, sourceData, 'exportSubTask.xlsx')} else {this.$message.error('没有可导出的已完成任务')}},
