09.人力资源管理项目

您所在的位置:网站首页 javaweb导出excel表格是如何实现的 09.人力资源管理项目

09.人力资源管理项目

2023-05-21 13:27| 来源: 网络整理| 查看: 265

09.人力资源管理项目 -_Excel导入导出==>文件上传方式(前端主导、后端主导)、从路由出发寻找组件代码、注册全局组件、内容格式化、导出实现、导出顺序问题 01.员工管理-Excel导入功能介绍 目标

在前面员工的添加是一个一个进行的,如果一次性添加多个员工信息,这时候就会很繁琐

因此需要我们开发一个批量导入的功能,将用户的信息存储到 excel 中然后进行批量导入

讲解 实现方式 1

前端主导(工作大量在前端)

上传 excel 文件,把 excel 文件的内容读出来,还原成最基本的行列结构将数据按照后端接口要求格式化,并使用 AJAX 将数据发送到服务器

image-20230509211320921

实现方式 2

后端主导(工作大量在后端)

前端只需要负责将 excel 文件上传

image-20230509211311861

小结

excel文件上传有几种方式?

答案 在前端, 把excel文件获取到, 用第三方包把文件数据读出, 转换后发给后台在后端, 前端把excel文件, 用FormData对象直接发给后台, 让后台读取/保存

图片上传也有几种方式呢?

答案 前端把图片转成base64字符串发给后台, 后台保存图片的base64字符串数据前端把图片文件, 放到formData表单对象中, 直接发给后台, 后台接收文件数据流, 把文件保存到后台 02.员工管理-Excel导入方案 目标

分析 vue-element-admin 中的导入方案

image-20230509211301860

