Excel 文件导入导出

文件导入

首先封装一个类似的组件,首先需要注意的是,类似功能,vue-element-admin已经提供了,我们只需要改造即可 代码地址

类似功能性的组件,我们只需要会使用和封装即可

安装xlsx插件

excel导入功能需要使用npm包xlsx,所以需要安装xlsx插件

$ npm i xlsx
复制代码

注册全局组件

import PageTools from './PageTools'
import UploadExcel from './UploadExcel'
export default {
  install(Vue) { // install(Vue) 就是当前Vue实例,此方法就是直接挂载全局组件
    Vue.component('PageTools', PageTools) // 注册工具栏组件
    Vue.component('UploadExcel', UploadExcel) // 注册导入excel组件
  }
}
复制代码

建立公共导入的页面路由

新建一个公共的导入页面,挂载路由 src/router/index.js

{
    path: '/import',
    component: Layout,
    hidden: true, // 隐藏在左侧菜单中
    children: [{
      path: '', // 二级路由path什么都不写 表示二级默认路由
      component: () => import('@/views/import')
    }]
  },
复制代码

创建import路由组件 src/views/import/index.vue

<template>
  <!-- 公共导入组件 --> 
  <upload-excel :on-success="success" />
</template>
复制代码

样式布局

包含上传文件的基本逻辑

<template>
  <div class="upload-excel">
    <div class="btn-upload">
      <el-button
        :loading="loading"
        size="mini"
        type="primary"
        @click="handleUpload"
      >
        点击上传
      </el-button>
    </div>

    <input
      ref="excel-upload-input"
      class="excel-upload-input"
      type="file"
      accept=".xlsx, .xls"
      @change="handleClick"
    />
    <div
      class="drop"
      @drop="handleDrop"
      @dragover="handleDragover"
      @dragenter="handleDragover"
    >
      <i class="el-icon-upload" />
      <span>将文件拖到此处</span>
    </div>
  </div>
</template>

<script>
import XLSX from 'xlsx'

export default {
  props: {
    beforeUpload: Function, // eslint-disable-line
    onSuccess: Function// eslint-disable-line
  },
  data() {
    return {
      loading: false,
      excelData: {
        header: null,
        results: null
      }
    }
  },
  methods: {
    generateData({ header, results }) {
      this.excelData.header = header
      this.excelData.results = results
      this.onSuccess && this.onSuccess(this.excelData)
    },
    handleDrop(e) {
      e.stopPropagation()
      e.preventDefault()
      if (this.loading) return
      const files = e.dataTransfer.files
      if (files.length !== 1) {
        this.$message.error('Only support uploading one file!')
        return
      }
      const rawFile = files[0] // only use files[0]

      if (!this.isExcel(rawFile)) {
        this.$message.error('Only supports upload .xlsx, .xls, .csv suffix files')
        return false
      }
      this.upload(rawFile)
      e.stopPropagation()
      e.preventDefault()
    },
    handleDragover(e) {
      e.stopPropagation()
      e.preventDefault()
      e.dataTransfer.dropEffect = 'copy'
    },
    handleUpload() {
      this.$refs['excel-upload-input'].click()
    },
    handleClick(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

      if (!this.beforeUpload) {
        this.readerData(rawFile)
        return
      }
      const before = this.beforeUpload(rawFile)
      if (before) {
        this.readerData(rawFile)
      }
    },
    readerData(rawFile) {
      this.loading = true
      return new Promise((resolve, reject) => {
        const reader = new FileReader()
        reader.onload = e => {
          const data = e.target.result
          const workbook = XLSX.read(data, { type: 'array' })
          const firstSheetName = workbook.SheetNames[0]
          const worksheet = workbook.Sheets[firstSheetName]
          const header = this.getHeaderRow(worksheet)
          const results = XLSX.utils.sheet_to_json(worksheet)

          this.generateData({ header, results })
          this.loading = false
          resolve()
        }
        reader.readAsArrayBuffer(rawFile)
      })
    },
    getHeaderRow(sheet) {
      const headers = []
      const range = XLSX.utils.decode_range(sheet['!ref'])
      let C
      const R = range.s.r
      /* start in the first row */
      for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */
        const cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })]
        /* find the cell in the first row */
        let hdr = 'UNKNOWN ' + C // <-- replace with your desired default
        if (cell && cell.t) hdr = XLSX.utils.format_cell(cell)
        headers.push(hdr)
      }
      return headers
    },
    isExcel(file) {
      return /\.(xlsx|xls|csv)$/.test(file.name)
    }
  }
}
</script>

