「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」。
vue项目开发中经常会用到导入文件功能,我们公司的项目中,文件导入统一设计的,如下图,在这个弹框中,上传分为3步,第一步:下载对应的模板,填入数据,选择对应的文件。第二步:上传文件,后台验证数据的合法性。第三步:下载错误信息。我们一起看看吧!
封装组件
ele的分步骤组件(<el-steps)来布局,默认如上图,点击选取文件之后,文件的列表就出现在按钮的位置,此处只能一次上传一个文件,这时候第二步的导入文件按钮就会高亮,点导入文件,就可以上传了,在第3步会展示出导入成功和导入失败的数量。
<template>
<div class="import-excel">
<el-steps direction="vertical" :active="uploadStep">
<el-step></el-step>
<el-step></el-step>
<el-step></el-step>
</el-steps>
<div class="excel-con">
<div class="step-first">
<div class="name">选取文件</div>
<div class="desc">如果您是初次使用,建议您<span class="down" @click="exportInsertTable"> 下载模板 </span>进行查看。</div>
<div class="select">
<el-upload
:disabled="disabled"
action=""
:on-remove="handleRemove"
:file-list="fileList"
:auto-upload="false"
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
:limit="1"
:on-change="onChange"
>
<el-button type="primary" size="small" class="select-btn" plain v-if="fileList.length === 0" :disabled="disabled">点击选取</el-button>
</el-upload>
</div>
</div>
<div class="step-next">
<div class="name">导入文件</div>
<div class="desc">等待文件导入完毕后自动检查数据</div>
<el-button type="primary" size="small" class="select-btn" plain v-if="fileList.length !== 0 && uploadStep === 2" :loading="importBtn" @click="importExcel">导入文件</el-button>
</div>
<div class="step-finish">
<div class="name">完成</div>
<div class="desc" v-if="uploadStep === 3">
导入已完成, 共导入成功<span class="green-color">{{ successCount }}</span>条,
导入失败<span class="red-color">{{ failedCount }}</span>条。
<div v-if="failedCount > 0">
<span class="grey-color">具体结果可
<span class="blue-color" @click="onerrorTemplate()">下载错误日志</span> 进行查看</span>
</div>
</div>
</div>
</div>
</div>
</template>
ele的上传组件(el-upload)组件属性如下
| 参数 | 说明 | 类型 | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| action | 必选参数,上传的地址 | string | — | ||||||||||||
| headers | 设置上传的请求头部 | — | |||||||||||||
| multiple | 是否支持多选文件 | boolean | — | ||||||||||||
| data | 上传时附带的额外参数 | object | — | ||||||||||||
| name | 上传的文件字段名 | — | file | ||||||||||||
| show-file-list | 是否显示已上传文件列表 | boolean | — | ||||||||||||
| drag | 是否启用拖拽上传 | — | false | accept | 接受上传的文件类型(thumbnail-mode 模式下此参数无效) | string | — | — | on-preview | 点击文件列表中已上传的文件时的钩子 | function(file) | — | — | ||
| on-remove | 文件列表移除文件时的钩子 | function(file, fileList) | — | — | |||||||||||
| on-success | 文件上传成功时的钩子 | function(response, file, fileList) | — | — | |||||||||||
| on-error | 文件上传失败时的钩子 | function(err, file, fileList) | — | — | |||||||||||
| on-progress | 文件上传时的钩子 | function(event, file, fileList) | — | — | |||||||||||
| on-change | 文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用 | function(file, fileList) | — | — | |||||||||||
| before-upload | 上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传。 | function(file) | — | — | |||||||||||
| before-remove | 删除文件之前的钩子,参数为上传的文件和文件列表,若返回 false 或者返回 Promise 且被 reject,则停止删除。 | function(file, fileList) | — | — | |||||||||||
| list-type | 文件列表的类型 | string | text/picture/picture-card | text | |||||||||||
| auto-upload | 是否在选取文件后立即进行上传 | boolean | — | true | |||||||||||
| file-list | 上传的文件列表, 例如: [{name: 'food.jpg', url: 'xxx.cdn.com/xxx.jpg'}] | array | — | [] | |||||||||||
| http-request | 覆盖默认的上传行为,可以自定义上传的实现 | function | — | — | disabled | 是否禁用 | boolean | — | false | ||||||
| limit | 最大允许上传个数 | number | — | — | |||||||||||
| on-exceed | 文件超出个数限制时的钩子 | function(files, fileList) | — |
<script>
import {
downTemp,// 公共下载模板
importTeacher,// 导入
exportExcelTeacher,// 下载错误模板
} from '@/utils/api.js';
export default {
name: "ImportExport",
props:{
flagName: { // 页面标识
type: String,
default: ''
},
fileName: { // 传参
type: String,
default: ''
},
// 业务需要传过来的参数放这里
importData: {
type: Object,
default: () => {}
},
disabled: {
type: Boolean,
default: false,
}
},
data(){
return {
baseFile: process.env.VUE_APP_FILE_URL,
fileList: [],
uploadStep: 1,
importBtn: false,
successCount: 0,
failedCount: 0,
key: '',
}
},
computed:{
schoolNum() {
return this.$store.state.user.schoolNum;
},
userNum() {
return this.$store.state.user.userInfo.userNum;
},
},
mounted() {
let map = new Map([
['teacher',[importTeacher, downTemp, exportExcelTeacher]],
]);
this.checkImportExcel = map.get(this.flagName)[0];// 导入
this.downExcel = map.get(this.flagName)[1];// 下载模板
this.exportErrorData = map.get(this.flagName)[2];// 导出错误
},
methods: {
// 移除文件
handleRemove(file, fileList) {
this.fileList = fileList;
this.uploadStep = 1;
this.importBtn = false;
},
// 修改文件
onChange(file, fileList) {
this.fileList = fileList;
this.uploadStep = 2;
},
// 导入
importExcel() {
const file = this.fileList[0].raw;
this.importBtn = true;
if (file.size < 10 * 1024 * 1024) {
let params = new FormData();
params.append('fileName', file);
params.append('schoolNum', this.schoolNum);
params.append('userNum', this.userNum);
this.$postForm(this.checkImportExcel, params).then((res) => {
this.importBtn = false;
if (res.status == 200){
this.uploadStep = 3;
this.successCount = res.result.successCount;
this.failedCount = res.result.failedCount;
this.key = res.result.key;
}
})
} else {
this.importBtn = false;
this.$message({
message: '请上传10M以内的文件',
type: 'warning'
})
}
},
// 导出错误数据
onerrorTemplate() {
let postData = {
schoolNum: this.$store.state.user.schoolNum,
number: this.$store.state.user.userInfo.userNum,
Authorization: this.$store.state.user.userToken
};
doExportExcel(this.exportErrorData, postData);
},
// 下载模板
exportInsertTable() {
doExportExcel(this.downExcel, { fileName: this.fileName });
},
},
}
</script>
封装好组件之后,只需要在需要导入的页面引入组件,传参进来,就可以轻松使用了,解决了很多的时间。记录一下,温故而知新