讲解 分析 打开我们前面下载的项目, 通过路由路径定位到源码位置进行分析导入相关的代码文件有两个: 使用组件:src/views/excel/upload-excel.vue定义组件:src/components/UploadExcel/index.vue 上传组件实现分析 源代码 src/components/UploadExcel/index.vue import XLSX from 'xlsx' export default { props: { beforeUpload: Function, // eslint-disable-line onSuccess: Function// eslint-disable-line }, data() { // 代码略 }, methods: { // 代码略 } }

这个组件引入了 xlsx 包, 因此我们需要提前安装

Excel 的导入导出都是依赖于js-xlsx来实现的,在 js-xlsx的基础上又封装了Export2Excel.js来方便导出数据由于 Export2Excel不仅依赖js-xlsx还依赖file-saver和script-loader file-saver 用户在客户端保存文件的script-loader 用于在前端执行一次js脚本文件的 npm install xlsx file-saver -S npm install script-loader -S -D

需要给它提供两个 props:

beforeUpload:上传之前的函数,可以在上传之前做一些自己的特殊判断,如判断文件的大小是否大于 1 兆?onSuccess: 成功调用之后的函数,它会返回表格的表头和内容。 导入组件使用分析

源代码:src/views/excel/upload-excel.vue

// 导入上传的组件 import UploadExcelComponent from '@/components/UploadExcel/index.vue' export default { name: 'UploadExcel', // 绑定上传组件 components: { UploadExcelComponent }, data() { return { tableData: [], tableHeader: [] } }, methods: { // 上传之前的函数 beforeUpload(file) { // 如判断文件的大小是否大于 1 兆 const isLt1M = file.size / 1024 / 1024 < 1 // 若大于 1 兆则停止解析并提示错误信息。 if (isLt1M) { return true } this.$message({ message: 'Please do not upload files larger than 1m in size.', type: 'warning' }) return false }, // 成功调用之后的函数,它会返回表格的表头和内容。 handleSuccess({ results, header }) { this.tableData = results this.tableHeader = header } } } 图解

image-20230509211250286

小结

分析别的项目, 页面文件去哪里找, 具体标签在哪里找?

答案 页面组件看路由, 从路由里找到, 标签可以看关键字或者类名去代码全局搜索/页面搜索

文件转数据是依赖哪些包实现的?

答案 xlsx包和它需要依赖的file-saver和script-loader包 03.员工管理-Excel导入组件准备 目标

拷贝 vue-element-admin 中提供的 excel 导入功能组件到自己项目中

讲解 分析 安装包拷贝核心组件 实现

安装必要的插件

-S和-D (默认就是–save不写即可, -S -D(是–save-dev) : 具体区别可以看这里: https://www.bilibili.com/video/BV15M4y1u78F?spm_id_from=333.999.0.0

npm install xlsx file-saver -S npm install script-loader -S -D

引入UploadExcel组件并注册为全局

将 vue-element-admin 提供的组件复制到我们自己的项目 src/components/UploadExcel下

在 src\components\index.js 中将该组件注册成全局组件

在index.js将它注册成全局组件

/** * 进行全局组件的挂载 */ import PageTools from './PageTools/index.vue' import UploadExcel from './UploadExcel/index.vue' export default { install(Vue) { Vue.component('PageTools', PageTools) Vue.component('UploadExcel', UploadExcel) } }

这里要格外注意, 最新版的xlsx包, 导出的方式改变了, 所以我们要修改UploadExcel组件代码

// import XLSX from 'xlsx' // 上面改成下面这样, 按需引入所有然后形成一个对象保存到XLSX变量上 import * as XLSX from 'xlsx' 小结

我们为什么在components/index.js - 在这里导入和注册

答案 统一注册和导出, 然后在main.js用Vue.use注册全局组件 04.员工管理-Excel导入页面准备 目标 根据业务要求配置一个独立的 excel导入功能 路由创建 excel导入功能 对应的组件,在这个单独的页面中实现员工导入功能 讲解 分析 配置路由建立对应的页面,然后在这个页面中引入 UploadExcel 组件实现导入功能 实现 建立公共导入的页面路由

在 src 目录下创建 excel 文件夹

创建 excel导入功能 组件,src\views\excel\index.vue

创建页面的结构,同时补充导入成功后的回调函数 export default { name: 'Excel', methods: { // 导入成功以后的回调函数 handleSuccess({ results, header }) {} } } 配置路由

这个路由不需要根据权限控制,直接定义为静态路由即可。在**src/router/index.js**下的静态路由表末尾404前添加一个路由

{ path: '/excel', component: Layout, hidden: true, // 不显示到左侧菜单 children: [{ path: '', component: () => import('@/views/excel') }] } 在views/employees/index.vue 在 按钮绑定点击事件,点击后跳转到 Excel 导入页面 导入excel 事件方法中, 切换路由页面到/excel, 查看前面准备的上传表格页 // 导入excel按钮->点击事件 uploadExcelBtnFn() { this.$router.push('/excel') }

测试导入效果

excel 导入插件本质:把 excel 经过分析转换成js能够识别的常规数据,拿到数据我们可以进行任何操作 methods: { // 导入成功以后的回调函数 handleSuccess({ results, header }) { console.log(results) console.log(header) } } 小结

我们是如何实现表格导入读取成数组的功能?

答案 使用xlsx的这个第三方的包, 然后使用模板项目里准备的组件文件使用即可 05.员工管理-Excel导入内容格式化 目标

数据格式转换:将 excel 解析好的数据经过处理后,转成可以传给接口调用的数据

image-20230509211235234

讲解 分析 调用接口进行excel上传的重点其实是数据的处理,按照接口的要求,把 excel 表格中经过插件处理好的数据处理成后端接口要求的格式 实现 在views/excel/index.vue导入时间处理方法 import { formatExcelDate } from '@/utils'

按接口要求,处理excel导入的数据。处理内容包含:

字段中文转英文。excel中读入的是姓名,而后端需要的是username

日期处理。从excel中读入的时间是一个 number 值,而后端需要的是标准日期

methods: { // 将表格中的数据进行格式化 transExcel(results) { const userRelations = { '入职日期': 'timeOfEntry', '手机号': 'mobile', '姓名': 'username', '转正日期': 'correctionTime', '工号': 'workNumber', '部门': 'departmentName', '聘用形式': 'formOfEmployment' } return results.map(item => { const obj = {} // 1. 取出这个对象所有的属性名: ['姓名', ‘手机号’] // 2. 遍历这个数组,通过 中文名去 userRelations 找对应英文名, 保存值 const contentKeys = Object.keys(item) contentKeys.forEach(key => { // 找到对应的英文名 const transKey = userRelations[key] // 如果格式化的是时间,需要进行转换 if (transKey === 'timeOfEntry' || transKey === 'correctionTime') { // 表格的天数->转成日期对象 const transDate = new Date(formatExcelDate(item[key])) // 再把日期对象转成->'年-月-日'保存到对象属性里给后台 obj[transKey] = parseTime(transDate, '{yyyy}-{mm}-{dd}') } else { obj[transKey] = item[key] } }) return obj }) }, // 导入成功以后的回调函数 handleSuccess({ results, header }) { const arr = this.transExcel(results) console.log('转换之后的格式是', arr) } }

上面用到的日期处理函数在 utils/index.js 中定义如下

// 把excel文件中的日期格式的内容转回成标准时间 export function formatExcelDate(numb, format = '/') { const time = new Date((numb - 25567) * 24 * 3600000 - 5 * 60 * 1000 - 43 * 1000 - 24 * 3600000) time.setYear(time.getFullYear()) const year = time.getFullYear() + '' const month = time.getMonth() + 1 + '' const date = time.getDate() + '' if (format && format.length === 1) { return year + format + month + format + date } return year + (month url: '/sys/user/batch', method: 'post', data }) }

在views/excel/index.vue表格上传页面中导入封装的方法

import { importEmployeeAPI } from '@/api'

调用封装的方法,实现 Excel 导入功能

// 导入成功以后的回调函数 async handleSuccess({ results, header }) { const arr = this.transExcel(results) const res = await importEmployeeAPI(arr).catch(err => err) if (!res.success) return this.$message.error(res.message) this.$router.back() this.$message.success('操作成功') } 小结

$router.back作用是?

答案 跳转回到上一个路由历史的记录 07.员工管理-Excel导出功能介绍 目标

在表格中查询到了我们需要的数据,希望用他们生成excel文件,保存在本地。

讲解 实现方式 1

取回数据,解析数据,保存为 excel 文件,工作大量在前端

image-20230509211217175

实现方式 2

前端调用接口,获取 excel 文件,下载即可,工作大量在后端

image-20230509211208947

小结

在前端, 导出Excel形成一个文件, 如何做?

答案 先请求后台接口, 拿到列表所有数据然后借助xlsx包的方法, 把数据转成excel文件并下载 08.员工管理-Excel导出方案 目标

先去vue-admin中去学习导出功能的用法,并归纳总结把它用到本项目中的步骤

前置工作:这个功能在我们课程一开始学习的vue-element-admin中有现成的功能参考,我们也在项目资源里提供了现成的插件包,大家先把它复制到自己项目的src目录下

讲解 分析

学习使用现成的excel导出组件,通过路由路径定位到源码位置

image-20230509211158765

熟悉案例代码

网上示例地址:https://gitee.com/mirrors/vue-element-admin/blob/master/src/views/excel/export-excel.vue

import('@/vendor/Export2Excel').then(excel => { const tHeader = ['Id', 'Title', 'Author', 'Readings', 'Date'] const filterVal = ['id', 'title', 'author', 'pageviews', 'display_time'] const list = this.list const data = this.formatJson(filterVal, list) excel.export_json_to_excel({ header: tHeader, data, filename: this.filename, autoWidth: this.autoWidth, bookType: this.bookType }) this.downloadLoading = false }) 具体说明 插件包位于src/vendor/export2Excel中,采用的是按需引入的方式

什么时候正式要使用导出功能了,插件才会被正式引入到应用里

import('@/vendor/Export2Excel').then(excel => {})

Export2Excel依赖的包有js-xlsx、file-saver和script-loader

也就是说,在项目跑起来之前要安装依赖

npm install file-saver script-loader --save 小结

导出表格如何实现?

答案 使用xlsx包里,准备好的方法 09_员工管理-Excel导出基础实现 目标

实现员工的基础导出功能实现

讲解 分析

把vue-element-admin 中的导出功能,迁移本项目

使用静态数据实现基础的导出功能(先不使用从接口获取的数据)

实现

将 vue-element-admin 中的 src/vendor/export2Excel 复制到本项目中,直接使用

格外注意, 新版的xlsx导入方式改变了, 所以要改变代码

import * as XLSX from 'xlsx'

在项目中安装依赖

npm install file-saver script-loader --save

给导出按钮添加点击事件

导出excel // 导出excel按钮->点击事件 downloadExcel() { import('@/vendor/Export2Excel').then(excel => { // excel表示导入的模块对象 excel.export_json_to_excel({ header: ['姓名', '工资'], // 表头 必填 data: [ ['刘备', 100], ['关羽', 500] ], // 具体数据 必填 filename: 'excel-list', // 文件名称 autoWidth: true, // 宽度是否自适应 bookType: 'xlsx' // 生成的文件类型 }) }) }

以上代码表示:

当我们正式点击导出按钮之后,才去加载 vendor 文件夹中的Export2Excel模块import 方法执行完毕返回的是一个 promise 对象,在then方法中我们可以拿到使用的模块对象重点关注 data 的配置部分,我们发现它需要一个严格的二维数组

Excel导出参数说明

参数说明类型可选值默认值header导出数据的表头Array/[]data导出的具体数据Array/[[]]filename导出文件名String/excel-listautoWidth单元格是否要自适应宽度Booleantrue / falsetruebookType导出文件类型Stringxlsx, csv, txt, morexlsx 小结

导出时的二个数组, 怎么来呢?

答案 需要我们按照目标表格需要的字段和数据, 用js代码进行排列 10.员工管理-Excel导出尝试实现 目标

使用业务 真实数据实现导出功能

讲解 分析

从后台重新获取数据(这样才能确保是最新的)

对数据的格式进行转换(后端给的数据字段名都是英文的),以用来做导出

image-20230509211140074

核心在于把后端接口返回的数据转成 Export2Excel 这个插件需要的格式

准备表头header数据

因为接口中返回的数据中的key是英文,而我们期望导出的表头是中文,所以提前准备中文和英文的映射关系

const map = { 'id': '编号', 'password': '密码', 'mobile': '手机号', 'username': '姓名', 'timeOfEntry': '入职日期', 'formOfEmployment': '聘用形式', 'correctionTime': '转正日期', 'workNumber': '工号', 'departmentName': '部门', 'staffPhoto': '头像地址' } 目标表格data数据

具体的表格数据我们需要通过接口从后端获取回来,难点在于如何把后端返回的数据处理成Export2Excel插件需求的二维数组格式。

下面是一个示例:

const dataArr = [ ["13600000001", "吕勇锐", "1992-08-04", "正式", "2020-01-01", "0001", "总裁办"] ["13600000002", "袁永安", "1993-08-04", "正式", "2020-01-01", "0002", "总裁办"] ] 补充一个用来处理数据的函数 transData(rows) { // 写代码 const map = { 'id': '编号', 'password': '密码', 'mobile': '手机号', 'username': '姓名', 'timeOfEntry': '入职日期', 'formOfEmployment': '聘用形式', 'correctionTime': '转正日期', 'workNumber': '工号', 'departmentName': '部门', 'staffPhoto': '头像地址' } const headerKeys = Object.keys(rows[0]) const header = headerKeys.map(item => { return map[item] }) const data = rows.map(obj => { return Object.values(obj) }) return { header, data } } 最终的代码 methods: { transData(rows) { // 写代码 const map = { 'id': '编号', 'password': '密码', 'mobile': '手机号', 'username': '姓名', 'timeOfEntry': '入职日期', 'formOfEmployment': '聘用形式', 'correctionTime': '转正日期', 'workNumber': '工号', 'departmentName': '部门', 'staffPhoto': '头像地址' } const headerKeys = Object.keys(rows[0]) const header = headerKeys.map(item => { return map[item] }) const data = rows.map(obj => { return Object.values(obj) }) return { header, data } } // 导出 Excel async downloadExcel() { const res = await getEmployeeList() const excelObj = this.transData(res.data.rows) import('@/vendor/Export2Excel').then(excel => { // excel表示导入的模块对象 excel.export_json_to_excel({ header: excelObj.header, // 表头 必填 data: excelObj.data, // 具体数据 必填 filename: '员工列表', // 文件名称 autoWidth: true, // 宽度是否自适应 bookType: 'xlsx' // 生成的文件类型 }) }) }, } 小结

数据如果不是自己想要的结构要怎么办?

答案 先看好自己手上的数据, 和目标数据之间的关系, 找规律用js代码, 把对应的数据结构, 熟练使用对象的方法和数组方法进行转换使用

下载的只有当前页面的数据, 如果我想要全部的数据怎么办?

答案 请求第一次, 把总数据请求回来, 然后单独发送参数, 把1页所有数据拿回来导出成表格即可 11.员工管理-Excel导出顺序对应 目标

刚才我们的数据对应不了页面, 而且数据顺序也有点错乱, 尝试解决

讲解

分析原因, Object.values拿到的值数组顺序不稳定, 所以我们决定自己来实现一个个取值和按顺序组织数组

transData(rows) { // // 写代码 // const map = { // 'id': '编号', // 'password': '密码', // 'mobile': '手机号', // 'username': '姓名', // 'timeOfEntry': '入职日期', // 'formOfEmployment': '聘用形式', // 'correctionTime': '转正日期', // 'workNumber': '工号', // 'departmentName': '部门', // 'staffPhoto': '头像地址' // } // const headerKeys = Object.keys(rows[0]) // const header = headerKeys.map(item => { // return map[item] // }) // const data = rows.map(obj => { // return Object.values(obj) // }) // return { header, data } // 考虑顺序 (页面上列保持一致顺序) // 4.0 准备一个列表头中文数组 (8个) const headerArr = ['序号', '姓名', '头像', '手机号', '工号', '聘用形式', '部门', '入职时间'] // 4.1 数据key的映射关系(思路: 遍历上边数组里按照顺序, 取出中文的名字, 但是对应数组值的数组, 要从英文key对象中取出value值, 我要用中文key换到英文key然后去取到值) const myObj = { // 序号可以等遍历的时候直接用索引值, 而不是来自于英文对象里 '姓名': 'username', '头像': 'staffPhoto', '手机号': 'mobile', '工号': 'workNumber', '聘用形式': 'formOfEmployment', '部门': 'departmentName', '入职时间': 'timeOfEntry' } // 4.2 按照顺序, 形成值的数组 (明确目标->想要数据结构->读代码(每个变量意思)读2-3遍->仿写3-5遍) const resultArr = rows.map((item, index) => { const valueArr = [] // 值小数组 headerArr.forEach(zhKey => { if (zhKey === '序号') { valueArr.push(index + 1) } else { const enKey = myObj[zhKey] valueArr.push(item[enKey]) } }) return valueArr }) return { header: headerArr, data: resultArr } }, // 导出 Excel async downloadExcel() { const res = await getEmployeeListAPI() const res2 = await getEmployeeListAPI({ page: 1, size: res.data.total }) const excelObj = this.transData(res2.data.rows) import('@/vendor/Export2Excel').then(excel => { // excel表示导入的模块对象 excel.export_json_to_excel({ header: excelObj.header, // 表头 必填 data: excelObj.data, // 具体数据 必填 filename: '员工列表', // 文件名称 autoWidth: true, // 宽度是否自适应 bookType: 'xlsx' // 生成的文件类型 }) }) } 小结

值数组是如何和列标题头数组对应的?

答案 首先, 遍历数组是按照顺序的, 拿到中文的key换成英文的key, 再去对象取值后, 按顺序push到值的数组中


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3