vue-element-admin项目导入和导出的实现


Posted in Vue.js onMay 21, 2021

vue-element-admin导入组件封装

模板和样式

vue-element-admin项目导入和导出的实现

首先封装一个类似的组件,首先需要注意的是,类似功能,vue-element-admin已经提供了,我们只需要改造即可
excel导入功能需要使用npm包xlsx,所以需要安装xlsx插件

npm i xlsx

将vue-element-admin提供的导入功能新建一个组件,位置: src/components/UploadExcel

import CommonTools from './CommonTools'
import UploadExcel from './UploadExcel'
export default {
  install(Vue) {
    Vue.component('CommonTools', CommonTools) // 注册工具栏组件
    Vue.component('UploadExcel', UploadExcel) // 注册导入excel组件
  }
}

修改样式和布局

<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>

创建路由和组件

建立公共导入的页面路由,新建一个公共的导入页面,挂载路由 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>

实现导入

封装导入用户的api接口

export function importUser(data) {
  return request({
    url: 'user/batch',
    method: 'post',
    data
  })
}

获取导入的excel数据, 导入excel接口

async  success({ header, results }) {
      // 如果是导入用户
        const userRelations = {
          '入职日期': 'create_time',
          '手机号': 'mobile',
          '用户名': 'username',
          '密码': 'password',
          '邮箱': 'email',
          '部门':'部门'
        }
        const arr = []
       results.forEach(item => {
          const userInfo = {}
          Object.keys(item).forEach(key => {
            userInfo[userRelations[key]] = item[key]
          })
         arr.push(userInfo) 
        })
        await importUser(arr) // 调用导入接口
        this.$router.back()
    }

为了让这个页面可以服务更多的导入功能,我们可以在页面中用参数来判断,是否是导入用户

data() {
    return {
      type: this.$route.query.type
    }
  },

当excel中有日期格式的时候,实际转化的值为一个数字,我们需要一个方法进行转化

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

导入的手机号不能和之前的存在的手机号重复

逻辑判断

async  success({ header, results }) {
      if (this.type === 'user') {
        const userRelations = {
          '入职日期': 'create_time',
          '手机号': 'mobile',
          '用户名': 'username',
          '密码': 'password',
          '邮箱': 'email',
          '部门':'部门'
        }
        const arr = []
        // 遍历所有的数组
        results.forEach(item => {
        // 需要将每一个条数据里面的中文都换成英文
          const userInfo = {}
          Object.keys(item).forEach(key => {
          // key是当前的中文名 找到对应的英文名
            if (userRelations[key] === 'timeOfEntry' || userRelations[key] === 'correctionTime') {
              userInfo[userRelations[key]] = new Date(this.formatDate(item[key], '/')) // 只有这样, 才能入库
              return
            }
            userInfo[userRelations[key]] = item[key]
          })
          // 最终userInfo变成了全是英文
          arr.push(userInfo)
        })
        await importUser(arr)
        this.$message.success('导入成功')
      }
      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)
    }

用户页面跳转

<el-button type="warning" size="small" @click="$router.push('/import?type=user')">导入</el-button>

用户导出**

日常业务中,我们经常遇到excel导出功能, 怎么使用呢
Excel 的导入导出都是依赖于js-xlsx来实现的。
在 js-xlsx的基础上又封装了Export2Excel.js来方便导出数据。

安装所需依赖

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导出参数的介绍

vue-element-admin提供了导出的功能模块,在课程资源/excel导出目录下,放置到src目录下

vue-element-admin项目导入和导出的实现

excel导出基本的结构

下面代码会用到 Export2Excel.js 模块,所以首先在 src 目录下新建 vendor 目录,其中新建 Export2Excel.js ,输入如下代码

/* eslint-disable */
import { saveAs } from 'file-saver'
import XLSX from 'xlsx'

function generateArray(table) {
  var out = [];
  var rows = table.querySelectorAll('tr');
  var ranges = [];
  for (var R = 0; R < rows.length; ++R) {
    var outRow = [];
    var row = rows[R];
    var columns = row.querySelectorAll('td');
    for (var C = 0; C < columns.length; ++C) {
      var cell = columns[C];
      var colspan = cell.getAttribute('colspan');
      var rowspan = cell.getAttribute('rowspan');
      var cellValue = cell.innerText;
      if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue;

      //Skip ranges
      ranges.forEach(function (range) {
        if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) {
          for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null);
        }
      });

      //Handle Row Span
      if (rowspan || colspan) {
        rowspan = rowspan || 1;
        colspan = colspan || 1;
        ranges.push({
          s: {
            r: R,
            c: outRow.length
          },
          e: {
            r: R + rowspan - 1,
            c: outRow.length + colspan - 1
          }
        });
      };

      //Handle Value
      outRow.push(cellValue !== "" ? cellValue : null);

      //Handle Colspan
      if (colspan)
        for (var k = 0; k < colspan - 1; ++k) outRow.push(null);
    }
    out.push(outRow);
  }
  return [out, ranges];
};

