xlsx

安装

  1. npm i xlsx --D

引入

  1. import XLSX from 'xlsx'

导入功能

  • commonjs(公共函数)

    1. /**
    2. * 1、 String.fromCharCode(65 + i) + 1 : A1,B1,C1....
    3. * 2、 String.fromCharCode(65 + j) + (i + 2) A2,B2,C2...
    4. * A3,B3,C3...
    5. * 测试:
    6. * const headers = [{ key: 'date', title: '日期' }, { key: 'name', title: '名称' }]
    7. * const data = [{ date: '2019-05-31', name: 'megen.huang' }, { date: '2019-06-20', name: '小明' }]
    8. * console.log(exportJsonToExcel(headers, data))
    9. * 使用xlsx插件将json数据导出到Excel中----针对表格数据
    10. * @param {Array} headers 表头:[{key: 'date', title: '日期'}, {key: 'name', title: '名称'}]
    11. * @param {Array} data 表体数据:[{date: '2019-05-31', name: 'megen.huang'}, {date: '2019-06-20', name: '小明'}]
    12. * @param {String} fileName 导出的文件名称 :'export.xlsx'
    13. */
    14. export function exportJsonToExcel (headers = [], data = [], fileName = 'export.xlsx') {
    15. // 先处理数据
    16. data = handleCSV(data)
    17. const _headers = headers
    18. .map((item, i) => Object.assign({}, { key: item.key, title: item.title, position: String.fromCharCode(65 + i) + 1 }))
    19. .reduce((prev, next) => Object.assign({}, prev, { [next.position]: { key: next.key, v: next.title }}), {})
    20. const _data = data
    21. // 二维数组
    22. .map((item, i) => headers.map((key, j) => Object.assign({}, { content: item[key.key], position: String.fromCharCode(65 + j) + (i + 2) })))
    23. // 二维转一维
    24. .reduce((prev, next) => prev.concat(next))
    25. // 转成worksheet需要的数据结构
    26. .reduce((prev, next) => Object.assign({}, prev, { [next.position]: { v: next.content }}), {})
    27. // 合并 headers 和 data
    28. const output = Object.assign({}, _headers, _data)
    29. console.log('output', output)
    30. // 获取所有单元格的位置
    31. const outputPos = Object.keys(output)
    32. // 计算出范围 ,["A1",..., "H2"]
    33. const ref = `${outputPos[0]}:${outputPos[outputPos.length - 1]}`
    34. console.log('ref', ref)
    35. // 构建 workbook 对象
    36. const wb = {
    37. SheetNames: ['mySheet'],
    38. Sheets: {
    39. mySheet: Object.assign(
    40. {},
    41. output,
    42. {
    43. '!ref': ref,
    44. '!cols': headers.map(item => ({ wpx: 120 }))// width in screen pixels
    45. }
    46. )
    47. }
    48. }
    49. // 导出 Excel
    50. XLSX.writeFile(wb, fileName)
    51. }
    52. // 防止CSV注入处理
    53. export function handleCSV (arr) {
    54. const reg = new RegExp('(^=|^-)')
    55. if (Array.isArray(arr) && arr.length > 0) {
    56. for (const item of arr) {
    57. Object.keys(item).forEach(key => {
    58. if (item[key] && reg.test(item[key])) {
    59. item[key] = '\'' + item[key]
    60. }
    61. })
    62. }
    63. }
    64. return arr
    65. }
    66. /**
    67. * 日期格式转换
    68. * `第一个参数为传入的以毫秒为单位的时间戳,第二个参数为格式,具体说明见代码;
    69. * 不传参则返回当前日期,则为“'yyyy年MM月dd日'”格式显示.`
    70. * @param {object} _date 日期
    71. * @param {string} _format 转换后的日期格式
    72. */
    73. export function FormatDate (_date, _format) {
    74. if (_format && !_date) {
    75. return ''
    76. }
    77. var date = _date || new Date()
    78. var format = _format || 'yyyy/MM/dd'
    79. date = new Date(_date)
    80. var map = {
    81. M: date.getMonth() + 1, // 月份
    82. d: date.getDate(), // 日
    83. h: date.getHours(), // 小时
    84. m: date.getMinutes(), // 分
    85. s: date.getSeconds(), // 秒
    86. q: Math.floor((date.getMonth() + 3) / 3), // 季度
    87. S: date.getMilliseconds() // 毫秒
    88. }
    89. format = format.replace(/([yMdhmsqS])+/g, function (all, t) {
    90. var v = map[t]
    91. if (v !== undefined) {
    92. if (all.length > 1) {
    93. v = '0' + v
    94. v = v.substr(v.length - 2)
    95. }
    96. return v
    97. } else if (t === 'y') {
    98. return (date.getFullYear() + '').substr(4 - all.length)
    99. }
    100. return all
    101. })
    102. return format
    103. }
  • html

    1. <template>
    2. <div>
    3. <!-- 这里使用了ElementUIel-upload组件 -->
    4. <el-upload
    5. ref="upload"
    6. class="upload-demo"
    7. :action="''"
    8. :multiple="false"
    9. :show-file-list="false"
    10. :limit="1"
    11. :before-upload="beforeAvatarUpload"
    12. :file-list="fileList"
    13. >从Excel导入
    14. </el-upload>
    15. </div>
    16. </template>
  • js ```javascript import { exportJsonToExcel, deepClone, FormatDate } from ‘@/utils’ data(){ return { outJson: [], // 最后要发送给后台的json数据 // 导入表头必填字段

    1. excelHeaderRequired: [
    2. '序号(必填)',
    3. '子任务名称(必填)',
    4. '子任务内容(必填)',
    5. '执行人(必填)',
    6. '预计开始时间(必填)',
    7. '预计完成时间(必填)',
    8. '紧急程度(必填)'
    9. ],
    10. exportHeader: Object.freeze([{
    11. key: 'index', title: '序号' }, {
    12. key: 'workItem', title: '事项名称' }, {
    13. key: 'taskName', title: '子任务名称' }, {
    14. key: 'remark', title: '子任务内容' }, {
    15. key: 'executor', title: '执行人' }, {
    16. key: 'planStarttime', title: '预计开始时间' }, {
    17. key: 'planEndtime', title: '预计完成时间' }, {
    18. key: 'actualStarttime', title: '实际开始时间' }, {
    19. key: 'actualEndtime', title: '实际完成时间' }, {
    20. key: 'tagList', title: '标签' }, {
    21. key: 'orderNum', title: '紧急程度' }, {
    22. key: 'taskProgress', title: '工作进展' }
    23. ]),
    24. order: Object.freeze({
    25. '紧急': 0,
    26. '一般': 1,
    27. '重要紧急': 2
    28. }),
    29. orderObj: Object.freeze({
    30. 0: '紧急',
    31. 1: '一般',
    32. 2: '重要紧急'
    33. }),

    }

} 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’) }

  1. console.log(item['预计开始时间(必填)'], item['预计完成时间(必填)'])
  2. if (item['紧急程度(必填)'] && Object.keys(this.order).includes(item['紧急程度(必填)'].trim())) {
  3. // 需要把汉字转成key传过去
  4. obj['orderNum'] = this.order[item['紧急程度(必填)'].trim()]
  5. } else {
  6. this.$message.error('任务等级不存在')
  7. return false
  8. }
  9. this.successObj = { ...obj }
  10. return true
  11. },

}

  1. <a name="zIE4Q"></a>
  2. ## 导出功能
  3. - js
  4. ```javascript
  5. // 导出
  6. exportMatter (type, tag) {
  7. if (type === '1' && this.completeList.length > 0) {
  8. // 这里深copy防止污染原数据
  9. const arr = deepClone(this.completeList)
  10. // 需要处理数据
  11. const sourceData = arr.map((item, index) => {
  12. item['index'] = index + 1
  13. item['tagList'] = this.tagsText(item.tagList)
  14. item['orderNum'] = this.orderObj[item.orderNum]
  15. item['planStarttime'] = item.planStarttime ? FormatDate(item.planStarttime, 'yyyy/MM/dd hh:mm:ss') : ''
  16. item['planEndtime'] = item.planEndtime ? FormatDate(item.planEndtime, 'yyyy/MM/dd hh:mm:ss') : ''
  17. item['actualStarttime'] = item.actualStarttime ? FormatDate(item.actualStarttime, 'yyyy/MM/dd hh:mm:ss') : ''
  18. item['actualEndtime'] = item.planStarttime ? FormatDate(item.actualEndtime, 'yyyy/MM/dd hh:mm:ss') : ''
  19. Object.keys(item).forEach(key => {
  20. item[key] = item[key] === null ? '' : item[key]
  21. })
  22. return item
  23. })
  24. exportJsonToExcel(this.exportHeader, sourceData, 'exportSubTask.xlsx')
  25. } else {
  26. this.$message.error('没有可导出的已完成任务')
  27. }
  28. },