<style scoped lang="scss">
.upload-excel {
  display: flex;
  justify-content: center;
  margin-top: 100px;
  .excel-upload-input {
    display: none;
    z-index: -9999;
  }
  .btn-upload,
  .drop {
    border: 1px dashed #bbb;
    width: 350px;
    height: 160px;
    text-align: center;
    line-height: 160px;
  }
  .drop {
    line-height: 80px;
    color: #bbb;
    i {
      font-size: 60px;
      display: block;
    }
  }
}
</style>
复制代码

总页面逻辑代码

<template>
  <!-- 公共导入组件 -->
  <upload-excel :on-success="success" />
</template>

<script>
import { importEmployee } from '@/api/employees'
export default {
  // 组件名称
  name: '',
  // 组件参数 接收来自父组件的数据
  props: {},
  // 局部注册的组件
  components: {},
  // 组件状态值
  data() {
    return {
      //   type: this.$route.query.type
    }
  },
  // 计算属性
  computed: {},
  // 侦听器
  watch: {},
  // 组件方法
  methods: {
    async success({ header, results }) {
      const userRelations = {
        '入职日期': 'timeOfEntry',
        '手机号': 'mobile',
        '姓名': 'username',
        '转正日期': 'correctionTime',
        '工号': 'workNumber'
      }
      const arr = []
      var newArr = results.map(item => {
        var userInfo = {}
        
        Object.keys(item).forEach(key => {
          if (userRelations[key] === 'timeOfEntry' || userRelations[key] === 'correctionTimee') {
            userInfo[userRelations[key]] = new Date(this.formatDate(item[key]), '/')
          } else {
            userInfo[userRelations[key]] = item[key]
          }

        })
        return userInfo
      })
      await importEmployee(newArr)
      this.$message.success('导入excel成功')
      this.$router.back()
    },
    formatDate(numb, format) {
      const time = new Date((numb - 1) * 24 * 3600000 + 1)
      time.setYear(time.getFullYear() - 70)
      const year = time.getFullYear() + ''
      const month = time.getMonth() + 1 + ''
      const date = time.getDate() - 1 + ''
      if (format && format.length === 1) {
        return year + format + month + format + date
      }
      return year + (month < 10 ? '0' + month : month) + (date < 10 ? '0' + date : date)
    }
  },
  // 以下是生命周期钩子   注:没用到的钩子请自行删除
  /**
  * 组件实例创建完成,属性已绑定,但DOM还未生成,$ el属性还不存在
  */
  created() {
  },
  /**
  * el 被新创建的 vm.$ el 替换,并挂载到实例上去之后调用该钩子。
  * 如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$ el 也在文档内。
  */
  mounted() {
  },
}
</script> 

<style scoped lang="less">
</style>
复制代码

文件导出

安装excel所需依赖和按需加载

由于 Export2Excel不仅依赖js-xlsx还依赖file-saver和script-loader。

所以你先需要安装如下命令:

npm install xlsx file-saver -S
npm install script-loader -S -D
复制代码

由于js-xlsx体积还是很大的,导出功能也不是一个非常常用的功能,所以使用的时候建议使用懒加载。

import('@/vendor/Export2Excel').then(excel => {
  excel.export_json_to_excel({
    header: tHeader, //表头 必填
    data, //具体数据 必填
    filename: 'excel-list', //非必填
    autoWidth: true, //非必填
    bookType: 'xlsx' //非必填
  })
})
复制代码

导出插件

两个文件 顾名思义,一个导出到excel 一个导出到压缩包

