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 相关文章推荐
vue 获取到数据但却渲染不到页面上的解决方法
Nov 19 Vue.js
vue element-ul实现展开和收起功能的实例代码
Nov 25 Vue.js
vue中如何自定义右键菜单详解
Dec 08 Vue.js
详解Vue2的diff算法
Jan 06 Vue.js
vue.js实现点击图标放大离开时缩小的代码
Jan 27 Vue.js
Vite和Vue CLI的优劣
Jan 30 Vue.js
如何让vue长列表快速加载
Mar 29 Vue.js
vue如何批量引入组件、注册和使用详解
May 12 Vue.js
vue中 this.$set的使用详解
Nov 17 Vue.js
详解Vue项目的打包方式(生成dist文件)
Jan 18 Vue.js
Vue自定义铃声提示音组件的实现
Jan 22 Vue.js
Vue3如何理解ref toRef和toRefs的区别
Feb 18 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检测数组长度函数sizeof与count用法
2014/11/17 PHP
php中如何执行linux命令详解
2018/11/06 PHP
Aster vs Newbee BO5 第一场2.19
2021/03/10 DOTA
jQuery使用手册之 事件处理
2007/03/24 Javascript
一款js和css代码压缩工具[附JAVA环境配置方法]
2010/04/16 Javascript
20款超赞的jQuery插件 Web开发人员必备
2011/02/26 Javascript
获取select元素被选中的文本内容的js代码
2014/01/29 Javascript
jquery插件开发之实现jquery手风琴功能分享
2014/03/10 Javascript
jQuery form 表单验证插件(fieldValue)校验表单
2016/01/24 Javascript
jquery获取table指定行和列的数据方法(当前选中行、列)
2016/11/07 Javascript
jquery validation验证表单插件
2017/01/07 Javascript
基于MVC方式实现三级联动(JavaScript)
2017/01/23 Javascript
vue轮播图插件vue-awesome-swiper的使用代码实例
2017/07/10 Javascript
基于vue.js中事件修饰符.self的用法(详解)
2018/02/23 Javascript
浅谈vue的几种绑定变量的值 防止其改变的方法
2018/03/01 Javascript
详解基于DllPlugin和DllReferencePlugin的webpack构建优化
2018/06/28 Javascript
微信小程序url传参写变量的方法
2018/08/09 Javascript
vue2中,根据list的id进入对应的详情页并修改title方法
2018/08/24 Javascript
vue如何自动化打包测试环境和正式环境的dist/test文件
2019/06/06 Javascript
JavaScript实现的弹出遮罩层特效经典示例【基于jQuery】
2019/07/10 jQuery
JavaScript 俄罗斯方块游戏实现方法与代码解释
2020/04/08 Javascript
基于Python实现的百度贴吧网络爬虫实例
2015/04/17 Python
python如何统计序列中元素
2020/07/31 Python
Python判断字符串是否为字母或者数字(浮点数)的多种方法
2018/08/03 Python
利用Python对文件夹下图片数据进行批量改名的代码实例
2019/02/21 Python
程序员的七夕用30行代码让Python化身表白神器
2019/08/07 Python
在pycharm中配置Anaconda以及pip源配置详解
2019/09/09 Python
Python 忽略文件名编码的方法
2020/08/01 Python
python中str内置函数用法总结
2020/12/27 Python
澳大利亚买卖正宗二手奢侈品交易平台:Luxe.It.Fwd
2019/10/16 全球购物
考博专家推荐信模板
2013/12/02 职场文书
电子信息工程专业推荐信
2014/02/14 职场文书
一年级小学生评语大全
2014/12/25 职场文书
法制工作总结2015
2015/07/23 职场文书
职工趣味运动会开幕词
2016/03/04 职场文书
MySQL Threads_running飙升与慢查询的相关问题解决
2021/05/08 MySQL