Vue 实现 Excel 导入功能
在实际开发中导入功能是非常常见的,导入功能前端并不难,难的是后端字段的对应,主要处理在后端。我们只需要用饿了吗ui upload上传组件封装一层就可以了,主要起到上传文件作用。通过按钮跳转到页面,携带参数,下载excel模板。导入页面接受参数区分从哪一个页面过来。页面EXCEL导入成功就回到上一级页面,刷新数据。失败动画效果,把失败数据原因用表格展现出来。
前言
-
在实际开发中导入功能是非常常见的,导入功能前端并不难,难的是后端字段的对应,主要处理在后端。
-
我们只需要用饿了吗ui upload上传组件封装一层就可以了,主要起到上传文件作用。
-
通过按钮跳转到页面,携带参数,下载excel模板。导入页面接受参数区分从哪一个页面过来。
-
页面EXCEL导入成功就回到上一级页面,刷新数据。失败动画效果,把失败数据原因用表格展现出来。
代码实现
1.整体代码
<template>
<div class="center">
<!-- drag 是否启用拖拽上传 -->
<!-- multiple 是否支持多选文件 -->
<!-- action 必要属性,上传文件的地址,可以不给,但必须要有,不给就i调接口上传 -->
<!-- :http-request="uploadFile"这个是就上传文件的方法,把上传的接口写在这个方法里 -->
<!-- :limit="fileLimit"上传文件个数的限制 -->
<!-- :on-remove="handleRemove"//上传之后,移除的事件 -->
<!-- :file-list="fileList"//上传了那些文件的列表 -->
<!-- :on-exceed="handleExceed"//超出上传文件个数的错误回调 -->
<!-- :before-upload="beforeUpload"//文件通过接口上传之前,一般用来判断规则, -->
<!-- :show-file-list="false"//是否用默认文件列表显示 -->
<!-- :headers="headers"//上传文件的请求头 -->
<div class="upload" :class="{ active: blureimport }">
<div class="btn-box">
<!-- 问号组件 主页文章有 我是全局在main.js挂载 全局组件直接用 -->
<UsageTooltip data="bottom">
<H1>Excel参考模板下载</H1>
<p style="">
<i
class="el-icon-warning-outline"
style="font-size: 15px; background-color: red; border-radius: 50%"
></i
>请严格按照excel填写数据
</p>
<p>
填写完数据可以将excel文件推入指定区域或点击区域选择需要导入的excel文件
</p>
</UsageTooltip>
<el-button type="success" @click="downloadTemplate"
>Excel模板下载</el-button
>
<!-- 后期要删掉 方便看效果 又接口失败开启事件和赋值 -->
<el-button type="success" @click="qin">失败样式开关</el-button>
</div>
<!-- :file-list="fileList" 没用到 -->
<el-upload
drag
action
multiple
:http-request="uploadFile"
ref="upload"
:limit="fileLimit"
:on-remove="handleRemove"
:on-exceed="handleExceed"
:before-upload="beforeUpload"
:show-file-list="true"
:headers="headers"
>
<i class="el-icon-upload"></i>
<p>点击上传,或将文件拖到此处</p>
</el-upload>
</div>
<div class="table" :class="{ fade: blureimport }" v-if="blureimport">
<el-table
:data="tableData"
border
size="mini"
stripe
height="100%"
style="width: 100%"
>
<el-table-column label="序号" width="70" align="center">
<template slot-scope="scope">
<!-- {{ (pageInfo.pageNo - 1) * pageInfo.pageSize + scope.$index + 1 }}
-- -->
{{ scope.$index }}
</template>
</el-table-column>
<el-table-column
prop="data"
align="center"
label="合同名称"
width="200"
>
</el-table-column>
<el-table-column
prop="data"
align="center"
label="合同类型"
width="150"
>
</el-table-column>
<el-table-column
prop="data"
align="center"
label="合同编号"
width="200"
>
</el-table-column>
<el-table-column prop="data" align="center" label="负责人" width="150">
</el-table-column>
<el-table-column
prop="data"
align="center"
label="归属部门"
width="150"
>
</el-table-column>
<el-table-column
prop="data"
align="center"
label="导入状态"
width="180"
>
</el-table-column>
<el-table-column
prop="data"
align="center"
label="失败原因"
width="280"
>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script>
// 导入上传接口
export default {
name: "import",
data() {
return {
// 附件数量限制
fileLimit: 10,
//上传后的文件列表
fileList: [],
//请求头
headers: { "Content-Type": "multipart/form-data" },
// 允许的文件类型
fileType: ["xls", "xlsx"],
// 运行上传文件大小,单位 M
fileSize: 10,
// 失败样式开关
blureimport: false,
// 表格数据
tableData: [
{
data: "风过无痕",
},
{
data: "风过无痕",
},
{
data: "风过无痕",
},
{
data: "风过无痕",
},
{
data: "风过无痕",
},
{
data: "风过无痕",
},
{
data: "风过无痕",
},
{
data: "风过无痕",
},
{
data: "风过无痕",
},
{
data: "风过无痕",
},
{
data: "风过无痕",
},
{
data: "风过无痕",
},
{
data: "风过无痕",
},
{
data: "风过无痕",
},
{
data: "风过无痕",
},
],
};
},
methods: {
//模板下载
downloadTemplate() {
let type = this.$route.query.type;
console.log(type);
// 创建a标签
let a = document.createElement("a");
// 根据不同的页面参数下载不同模板
if (type == "personnel") {
// 例子
// 模板位置 最好不要出现中文
a.href = "./static/a.xlsx";
// 下载模板名称
a.download = "人事档案数据.xlsx";
} else if (type == "contract") {
// 模板位置 最好不要出现中文
a.href = "";
// 下载模板名称
a.download = "";
}
a.style.display = "none";
document.body.appendChild(a);
a.click();
a.remove();
},
//上传文件之前
beforeUpload(file) {
if (file.type != "" || file.type != null || file.type != undefined) {
//截取文件的后缀,判断文件类型
const FileExt = file.name.replace(/.+\./, "").toLowerCase();
//计算文件的大小
const isLt5M = file.size / 1024 / 1024 < 50; //这里做文件大小限制
// console.log(1);
//如果大于50M
if (!isLt5M) {
this.$showMessage("上传文件大小不能超过 10MB!");
return false;
}
//如果文件类型不在允许上传的范围内
if (this.fileType.includes(FileExt)) {
return true;
} else {
this.$message.error("上传文件格式不正确!");
return false;
}
}
},
//超出文件个数的回调
handleExceed() {
this.$message({
type: "warning",
message: "超出最大上传文件数量的限制!",
});
return;
},
//上传文件的事件
uploadFile(item) {},
//上传了的文件给移除的事件,由于我没有用到默认的展示,所以没有用到
handleRemove() {},
//上传了的文件给移除的事件,由于我没有用到默认的展示,所以没有用到
async handleRemove() {},
async uploadFile(item) {
// this.$showMessage("文件上传中........");
//上传文件的需要formdata类型;所以要转
// 创建formDatas类型
let formDatas = new FormData();
formDatas.append("uploadFile", item.file);
console.log("文件是", item.file);
// console.log("文件是 " + item.file.name);
// 判断 根据不同页面参数调用不同的接口
let type = this.$route.query.type;
if (type == "personnel") {
console.log("执行了");
eqbilkimport(formDatas)
.then((res) => {
console.log("成功打印", res);
// 导入成功退回导入之前页面 并且刷新
this.$route.go(-1);
})
.catch((err) => {
console.log("失败打印", err);
// 把导入失败的数据赋值给表格数组
// 开启失败之后的动画和淡入淡出效果
this.blureimport = true;
});
} else if (type == "contract") {
// 一样不同页面
}
},
// 模拟导入失败的样式变化
qin() {
console.log("失败了");
this.blureimport = true;
},
},
};
</script>
<style lang="scss" scoped>
.center {
height: 827px;
background-color: #fff;
position: relative;
// 正常屏幕下的上下间距
margin-top: 35px;
margin-bottom: 25px;
// 适配谷歌火狐,没有书签栏的上下边距
@media screen and (min-height: 950px) and (max-height: 990px) {
margin-top: 50px;
margin-bottom: 40px;
}
// 适配浏览器全屏模式下的上下边距
@media screen and (min-height: 1070px) {
margin-top: 100px;
margin-bottom: 100px;
}
.upload {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 720px;
display: flex;
.btn-box {
width: 360px;
height: 180px;
box-sizing: border-box;
border: 1px dashed #d9d9d9;
display: flex;
align-items: center;
justify-content: center;
::v-deep .el-tooltip {
color: rgb(88, 87, 81) !important;
font-size: 25px !important;
margin-right: 10px;
}
}
}
.active {
left: 35%;
display: block;
transition: left 2s, transform 3s;
}
.table {
width: 900px;
height: 600px;
background-color: skyblue;
position: fixed;
right: 100px;
top: 50%;
transform: translateY(-50%);
}
.fade {
animation-name: fade;
animation-duration: 4s;
/* Safari and Chrome */
-webkit-animation-name: fade;
-webkit-animation-duration: 4s;
@-webkit-keyframes fade {
from {
opacity: 0.1;
}
to {
opacity: 1;
}
}
@keyframes fade {
from {
opacity: 0.1;
}
to {
opacity: 1;
}
}
}
}
</style>
2.按钮带参数跳转
<el-button
type="success"
plain
icon="el-icon-upload2"
size="mini"
style="float: right"
@click="$router.push({ path: '/import', query: { type: 'contract' } })"
>导入数据</el-button
>
3.Excel 模板下载
把需要下载的EXCEL模板放到public文件夹/static/a.xlsx
3.全局提示组件 - 主页文章有(全局导入)
4.导入失败结构动画效果,数据失败原因淡入效果-动态绑定class类实现,代码有注释
复制细节-直接复制需要注意细节
1.我使用的vue-element-admin 路由是放在前端的
// 数据导入页面
{
path: '/import',
component: Layout,
children: [
{
name: 'import',
path:'',
component: () => import('@/views/import/index'),
hidden: true,
meta: {
title: '导入设备'
}
}
]
},
2.全局组件的问号提示 - 主页文章有,全局组件注册方式
3.Excel 模板下载注意放的位置和命名(不要出现中文名),代码中有注释
// 模板位置 最好不要出现中文
a.href = "./static/a.xlsx";
// 下载模板名称
a.download = "人事档案数据.xlsx";
4.效果图-不是动态的
经过这一趟流程下来相信你也对 Vue 实现 Excel 导入功能 有了初步的深刻印象,但在实际开发中我 们遇到的情况肯定是不一样的,所以我们要理解它的原理,万变不离其宗。加油,打工人!
什么不足的地方请大家指出谢谢 -- 風过无痕
更多推荐
所有评论(0)