wwr.lanzoui.com/b02c8alji
密码:hqwm

Excel导出插件 密码:hqwm

1.导入一个方法组件

import { export_json_to_excel } from ‘@/vendor/Export2Excel’

导出文件代码_(未进行时间格式化)

    exprotData() {
      const headers = {
        '姓名': 'username',
        '手机号': 'mobile',
        '入职日期': 'timeOfEntry',
        '聘用形式': 'formOfEmployment',
        '转正日期': 'correctionTime',
        '工号': 'workNumber',
        '部门': 'departmentName'
      }
      import('@/vendor/Export2Excel').then(async excel => {
        const { rows } = await getEmployeeList({
          page: 1,
          size: this.page.total // 直接获取一页所有数据,total是数据总数
        })
        const data = this.formatJson(headers, rows)
        export_json_to_excel({
          header: Object.keys(headers), // 直接赋值上面的属性名
          data,
          filename: '员工工资表'
        })
      })
    },

     formatJson(headers, rows) {
      // 传参表头名字headers 和获取的所有数据 rows 进行数据的一一对应
      return rows.map(item => { // map遍历数组 item就是每个对象,里面有表格的每一行的数据 {name:'李四',age:18}
        //  Object.keys(headers)就是循环 表头名字对象的方法 并返回一个数组 
        return Object.keys(headers).map(key => {
          // item是每个数据,下面这个item[headers[key]] 就是拿到每个item数据里面的英文名的值
          return item[headers[key]]   // headers[key]此时就是headers对象里面的每个属性值 username
        })
      })
      // 一行代码搞定 return rows.map(item => Object.keys(headers).map(key =>item[headers[key]]))
    }
复制代码

完美代码 (时间格式化+聘用形式枚举格式化)

导出代码_已处理时间格式化

时间过滤器插件 枚举文件

导入时间格式化过滤器和枚举文件(格式化聘用形式-正式非正式)

插件 wwr.lanzoui.com/b02c8arni 密码:time

枚举文件 wwr.lanzoui.com/b02c8at5c 密码:gggg

import { formatDate } from '@/filters' // 引入时间格式化插件
formatDate(item[headers[key]])就是格式化选择英文名字的数据,也就是时间
import EmployeeEnum from '@/api/constant/employees'
导入枚举数据
复制代码
 exprotData() {
      const headers = {
        '姓名': 'username',
        '手机号': 'mobile',
        '入职日期': 'timeOfEntry',
        '聘用形式': 'formOfEmployment',
        '转正日期': 'correctionTime',
        '工号': 'workNumber',
        '部门': 'departmentName'
      }
      import('@/vendor/Export2Excel').then(async excel => {
        const { rows } = await getEmployeeList({
          page: 1,
          size: this.page.total // 直接获取一页所有数据,total是数据总数
        })
        const data = this.formatJson(headers, rows)
        export_json_to_excel({
          header: Object.keys(headers), // 直接赋值上面的属性名
          data,
          filename: '员工工资表'
        })
      })
    },
    formatJson(headers, rows) {
      // 传参表头名字headers 和获取的所有数据 rows 进行数据的一一对应
      return rows.map(item => { // map遍历数组 item就是每个对象,里面有表格的每一行的数据 {name:'李四',age:18}
        //  Object.keys(headers)就是循环 表头名字对象的方法 并返回一个数组 
        return Object.keys(headers).map(key => {
          if (headers[key] === 'timeOfEntry' || headers[key] === 'correctionTime') {
            return formatDate(item[headers[key]]) // 返回格式化之前的时间
          } else if (headers[key] === 'formOfEmployment') {
            var en = EmployeeEnum.hireType.find(obj => obj.id === item[headers[key]])
            return en ? en.value : '未知'
          }
          // item是每个数据,下面这个item[headers[key]] 就是拿到每个item数据里面的英文名的值
          return item[headers[key]]   // headers[key]此时就是headers对象里面的每个属性值 username
        })
      })
      // 一行代码搞定 return rows.map(item => Object.keys(headers).map(key =>item[headers[key]]))
    }
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享