function datenum(v, date1904) {
  if (date1904) v += 1462;
  var epoch = Date.parse(v);
  return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
}

function sheet_from_array_of_arrays(data, opts) {
  var ws = {};
  var range = {
    s: {
      c: 10000000,
      r: 10000000
    },
    e: {
      c: 0,
      r: 0
    }
  };
  for (var R = 0; R != data.length; ++R) {
    for (var C = 0; C != data[R].length; ++C) {
      if (range.s.r > R) range.s.r = R;
      if (range.s.c > C) range.s.c = C;
      if (range.e.r < R) range.e.r = R;
      if (range.e.c < C) range.e.c = C;
      var cell = {
        v: data[R][C]
      };
      if (cell.v == null) continue;
      var cell_ref = XLSX.utils.encode_cell({
        c: C,
        r: R
      });

      if (typeof cell.v === 'number') cell.t = 'n';
      else if (typeof cell.v === 'boolean') cell.t = 'b';
      else if (cell.v instanceof Date) {
        cell.t = 'n';
        cell.z = XLSX.SSF._table[14];
        cell.v = datenum(cell.v);
      } else cell.t = 's';

      ws[cell_ref] = cell;
    }
  }
  if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range);
  return ws;
}

function Workbook() {
  if (!(this instanceof Workbook)) return new Workbook();
  this.SheetNames = [];
  this.Sheets = {};
}

function s2ab(s) {
  var buf = new ArrayBuffer(s.length);
  var view = new Uint8Array(buf);
  for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
  return buf;
}

export function export_table_to_excel(id) {
  var theTable = document.getElementById(id);
  var oo = generateArray(theTable);
  var ranges = oo[1];

  /* original data */
  var data = oo[0];
  var ws_name = "SheetJS";

  var wb = new Workbook(),
    ws = sheet_from_array_of_arrays(data);

  /* add ranges to worksheet */
  // ws['!cols'] = ['apple', 'banan'];
  ws['!merges'] = ranges;

  /* add worksheet to workbook */
  wb.SheetNames.push(ws_name);
  wb.Sheets[ws_name] = ws;

  var wbout = XLSX.write(wb, {
    bookType: 'xlsx',
    bookSST: false,
    type: 'binary'
  });

  saveAs(new Blob([s2ab(wbout)], {
    type: "application/octet-stream"
  }), "test.xlsx")
}

export function export_json_to_excel({
  multiHeader = [],
  header,
  data,
  filename,
  merges = [],
  autoWidth = true,
  bookType = 'xlsx'
} = {}) {
  /* original data */
  filename = filename || 'excel-list'
  data = [...data]
  data.unshift(header);

  for (let i = multiHeader.length - 1; i > -1; i--) {
    data.unshift(multiHeader[i])
  }

  var ws_name = "SheetJS";
  var wb = new Workbook(),
    ws = sheet_from_array_of_arrays(data);

  if (merges.length > 0) {
    if (!ws['!merges']) ws['!merges'] = [];
    merges.forEach(item => {
      ws['!merges'].push(XLSX.utils.decode_range(item))
    })
  }

  if (autoWidth) {
    /*设置worksheet每列的最大宽度*/
    const colWidth = data.map(row => row.map(val => {
      /*先判断是否为null/undefined*/
      if (val == null) {
        return {
          'wch': 10
        };
      }
      /*再判断是否为中文*/
      else if (val.toString().charCodeAt(0) > 255) {
        return {
          'wch': val.toString().length * 2
        };
      } else {
        return {
          'wch': val.toString().length
        };
      }
    }))
    /*以第一行为初始值*/
    let result = colWidth[0];
    for (let i = 1; i < colWidth.length; i++) {
      for (let j = 0; j < colWidth[i].length; j++) {
        if (result[j]['wch'] < colWidth[i][j]['wch']) {
          result[j]['wch'] = colWidth[i][j]['wch'];
        }
      }
    }
    ws['!cols'] = result;
  }

  /* add worksheet to workbook */
  wb.SheetNames.push(ws_name);
  wb.Sheets[ws_name] = ws;

  var wbout = XLSX.write(wb, {
    bookType: bookType,
    bookSST: false,
    type: 'binary'
  });
  saveAs(new Blob([s2ab(wbout)], {
    type: "application/octet-stream"
  }), `${filename}.${bookType}`);
}

因为数据中的key是英文,想要导出的表头是中文的话,需要将中文和英文做对应

const headers = {
        '入职日期': 'create_time',
        '手机号': 'mobile',
        '用户名': 'username',
        '角色': 'role_name',
        '邮箱': 'email',
        '部门': 'department_name'
      }

完成导出代码

import { formatDate } from '@/filters'
// 导出数据
    exportData() {
      const headers = {
        '入职日期': 'create_time',
        '手机号': 'mobile',
        '用户名': 'username',
        '角色': 'role_name',
        '邮箱': 'email',
        '部门': 'department_name'
      }
      import('@/vendor/Export2Excel').then(async excel => {
        const res = await getUserList({ query: '', pagenum: 1, pagesize: this.page.total })
        // console.log(res)
        const data = this.formatJson(headers, res.users)
        console.log(data)
        excel.export_json_to_excel({
          header: Object.keys(headers),
          data,
          filename: '用户信息表',
          autoWidth: true,
          bookType: 'xlsx'

        })
      })
    }    
    }

