提交 cd3f87ea authored 作者: 龙菲's avatar 龙菲

批量导入

上级 5da5ee84
...@@ -63,21 +63,25 @@ export function uploadV1(data) { ...@@ -63,21 +63,25 @@ export function uploadV1(data) {
* 批量上传文件 * 批量上传文件
* @param data formData类型 * 参数1 type:导入数据类别(biz_cultural_relic、biz_exhibition二选一) 参数2 zipFile:zip压缩文件 * @param data formData类型 * 参数1 type:导入数据类别(biz_cultural_relic、biz_exhibition二选一) 参数2 zipFile:zip压缩文件
* @param callback 用于获取上传进度 * @param callback 用于获取上传进度
* @param cancelCallBack 用于取消上传
* @returns {Promise} * @returns {Promise}
*/ */
export function importZip(data, callback) { let CancelToken = axios.CancelToken;
export function importZip(data, callback, cancelCallBack) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios.post(importZipUrl, data, { axios.post(importZipUrl, data, {
headers: { headers: {
'Content-Type': 'multipart/form-data;boundary = ' + new Date().getTime(), 'Content-Type': 'multipart/form-data;boundary = ' + new Date().getTime(),
'authorization': getToken(), 'authorization': getToken(),
}, },
onUploadProgress: progressEvent => { onUploadProgress(progressEvent) {
// 原生获取上传进度的事件
if (progressEvent.lengthComputable) { if (progressEvent.lengthComputable) {
callback && callback(progressEvent); callback(progressEvent);
} }
}, },
cancelToken: new CancelToken(function executor(c) {
cancelCallBack(c)
})
}).then(response => { }).then(response => {
resolve(response.data) resolve(response.data)
}).catch(error => { }).catch(error => {
......
<template>
<el-dialog
:visible="dialogVisible"
width="50%"
style="height: 98%"
:before-close="handleClose"
top="5vh"
lock-scroll
>
<div class="title" slot="title">
<div class="divider"></div>
<div class="label">
<span style="margin-right: 10px">批量上传文物</span>
<el-button
type="text"
icon="el-icon-download"
@click="handleDownloadTemplate"
style="padding: 0"
>下载模板文件</el-button
>
</div>
</div>
<div class="dialog-content">
<el-upload
class="upload-area"
drag
action="#"
accept=".zip"
:auto-upload="false"
:show-file-list="false"
:on-change="handleChange"
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只能上传.zip文件</div>
</el-upload>
<div class="upload-progress" v-if="isUpLoading">
<div class="subtitle">
<div class="divider"></div>
<div class="label">当前上传列表</div>
</div>
<!-- <el-progress
:percentage="percentState"
:status="progressStatus"
></el-progress> -->
<!-- <el-table>
<el-table-column prop="fileName" label="文件名"> </el-table-column>
<el-table-column prop="size" label="文件大小"> </el-table-column>
<el-table-column prop="progress" label="进度">
<template slot-scope="scope">
<i class="el-icon-time"></i>
<span style="margin-left: 10px">{{ scope.row.date }}</span>
</template>
</el-table-column>
<el-table-column prop="operation" label="操作"> </el-table-column>
</el-table> -->
</div>
<div class="upload-records">
<div class="subtitle">
<div class="divider"></div>
<div class="label">上传历史记录</div>
</div>
<TablePage :data="list.records" :tableTitle="tableTitle" />
</div>
<div class="dialog-footer">
<el-button type="primary" @click.native="handleClose">关闭</el-button>
</div>
</div>
</el-dialog>
</template>
<script>
import TablePage from "@/components/Table/TablePage";
import { getImportListPage } from "@/api/culturalRelic";
import { importZip } from "@/utils/file";
export default {
name: "MultiUploadDialog",
components: {
TablePage,
},
props: {
visible: {
type: Boolean,
default: false,
},
},
watch: {
visible: {
handler: function (value) {
this.dialogVisible = value;
},
deep: true,
immediate: true,
},
},
data() {
return {
dialogVisible: false,
isUpLoading: false,
percentState: 0,
list: {
records: [],
current: 1,
size: 10,
},
tableTitle: [
{
prop: "createTime",
label: "导入时间",
columnAlign: "center",
},
{
prop: "batchNum",
label: "导入批次",
columnAlign: "center",
},
{
prop: "fileName",
label: "文件名称",
columnAlign: "center",
},
{
prop: "fileSize",
label: "文件大小",
columnAlign: "center",
},
{
prop: "remark",
label: "备注",
columnAlign: "center",
},
],
progressStatus: null,
};
},
mounted() {
this.loadData();
},
methods: {
// 取消编辑
cancelForm() {
this.handleClose();
},
async loadData() {
const params = {
limit: this.list.size,
page: this.list.current,
};
let res = await getImportListPage(params);
this.list = res.data;
},
handleClose(done) {
let title = this.isUpLoading
? "当前有上传任务,是否后台继续上传?"
: "确认关闭?";
let confirmButtonText = this.isUpLoading ? "是" : "确定";
let cancelButtonText = this.isUpLoading ? "取消上传" : "取消";
let that = this;
this.$confirm(title, "提示", {
confirmButtonText,
cancelButtonText,
type: "warning",
})
.then(() => {
// 点击继续后台上传
if (that.isUpLoading) {
this.$message.warning("文件仍在上传,请勿关闭窗口!");
}
this.dialogVisible = false;
that.$emit("handleClose");
})
.catch(() => {
// 点击取消上传
if (that.isUpLoading) {
// TODO:取消上传
this.$message.info("已取消上传!");
}
});
},
handleDownloadTemplate() {
let a = document.createElement("a");
a.href = "./static/upload_cr_template.zip";
a.download = "批量上传文物模板.zip";
a.style.display = "none";
document.body.appendChild(a);
a.click();
a.remove();
},
async handleChange(file, fileList) {
console.log("handleChange", file, fileList);
if (file.status == "ready") {
let { name, size, raw } = file;
size = size / 1024 / 1024 / 100;
console.log('size',size);
// let fileItem = {
// name,
// size,
// };
// this.fileList.push(file);
// this.isUpLoading = true;
// let formData = new FormData();
// formData.append("type", "biz_cultural_relic");
// formData.append("zipFile", file.raw);
// let res = await importZip(formData, this.updateProgress);
// if (res.code == 0) {
// this.percentState = 100;
// this.$message.success("上传成功!");
// this.progressStatus = "success";
// this.isUpLoading = false;
// let index = this.fileList.indexOf(file);
// this.fileList.splice(index, 1); //上传成功后删除当前文件
// } else {
// this.progressStatus = "warning";
// this.$message.error(res.msg);
// }
}
},
updateProgress(e) {
//e为回调回来的参数 通过进行和total的值来进行进度
this.percentState = parseInt((e.loaded / e.total) * 100) - 1;
if (this.percentState == 99) {
// this.$message.success("上传成功!");
// this.isUpLoading = false;
// this.uploadStatus = "success";
}
},
},
};
</script>
<style lang='scss' scoped>
.title {
.label {
font-weight: bold;
}
}
.subtitle {
display: flex;
margin-bottom: 16px;
.divider {
width: 8px;
border-left: 4px solid #409eff;
margin-right: 8px;
}
.label {
font-weight: bold;
}
}
.dialog-content {
padding: 0 32px;
display: flex;
flex-direction: column;
.upload-area {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
margin-bottom: 30px;
}
.upload-progress {
margin-bottom: 30px;
}
.upload-records {
margin-bottom: 30px;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
}
}
.el-dialog__body {
padding: 0 20px 30px 20px;
}
</style>
\ No newline at end of file
<template>
<el-dialog
:visible="dialogVisible"
width="50%"
style="height: 98%"
:before-close="handleClose"
top="5vh"
lock-scroll
>
<div class="title" slot="title">
<div class="divider"></div>
<span class="label">上传列表</span>
</div>
<div class="upload-progress">
<el-table :data="filesList" fit>
<el-table-column prop="name" label="文件名"> </el-table-column>
<el-table-column prop="size" label="文件大小">
<template slot-scope="scope">
{{ getSize(scope.row.size) }}
</template>
</el-table-column>
<el-table-column prop="progress" label="进度" width="300">
<template slot-scope="scope">
<el-progress :percentage="scope.row.percent"></el-progress>
</template>
</el-table-column>
<el-table-column prop="operation" label="操作" width="100">
<el-button
type="text"
size="48"
icon="el-icon-circle-close"
@click.native="handleClick(scope.row)"
></el-button>
</el-table-column>
</el-table>
</div>
<div class="dialog-footer">
<el-button type="primary" @click.native="handleClose">关闭</el-button>
</div>
</el-dialog>
</template>
<script>
import TablePage from "@/components/Table/TablePage";
import { getImportListPage } from "@/api/culturalRelic";
export default {
name: "UploadListDialog",
components: {
TablePage,
},
props: {
visible: {
type: Boolean,
default: false,
},
filesList: {
type: Array,
default: () => [],
},
},
watch: {
visible: {
handler: function (value) {
this.dialogVisible = value;
},
deep: true,
immediate: true,
},
filesList(value) {
console.log("value", value);
},
},
data() {
return {
dialogVisible: false,
isUpLoading: false,
percentState: 0,
list: {
records: [],
current: 1,
size: 10,
},
progressStatus: null,
};
},
computed: {
getSize(size) {
return (size) => {
return (size / 1024 / 1024).toFixed(2) + "M"; //1M=1024Kb=1024*1024byte
};
},
},
mounted() {
// this.loadData();
},
methods: {
// 取消编辑
cancelForm() {
this.handleClose();
},
handleClick(item) {
console.log("item", item);
},
handleClose(done) {
this.$emit("handleClose");
// let title = this.isUpLoading
// ? "当前有上传任务,是否取消上传"
// : "确认关闭?";
// let confirmButtonText = this.isUpLoading ? "关闭并取消上传" : "确定";
// let cancelButtonText = this.isUpLoading ? "否" : "取消";
// let that = this;
// this.$confirm(title, "提示", {
// confirmButtonText,
// cancelButtonText,
// type: "warning",
// })
// .then(() => {
// // 点击取消上传
// if (that.isUpLoading) {
// // TODO:取消上传
// this.$message.info("已取消上传!");
// }
// this.dialogVisible = false;
// that.$emit("handleClose");
// })
// .catch(() => {
// console.log('用户取消操作');
// });
},
},
};
</script>
<style lang='scss' scoped>
.title {
display: flex;
.divider {
width: 8px;
height: 16px;
border-left: 4px solid #409eff;
margin-right: 8px;
}
.label {
font-weight: bold;
}
}
.dialog-content {
padding: 0 32px;
display: flex;
flex-direction: column;
.upload-area {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
margin-bottom: 30px;
}
.upload-progress {
margin-bottom: 30px;
}
.upload-records {
margin-bottom: 30px;
}
}
.dialog-footer {
margin-top: 30px;
display: flex;
justify-content: flex-end;
}
.el-dialog__body {
padding: 0 20px 30px 20px;
}
</style>
\ No newline at end of file
...@@ -3,12 +3,32 @@ ...@@ -3,12 +3,32 @@
<div class="top-bar"> <div class="top-bar">
<SearchBar :config="searchConfig" @search="search" @reset="reset" /> <SearchBar :config="searchConfig" @search="search" @reset="reset" />
<div class="tools"> <div class="tools">
<el-upload
class="upload-button"
:action="importZipUrl"
:headers="headers"
accept=".zip"
:show-file-list="false"
:on-exceed="handleExceed"
:before-upload="handleUpload"
:on-success="handleSuccess"
multiple
>
<el-button
type="primary"
@click.native="handleOperation({ type: 'multiAdd' })"
icon="el-icon-upload"
>
批量导入</el-button
>
</el-upload>
<el-button <el-button
type="primary" type="primary"
@click.native="handleOperation({ type: 'multiAdd' })" @click.native="handleOperation({ type: 'downloadTemplate' })"
icon="el-icon-upload" icon="el-icon-download"
> >
批量导入</el-button 下载导入模板</el-button
> >
<el-button <el-button
type="primary" type="primary"
...@@ -82,8 +102,9 @@ ...@@ -82,8 +102,9 @@
@handleClose="handleEditClose" @handleClose="handleEditClose"
@refresh="loadData" @refresh="loadData"
/> />
<MultiUploadDialog <UploadListDialog
:visible="multiUploadVisible" :visible="multiUploadVisible"
:filesList="filesList"
@handleClose="handleMultiUploadClose" @handleClose="handleMultiUploadClose"
/> />
</div> </div>
...@@ -101,22 +122,18 @@ import { ...@@ -101,22 +122,18 @@ import {
editCulturalRelic, editCulturalRelic,
} from "@/api/culturalRelic"; } from "@/api/culturalRelic";
import InfoEditDialog from "./components/InfoEditDialog"; import InfoEditDialog from "./components/InfoEditDialog";
import MultiUploadDialog from "./components/MultiUploadDialog"; import UploadListDialog from "./components/UploadListDialog";
import { mapGetters } from "vuex"; import { mapGetters } from "vuex";
import { importZip } from "@/utils/file";
import { getToken } from "@/utils/auth";
export default { export default {
components: { components: {
TablePage, TablePage,
TableOperation, TableOperation,
InfoEditDialog, InfoEditDialog,
SearchBar, SearchBar,
MultiUploadDialog, UploadListDialog,
}, },
// dicts: [
// // "cultural_relic_years",
// "culturalRelicLevel",
// // "cultural_relic_texture",
// "culturalRelicType",
// ],
data() { data() {
return { return {
list: { list: {
...@@ -158,7 +175,7 @@ export default { ...@@ -158,7 +175,7 @@ export default {
}, },
], ],
editVisible: false, //编辑 editVisible: false, //编辑
multiUploadVisible: false, //批量上传
isAdd: true, isAdd: true,
form: { form: {
name: "", //名称 name: "", //名称
...@@ -187,8 +204,35 @@ export default { ...@@ -187,8 +204,35 @@ export default {
loading: false, loading: false,
imgViewerVisible: false, imgViewerVisible: false,
imgList: [], imgList: [],
importZipUrl: process.env.VUE_APP_BASE_API + "/bizImport/importZip",
headers: {
authorization: getToken(),
},
multiUploadVisible: false, //控制批量上传弹窗显示
filesList: [], //上传当中的文件队列
uploadCount: 0, //处于上传中的文件数量,当等于fileList的时候就关闭弹窗,请求完毕一个就++
cancelUploadArr: [], //保存每个文件上传接口对应的取消请求的函数[fn,fn,fn...],点叉叉关闭弹窗就遍历这个全部执行一遍就取消了所以请求,(有那么点点发布订阅的思想,关闭弹窗,通知取消请求,我这里是全部取消,也可以根据需要,取消某一个请求,思想都一样的)
}; };
}, },
//watch部分
watch: {
//监听弹窗变化
multiUploadVisible(val) {
//弹窗关闭记得清空,开启执行批量上传
if (val) {
for (let i = 0; i < this.filesList.length; i++) {
this.uploadSelf(this.filesList[i].file, i); //弹窗显示的时候,就根据文件队列的数量调用上传接口
}
} else {
//弹窗关闭,记得还原数据到初始位置
this.filesList = [];
this.uploadCount = 0;
this.cancelUploadArr = [];
console.log(this.filesList, this.uploadCount);
}
},
},
computed: { computed: {
tableTitle() { tableTitle() {
return title; return title;
...@@ -273,11 +317,123 @@ export default { ...@@ -273,11 +317,123 @@ export default {
break; break;
case "multiAdd": case "multiAdd":
// debugger // debugger
this.multiUploadVisible = true; // this.multiUploadVisible = true;
console.log('this.multiUploadVisible',this.multiUploadVisible); // console.log("this.multiUploadVisible", this.multiUploadVisible);
break;
case "downloadTemplate":
this.handleDownloadTemplate();
break; break;
} }
}, },
//下载批量导入模板
handleDownloadTemplate() {
let a = document.createElement("a");
a.href = "./static/文物导入模板及操作说明.zip";
a.download = "文物导入模板及操作说明.zip";
a.style.display = "none";
document.body.appendChild(a);
a.click();
a.remove();
},
// 文件个数超出
handleExceed() {
this.$message.error(`超出上传文件个数,请删除以后再上传!`);
},
handleUpload(file) {
this.multiUploadVisible = true; //显示弹窗
this.filesList.push({
file,
name: file.name,
size: file.size,
status: null,
desc: null,
});
return false; //阻止自动上传
},
uploadSelf(file, index) {
let formData = new FormData();
formData.append("type", "biz_cultural_relic");
formData.append("zipFile", file);
importZip(
formData,
(progressEvent) => this.uploadUnderWayCallback(progressEvent, index),
(c) => this.cancelCallBack(c, index)
).then((res) => {
if (res.code == 0) {
this.$set(this.filesList[index], "status", "success");
this.$set(this.filesList[index], "desc", "上传成功");
} else {
this.$set(this.filesList[index], "status", "warning");
this.$set(this.filesList[index], "desc", "上传失败" + res.msg);
this.$message.error("上传失败:" + res.msg);
}
});
},
// 文件上传进度回调
uploadUnderWayCallback(progressEvent, index) {
let completeVal = (progressEvent.loaded / progressEvent.total) * 100 || 0; //处理成组件库进度组件需要的格式
this.$set(this.filesList[index], "percent", Math.floor(completeVal)); //直接改变数组某一项不是响应式的,因此我们需要用到这个api,将其响应式化,添加到数组中
},
// 文件取消回调
cancelCallBack(c, index) {
this.$set(this.cancelUploadArr, index, c); //添加取消队列中,关闭弹窗批量取消
this.uploadCount = 0;
},
handleMultiUploadClose() {
// 文件列表中如果Status为null,则代表有仍在上传中
let isUpLoading = false;
this.filesList.map((item) => {
if (item.status == null) {
isUpLoading = true;
return;
}
});
// let isUpLoading = this.uploadCount != this.filesList.length;
// console.log("this.uploadCount", this.uploadCount);
// return
let title = isUpLoading ? "当前有上传任务,是否取消上传" : "确认关闭?";
let confirmButtonText = isUpLoading ? "关闭并取消上传" : "确定";
let cancelButtonText = isUpLoading ? "否" : "取消";
let that = this;
this.$confirm(title, "提示", {
confirmButtonText,
cancelButtonText,
type: "warning",
})
.then(() => {
// 点击取消上传
if (that.isUpLoading) {
this.cancelUploadArr.forEach((cancelCallBack) => cancelCallBack()); //批量取消上传
this.$message.warning("已取消上传!");
}
this.multiUploadVisible = false; //最后关闭
that.$emit("handleClose");
})
.catch(() => {
console.log("用户取消操作");
});
// // 取消请求
// if (this.uploadCount != this.filesList.length) {
// this.cancelUploadArr.forEach((cancelCallBack) => cancelCallBack()); //批量取消上传
// this.$Message.warning("取消上传!");
// }
console.log("父组件关闭被触发");
},
handleSuccess(res) {
res.Success && this.$Message.success("上传成功"); //提示
this.processModal = false; //成功后关闭弹窗
this.filesList = [];
},
// 关闭预览图片 // 关闭预览图片
closeImgViewer() { closeImgViewer() {
this.imgViewerVisible = false; this.imgViewerVisible = false;
...@@ -346,10 +502,6 @@ export default { ...@@ -346,10 +502,6 @@ export default {
status: 0, status: 0,
}; };
}, },
handleMultiUploadClose() {
this.multiUploadVisible = false;
console.log('父组件关闭被触发');
},
}, },
}; };
</script> </script>
...@@ -360,6 +512,13 @@ export default { ...@@ -360,6 +512,13 @@ export default {
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 10px; margin-bottom: 10px;
.tools {
display: flex;
margin-bottom: 20px;
.upload-button {
margin-right: 10px;
}
}
} }
.pagination { .pagination {
margin: 16px; margin: 16px;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论