Vue - 使用Element UI Upload / importExcelJs进行文件导入

1 情景一

需求背景后端配合,点击"导入"按钮,弹出“导入”弹窗,将电脑本地Excel表格数据导入到页面中表格位置(需要调用后端接口),而页面中表格通过后端接口获取最新数据。
实现思路:弹窗嵌入 Element UI Upload 上传组件,获取到文件后调后端接口。

action: 上传的地址
file-list: 上传的文件列表, 例如: [{name: ‘food.jpg’, url: ‘https://xxx.cdn.com/xxx.jpg’}]
headers: 设置上传的请求头部(上传的文件可能是有固定格式的(表头),这个是在后端设定好了的,所以如果上传的文件格式不对可能会引起报错。)
before-upload: 上传文件之前的钩子,可作上传之前校验
on-error: 文件上传失败时的钩子
on-exceed: 文件超出个数限制时的钩子
on-success: 文件上传成功时的钩子
on-change: 文件状态改变时的钩子
this.$refs.fileUpload.submit(): 手动上传文件列表(fileUpload是自定义的名字)

  • 组件代码
<template><span><el-buttonplainicon="el-icon-upload2"type="primary"size="mini":disabled="disabled"@click="importFile">{{ $t('import') }}</el-button><el-dialogv-if="open":title="importTitle":visible.sync="open"width="500px"append-to-body:close-on-click-modal="false":show-close="false"@close="cancel"><div v-if="isShowRecord" class="record-btn"><el-button icon="el-icon-time" type="primary" size="mini" @click="recordBtnClick"><span>{{ recordText }}</span></el-button></div><div style="text-align: center;"><el-uploadref="fileUpload"multiple:auto-upload="false":action="uploadFileUrl":before-upload="handleBeforeUpload":file-list="fileList":limit="limit":on-error="handleUploadError":on-exceed="handleExceed":on-success="handleUploadSuccess":on-change="handleChange":headers="headers"class="upload-file-uploader"><div style="border:1px dashed #e9e9e9"><i class="el-icon-plus avatar-uploader-icon" style="margin:80px;font-size: 25px;" /></div><!-- 上传提示 --><div v-if="showTip" slot="tip" class="el-upload__tip">{{ $t("pleaseUpload") }}<template v-if="fileSize">{{ $t("sizeLess") }}<b style="color: #f56c6c">{{ fileSize }}MB</b></template><template v-if="fileType">{{ $t("formatIs") }}<b style="color: #f56c6c">{{ fileType.join("/") }}</b></template>{{ $t("file") }}</div></el-upload></div><div class="template"><!-- <form v-show="false" id="templateForm" :action="templateUrl" method="get" /> --><span @click="downloadFile">{{ $t("downloadThisTemplate") }}</span></div><div slot="footer" class="dialog-footer"><el-button type="primary" @click="submitForm">{{ $t('confirm') }}</el-button><el-button @click="cancel">{{ $t('cancel') }}</el-button></div></el-dialog></span>
</template>
<script>
import { getToken } from '@/utils/auth'
import { downloadGet } from '@/utils/request'
import moment from 'moment'
import $ from '@/i18n/index'export default {name: 'FileImport',props: {// 是否禁用导入按钮disabled: {type: Boolean,default: false},// 导入弹窗标题importTitle: {type: String,default: () => {return $.t('fileImport')}},// 数量限制limit: {type: Number,default: 1},// 大小限制(MB)fileSize: {type: Number,default: 20},// 文件类型, 例如['png', 'jpg', 'jpeg']fileType: {type: Array,default: () => ['csv']},// 是否显示提示isShowTip: {type: Boolean,default: true},// 下载模板路径downLoadUrl: { type: String, default: null },// 下载的全拼路径fullPathUrl: { type: String, default: null },// 模板名称fileName: { type: String, default: moment().format('yyyyMMDDHHmmss') },// 导入数据路径importUrl: { type: String, default: null },// 是否展示导入导出记录按钮isShowRecord: {type: Boolean,default: false},// 导入导出记录文字recordText: {type: String,default: () => {return $.t('importAndExportRecord')}}},data() {return {open: false,number: 0,baseUrl: process.env.VUE_APP_BASE_API,// templateUrl://   this.fullPathUrl || process.env.VUE_APP_BASE_API + this.downLoadUrl,fileList: []}},computed: {headers() {return { Authorization: getToken() }},// 是否显示提示showTip() {return this.isShowTip && (this.fileType || this.fileSize)},// 上传文件服务器地址uploadFileUrl() {return process.env.VUE_APP_BASE_API + this.importUrl}// templateUrl() {//   return this.fullPathUrl || process.env.VUE_APP_BASE_API + this.downLoadUrl// }},methods: {importFile() {this.open = true},submitForm() {if (this.fileList.length === 0) {this.$modal.msgError(this.$t('pleaseImportFile'))return}this.$refs.fileUpload.submit()},cancel() {this.$refs.fileUpload.clearFiles()this.open = falsethis.$emit('importSuccess')},// 上传前校检格式和大小handleBeforeUpload(file) {// 校检文件类型if (this.fileType) {const fileName = file.name.split('.')const fileExt = fileName[fileName.length - 1]const isTypeOk = this.fileType.indexOf(fileExt) >= 0if (!isTypeOk) {this.$modal.msgError(`${this.$t('fileTypeErrorUpload')}${this.fileType.join('/')}${this.$t('file')}`)return false}}// 校检文件大小if (this.fileSize) {const isLt = file.size / 1024 / 1024 < this.fileSizeif (!isLt) {this.$modal.msgError(`${this.$t('uploadFileSizeLess')} ${this.fileSize} MB!`)return false}}this.$modal.loading(this.$t('waitForUpload'))this.number++return true},// 文件个数超出handleExceed() {this.$modal.msgError(`${this.$t('uploadFileNumberLess')} ${this.limit}`)},// 上传失败handleUploadError() {this.$modal.msgError(this.$t('uploadFail'))this.$modal.closeLoading()},// 上传成功回调handleUploadSuccess(res, file) {if (res.code === 0) {this.$message({ type: 'success', message: this.$t('uploadSuccess') })this.cancel()this.$emit('handleUploadSuccess')} else {this.number--this.$modal.msgError(res.msg)this.$refs.fileUpload.handleRemove(file)}this.$modal.closeLoading()},downloadFile() {// document.getElementById('templateForm').submit()let dowloadUrl = this.downLoadUrlif (this.fullPathUrl) {dowloadUrl = this.fullPathUrl}downloadGet(dowloadUrl, `${this.fileName}.${this.fileType}`, {})},recordBtnClick() {this.$emit('recordBtnClick')},handleChange(file, fileList) {this.fileList = fileList}}
}
</script>
<style lang="scss" scoped>
.template {text-align: center;color: #1890ff;padding: 10px;span:hover {cursor: pointer;border-bottom: 1px solid #1890ff;}
}.record-btn {position: absolute;right: 18px;top: 18px;
}
</style>
// 通用下载方法,blob形式
export function downloadGet(url, filename, config) {downloadLoadingInstance = Loading.service({text: '正在下载数据,请稍候',spinner: 'el-icon-loading',background: 'rgba(0, 0, 0, 0.7)'})return service.get(url, {headers: { 'Content-Type': 'application/x-www-form-urlencoded' },responseType: 'blob',...config}).then(async(data) => {const isLogin = await blobValidate(data)if (isLogin) {const blob = new Blob([data])saveAs(blob, filename)} else {const resText = await data.text()const rspObj = JSON.parse(resText)const errMsg =errorCode[rspObj.code] || rspObj.msg || errorCode['default']Message.error(errMsg)}downloadLoadingInstance.close()}).catch((r) => {console.error(r)Message.error('下载文件出现错误,请联系管理员!')downloadLoadingInstance.close()})
}
import Cookies from 'js-cookie'const TokenKey = 'Admin-Token'export function getToken() {return Cookies.get(TokenKey)
}

在这里插入图片描述

  • 使用组件
 <FileImportdown-load-url="/client/template/export_template/sec_type"import-url="/client/sec_type/import"file-name="导入持仓"
/>

在这里插入图片描述

2 情景二

需求背景纯前端实现文件导入的情景。例如,一个常规excel文件填写模板,在用户的电脑上,用户上传完后,还可以在预览展示时,在线修改,改完可以下载,也可以将数据给到服务端,但这时,比如这模板数据通常不多,比如是一个团队成员这样的数据,通过文件流的形式传给后端,可能不是很理想,倒不如前端解析传那几行数据就行。
实现思路importExcel.js 导入excel文件

  1. 使用html支持上传标签从本地获取文件,例如type为file的input,el-upload等。
  2. 利用FileReader将文件读取为二进制字符串。
  3. 使用XLSX插件XLSX.read()方法,将二进制字符串转换成excel文件的工作蒲对象workbook(简写成wb)。
  4. 通过XLSX.utils.sheet_to_json()方法,从wb中获取第一张 Sheets表格数据并将其转换为json数据。
  5. 重组json数据生成数组,即是根据自己的定义的列字段名,重新组成符合自己需求的json数据。因为从excel中提取的数据是没有字段名或字段名不符合要求的,而我们需要渲染在页面表格中又确实需要合适的字段名。
/* eslint-disable */
/* 导入excel文件 */
/*** @param file 文件流* @param tableTemplate 要导入的表格模板,一个数组,如:* tableTemplate: ['userCode', 'userName', 'department', 'major', 'position'],其中的值* 为表格的字段名,注意字段的顺序应与实际的导入excel一致。*/
export default function importExcel (file, tableTemplate) {return new Promise((resolve, reject) => {let f = file.raw // 获取文件内容// 通过DOM取文件数据let rABS = false // 是否将文件读取为二进制字符串let reader = new FileReader()FileReader.prototype.readAsBinaryString = function (f) {let binary = ''let rABS = false // 是否将文件读取为二进制字符串let wb // 读取完成的数据let outdatalet reader = new FileReader()reader.onload = function (e) {let bytes = new Uint8Array(reader.result)let length = bytes.byteLengthfor (let i = 0; i < length; i++) {binary += String.fromCharCode(bytes[i])}let XLSX = require('xlsx')if (rABS) {wb = XLSX.read(btoa(binary), { // 手动转化type: 'base64'})} else {wb = XLSX.read(binary, {type: 'binary'})}outdata = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]) // outdata就是表格中的值let arr = []// 下面是数据解析提取逻辑if (tableTemplate.length > 0) {let tempArr = Object.keys(outdata[0])let tempArrNew = []for (let i in tempArr) {for (let k in tableTemplate) {if (i === k) {tempArrNew.push({fieldE: tableTemplate[k], fieldC: tempArr[i]})}}}tempArr = tempArrNewoutdata.map(item => {let obj = {}tempArr.map(temp2 => {obj[temp2.fieldE] = item[temp2.fieldC]})arr.push(obj)})}resolve(arr)}reader.readAsArrayBuffer(f)}if (rABS) {reader.readAsArrayBuffer(f)} else {reader.readAsBinaryString(f)}})
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/584637.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从零开始部署CTF题目环境(docker容器)

本教程将教会大家如何安装一台可以部署docker容器形式的CTF题目的CentOS服务器。 操作步骤 1-下载操作系统镜像文件 虚拟操作系统&#xff1a;CentOS 8 &#xff08;CentOS 9 毛病多&#xff0c;先不装&#xff09; 镜像文件下载地址&#xff0c;点击X86_64即可 CentOS St…

自定义docker镜像,ubuntu安装命令并导出

文章目录 问题现象解决步骤相关命令详细介绍docker save 与 docker loaddocker import 与 docker exportdocker commit 问题现象 我们的通讯服务&#xff0c;需要监测前端设备的在线情况&#xff08;是否在线、丢包率、延迟等&#xff09;&#xff0c;使用ping命令去实现此功能…

手把手教你配置Jenkins自动化邮件通知

完成基于Jenkins的持续集成部署后&#xff0c;自动化测试执行后&#xff0c;测试结果需要通知到相关人员&#xff0c;除了钉钉通知外我们还可以通过Email通知到对应负责人&#xff0c;这里记录一下测试结果通过Jenkins邮件通知的配置与部署 01、安装插件 方法1&#xff1a; 进…

第P8周:YOLOv5-C3模块实现

>- **&#x1f368; 本文为[&#x1f517;365天深度学习训练营](https://mp.weixin.qq.com/s/rbOOmire8OocQ90QM78DRA) 中的学习记录博客** >- **&#x1f356; 原作者&#xff1a;[K同学啊 | 接辅导、项目定制](https://mtyjkh.blog.csdn.net/)** 一、 前期准备 1. 设…

c基础学习(一)

学习网站&#xff1a; C语言的过去与未来 - C语言教程 - C语言网 (dotcpp.com)https://www.dotcpp.com/course/c-intros/ C 语言简介 - C 语言教程 - 网道 (wangdoc.com)https://wangdoc.com/clang/intro 变量&#xff1a; #include<stdio.h> /*引入头文件-- 标准…

git 常用命令总结

git 工作原理图&#xff1a; git 常用命令及解释: 命令解释例子git init在当前目录初始化一个新的 Git 仓库。git initgit clone <repository>克隆一个远程仓库到本地。git clone https://github.com/example/repository.gitgit add <file>将文件的变化添加到暂存…

Gaussian-Splatting 训练并导入Unity中

这个周末玩点啥~&#x1f41e; &#x1f365;环境安装&#x1f4a1;安装C编译工具&#x1f4a1;安装Python&#x1f4a1;安装CUDA&#x1f4a1;添加ffmpeg到环境变量Path添加COLMAP-3.8-windows-cuda文件路径到环境变量Path&#x1f4a1;pytorch安装&#x1f4a1;tqdm 安装&…

『JavaScript』全面解析JavaScript中的防抖与节流技术及其应用场景

&#x1f4e3;读完这篇文章里你能收获到 理解防抖&#xff08;Debouncing&#xff09;和节流&#xff08;Throttling&#xff09;的概念&#xff1a;了解这两种性能优化技术如何帮助我们更有效地处理频繁触发的事件掌握防抖与节流的实现方法&#xff1a;学习如何在JavaScript中…

WPF+Halcon 培训项目实战(8):WPF+Halcon初次开发

前言 为了更好地去学习WPFHalcon&#xff0c;我决定去报个班学一下。原因无非是想换个工作。相关的教学视频来源于下方的Up主的提供的教程。这里只做笔记分享&#xff0c;想要源码或者教学视频可以和他联系一下。 相关链接 微软系列技术教程 WPF 年度公益课程 Halcon开发 CSD…

本地搭建微信小程序或者公众号开发服务器的简单方法

现在小程序开发需要购买服务器&#xff0c;价格还是有点贵的&#xff0c;这里好代码网分享一个可以花费小代价就可以搭建一个本地服务器&#xff0c;可以用来开发小程序和微信公众号等。 1.域名&#xff08;备案过的&#xff09; 2.阿里云注册免费的https证书 3.配置本地的ngi…

[足式机器人]Part4 南科大高等机器人控制课 CH12 Robotic Motion Control

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;CLEAR_LAB 笔者带更新-运动学 课程主讲教师&#xff1a; Prof. Wei Zhang 课程链接 &#xff1a; https://www.wzhanglab.site/teaching/mee-5114-advanced-control-for-robotics/ 南科大高等机器人控制课 Ch12 Robotic …

大数据技术发展史

今天我们常说的大数据技术&#xff0c;其实起源于Google在2004年前后发表的三篇论文&#xff0c;也就是我们经常听到的“三驾马车”&#xff0c;分别是分布式文件系统GFS、大数据分布式计算框架MapReduce和NoSQL数据库系统BigTable。 你知道&#xff0c;搜索引擎主要就做两件事…

C语言 volatile关键字

volatile关键字介绍 volatile 是一个关键字&#xff0c;用于修饰变量&#xff0c;表示该变量是易变的&#xff0c;即可能在任何时候被意外地改变。在多线程编程中&#xff0c;当多个线程同时访问同一个变量时&#xff0c;由于线程之间的交互和优化&#xff0c;可能会导致变量的…

Python 实现 PDF 到 Word 文档的高效转换(DOC、DOCX)

PDF&#xff08;Portable Document Format&#xff09;已成为一种广泛使用的电子文档格式。PDF的主要优势是跨平台&#xff0c;可以在不同设备上呈现一致的外观。然而&#xff0c;当我们需要对文件内容进行编辑或修改&#xff0c;直接编辑PDF文件会非常困难&#xff0c;而且效果…

SimpleCG小游戏开发系列(2)--贪吃蛇

一、前言 在之前的C语言小游戏开发系列我们已经介绍了扫雷游戏的开发&#xff0c;本篇我们继续此系列第二篇&#xff0c;同样是比较简单但好玩的一个游戏--贪吃蛇。因为有了之前的游戏框架&#xff0c;我们只需要直接搬来原来的框架即可&#xff0c;可以省去不少活。 先看看游…

java数据结构与算法刷题-----LeetCode 680. 验证回文串 II

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 思路&#xff1a;双指针 详情见代码注释 class Solution {//贪心双指针&a…

什么是工厂方法模式,工厂方法模式解决了什么问题?

工厂方法模式是一种创建型设计模式&#xff0c;它定义了一个用于创建对象的接口&#xff0c;但将实际的实例化过程延迟到子类中。这样&#xff0c;客户端代码在不同的子类中实例化具体对象&#xff0c;而不是直接实例化具体类。工厂方法模式允许一个类的实例化延迟到其子类&…

Springboot实现登录注册

功能&#xff1a;1、实现用户的登录 2、实现用户的注册以及重名的判断 LoginControl&#xff1a; package com.example.demo.controls;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; imp…

CEC2017(Python):五种算法(HHO、RFO、OOA、PSO、GWO)求解CEC2017

一、5种算法简介 1、哈里斯鹰优化算法HHO 2、红狐优化算法RFO 3、鱼鹰优化算法OOA 4、粒子群优化算法PSO 5、灰狼优化算法GWO 二、CEC2017简介 参考文献&#xff1a; [1]Awad, N. H., Ali, M. Z., Liang, J. J., Qu, B. Y., & Suganthan, P. N. (2016). “Problem d…

resnet18

ResNet18的基本含义是&#xff0c;网络的基本架构是ResNet&#xff0c;网络的深度是18层。但是这里的网络深度指的是网络的权重层&#xff0c;也就是包括池化&#xff0c;激活&#xff0c;线性层。而不包括批量化归一层&#xff0c;池化层。 transforms.RandomCrop(32, pa…