导出时间格式的处理

// 该方法负责将数组转化成二维数组
    formatJson(headers, rows) {
      return rows.map(item => {
        return Object.keys(headers).map(key => {
          if (headers[key] === 'create_time') {
            return formatDate(item[headers[key]]) // formatDate 函数是定义好的一个过滤器
          }
          return item[headers[key]]
        })
      })

过滤器 formatDate

import moment from 'moment'
export function formatTime(value) {
  return moment(value * 1000).format('YYYY-MM-DD HH:mm:ss')
}
export function formatDate(value) {
  return moment(value * 1000).format('YYYY-MM-DD')
}

到此这篇关于vue-element-admin项目导入和导出的实现的文章就介绍到这了,更多相关vue-element-admin项目导入导出内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Vue.js 相关文章推荐
antdesign-vue结合sortablejs实现两个table相互拖拽排序功能
Jan 08 Vue.js
vue 根据选择的月份动态展示日期对应的星期几
Feb 06 Vue.js
Vue中使用wangeditor富文本编辑的问题
Feb 07 Vue.js
vue实现拖拽进度条
Mar 01 Vue.js
Vue中避免滥用this去读取data中数据
Mar 02 Vue.js
vue实现锚点定位功能
Jun 29 Vue.js
Vue鼠标滚轮滚动切换路由效果的实现方法
Aug 04 Vue.js
详解Vue slot插槽
Nov 20 Vue.js
Vue如何清空对象
Mar 03 Vue.js
vue 给数组添加新对象并赋值
Apr 20 Vue.js
vue修饰符.capture和.self的区别
Apr 22 Vue.js
Vue操作Storage本地化存储
Apr 29 Vue.js
vue2实现provide inject传递响应式
May 21 #Vue.js
vue使用节流函数的踩坑实例指南
vue实现同时设置多个倒计时
May 20 #Vue.js
Vue和Flask通信的实现
Vue Element UI自定义描述列表组件
使用这 6个Vue加载动画库来减少我们网站的跳出率
一文带你理解vue创建一个后台管理系统流程(Vue+Element)
You might like
PHP字符串函数系列之nl2br(),在字符串中的每个新行 (\n) 之前插入 HTML 换行符br
2011/11/10 PHP
PHP获取指定时间段之间的 年,月,天,时,分,秒
2016/06/05 PHP
javascript css styleFloat和cssFloat
2010/03/15 Javascript
各浏览器中querySelector和querySelectorAll的实现差异分析
2012/05/23 Javascript
妙用Jquery的val()方法
2012/06/27 Javascript
Javascript全局变量var与不var的区别深入解析
2013/12/09 Javascript
node.js中的fs.readlinkSync方法使用说明
2014/12/17 Javascript
实例讲解jquery中mouseleave和mouseout的区别
2016/02/17 Javascript
JS组件Bootstrap Table使用实例分享
2016/05/30 Javascript
jQuery图片渐变特效的简单实现
2016/06/25 Javascript
微信小程序 自定义对话框实例详解
2017/01/20 Javascript
关于JavaScript中的this指向问题总结篇
2017/07/23 Javascript
JavaScript实现精美个性导航栏筋斗云效果
2017/10/29 Javascript
高性能的javascript之加载顺序与执行原理篇
2018/01/14 Javascript
深入理解react-router 路由的实现原理
2018/09/26 Javascript
详解jQuery中的getAll()和cleanData()
2019/04/15 jQuery
vue实现带复选框的树形菜单
2019/05/27 Javascript
前端开发之便利店收银系统代码
2019/12/27 Javascript
JS可断点续传文件上传实现代码解析
2020/07/30 Javascript
Vue跨域请求问题解决方案过程解析
2020/08/07 Javascript
[02:52]2014DOTA2西雅图国际邀请赛 CIS战队巡礼
2014/07/07 DOTA
[02:04]完美世界城市挑战赛秋季赛报名开始 谁是solo路人王?
2019/10/10 DOTA
详细探究Python中的字典容器
2015/04/14 Python
python如何修改装饰器中参数
2018/03/20 Python
Numpy array数据的增、删、改、查实例
2018/06/04 Python
解决Python3中的中文字符编码的问题
2018/07/18 Python
解决Python图形界面中设置尺寸的问题
2020/03/05 Python
详解pycharm配置python解释器的问题
2020/10/15 Python
HTML5网页音乐播放器的示例代码
2017/11/09 HTML / CSS
sort命令的作用和用法
2013/08/25 面试题
一月红领巾广播稿
2014/02/11 职场文书
腾讯广告词
2014/03/19 职场文书
与死神共舞观后感
2015/06/15 职场文书
职位证明模板
2015/06/23 职场文书
MySQL REVOKE实现删除用户权限
2021/06/18 MySQL
vue3中provide && inject的使用
2021/07/01 Vue.js