网络编程
位置:首页>> 网络编程>> JavaScript>> vue-element-admin项目导入和导出的实现

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

作者:“落幕”  发布时间:2024-05-21 10:29:53 

标签:vue,element,admin,导入,导出

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

来源:https://blog.csdn.net/qq_15034541/article/details/117043381

0
投稿

猜你喜欢

手机版 网络编程 asp之家 www.aspxhome.com