Vue - 文件导入组件封装

1 情景一

需求背景:导入本地表格数据到页面中表格,而页面中表格数据通过后端接口获取。
实现思路:弹窗嵌入 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>
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/579015.shtml

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

相关文章

Springboot静态资源与模板引擎Thymeleaf篇

一、导入静态资源 1.1 静态资源目录 只要静态资源放在类路径下&#xff1a; /static or /public or /resources or /META-INF/resources访问 &#xff1a; 当前项目根路径/ 静态资源名原理&#xff1a; 静态映射/**&#xff1b; "/**" 访问当前项目的任何资源 (静态…

Arduino平台软硬件原理及使用——按键模块(下拉电阻电路)的使用

文章目录 一、上拉电阻电路 二、下拉电阻电路 二、按键模块在Arduino中的使用 一、上拉电阻电路 如上图为上拉电阻电路的按键原理&#xff0c;VCC及GND分别为正负极&#xff0c;PIN接信号端口&#xff1b; 此时可实现的功能为&#xff1a; 按键未按下时PIN接收高电平信号&#…

知乎冷门蓝海项目,零门槛教你如何单日变现200+

顺哥轻创资源网 shundazy1 一、项目介绍&#xff1a; 通过知乎平台上传相关资料作品 用文章内容吸引用户&#xff0c;随后会下载我们准备好的资料作品 用户下载资料后&#xff0c;我们即可通过资料变现 总结起来就是软文引流配合链接变现的模式 我们团队实操下来单号每日…

智能监控平台/视频共享融合系统EasyCVR点击通道后页面分页不显示是什么原因?如何解决?

TSINGSEE青犀视频监控汇聚平台EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安防视频监控的能力&…

API文档生成!超好用API调试工具

在数字化时代&#xff0c;API已经成为了应用程序之间进行通信的关键桥梁。随着API的普及和复杂性的增加&#xff0c;API研发和管理也面临着越来越多的挑战。为了更好地应对这些挑战&#xff0c;Apipost提供了一整套API研发工具&#xff0c;包括API设计、API调试、API文档和API自…

【算法学习】斐波那契数列模型-动态规划

前言 我在算法学习过程中&#xff0c;针对斐波那契数列模型的动态规划的例题进行了一个整理&#xff0c;并且根据标准且可靠一点的动态规划解题思路进行求解类似的动归问题&#xff0c;来达到学习和今后复习的必要。 所谓的斐波那契数列模型&#xff0c;即当前状态的值等于前两…

鸿蒙原生应用/元服务开发-Stage模型能力接口(十)上

ohos.app.form.FormExtensionAbility (FormExtensionAbility) FormExtensionAbility为卡片扩展模块&#xff0c;提供卡片创建、销毁、刷新等生命周期回调。 本模块首批接口从API version 9开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。本模块接…

odoo17核心概念view5——ir_ui_view.py

这是view系列的第5篇文章&#xff0c;介绍一下view对应的后端文件ir_ui_view.py&#xff0c;它是base模块下的一个文件 位置&#xff1a;odoo\addons\base\models\ir_ui_view.py 该文件一共定义了三个模型 1.1 ir.ui.view.custom 查询数据库这个表是空的&#xff0c;从名字看…

云原生Kubernetes:K8S集群实现容器运行时迁移(docker → containerd) 与 版本升级(v1.23.14 → v1.24.1)

目录 一、理论 1.K8S集群升级 2.环境 3.升级策略 4.master1节点迁移容器运行时(docker → containerd) 5.master2节点迁移容器运行时(docker → containerd) 6.node1节点容器运行时迁移(docker → containerd) 7.升级集群计划&#xff08;v1.23.14 → v1.24.1&#…

接口文档设计的12个注意点

我们做后端开发的,经常需要定义接口文档。 最近在做接口文档评审的时候&#xff0c;发现一个小伙伴定义的出参是个枚举值&#xff0c;但是接口文档没有给出对应具体的枚举值。其实&#xff0c;如何写好接口文档&#xff0c;真的很重要。今天我给你带来接口文档设计的12个注意点…

OpenCV数字图像处理——基于目标边缘适用于目标部分遮挡或不同光照模板匹配

简介 模板匹配是一种常见的计算机视觉问题&#xff0c;通常用于在一张图像中查找特定的模板图像。在处理模板匹配时&#xff0c;经常会面临对象的姿态未知的情况&#xff0c;其中姿态包括位置&#xff08;X&#xff0c;Y坐标&#xff09;和旋转角度&#xff08;θ&#xff09;…

C++继承与派生——(3)公有继承的访问权限的变化

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 缺乏明确的目标&#xff0c;一生将庸庸…

linux cpu调度分析

一、cpu调度调试方法 echo 0 > /sys/kernel/debug/tracing/tracing_on echo > /sys/kernel/debug/tracing/trace echo 30720 > /sys/kernel/debug/tracing/buffer_size_kb echo nop > /sys/kernel/debug/tracing/current_tracer echo sched_switch sched_wakeup s…

Python 基础面试第三弹

1. 获取当前目录下所有文件名 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import os def get_all_files(directory): file_list []<br> # <code>os.walk</code>返回一个生成器&#xff0c;每次迭代时返回当前目录路径、子目录列表和文件列表 for…

闲来无事,使用C++和代理IP采集天气预报信息

目录 一、引言 二、代理IP原理 三、选择合适的代理IP服务 四、C程序实现 五、测试与优化 六、结论 一、引言 在当今的互联网时代&#xff0c;网络信息的获取变得日益重要。天气预报信息作为日常生活的重要参考&#xff0c;其获取方式也随着技术的发展而不断变化。在本文…

JVisualVM工具的使用⭐️并使用自带JDBC监控sql语句执行时间记录

小伙伴们大家好&#xff0c;今天使用了继Jconsole工具之外的另一个JDK自带的性能分析工具 目录 一、JVisualVm 简介 二、使用 三、菜单使用 章末 一、JVisualVm 简介 JVisualVM是Java VisualVM的简称&#xff0c;是一个集成了多个 JDK 自带监控和故障处理工具的图形化工具…

MySQL的替换函数及补全函数的使用

前提&#xff1a; mysql的版本是8.0以下的。不支持树形结构递归查询的。但是&#xff0c;又想实现树形结构的一种思路 提示&#xff1a;如果使用的是MySQL8.0及其以上的&#xff0c;想要实现树形结构&#xff0c;请参考&#xff1a;MySQL数据库中&#xff0c;如何实现递归查询…

基于BaseHTTPRequestHandler的HTTP服务器基础实现

1. BaseHTTPRequestHandler介绍 BaseHTTPRequestHandler是Python中的一个基类&#xff0c;属于http.server模块&#xff0c;用于处理HTTP请求的基本功能。它提供了处理常见HTTP请求方法&#xff08;如GET、POST等&#xff09;的默认实现&#xff0c;并允许你在子类中进行定制化…

2024年【道路运输企业安全生产管理人员】考试题及道路运输企业安全生产管理人员报名考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 道路运输企业安全生产管理人员考试题考前必练&#xff01;安全生产模拟考试一点通每个月更新道路运输企业安全生产管理人员报名考试题目及答案&#xff01;多做几遍&#xff0c;其实通过道路运输企业安全生产管理人员…

day42 1226

作业1&#xff1a; #include <iostream>using namespace std;namespace myspace {string str; }int length(string str) {//char *p &str.at(0);const char *p str.data();int count 0;while (*p ! 0) {p;count;}return count; } int main() {getline(cin,myspac…