406 lines
10 KiB
Vue
406 lines
10 KiB
Vue
<template>
|
|
<div>
|
|
<el-dialog
|
|
:title="title"
|
|
:visible.sync="visible"
|
|
width="550px"
|
|
center
|
|
append-to-body
|
|
@open="handleDialogOpen"
|
|
@close="handleDialogClose"
|
|
:close-on-click-modal="false"
|
|
:close-on-press-escape="false"
|
|
custom-class="import-dialog-wrapper"
|
|
>
|
|
<div v-show="isUploading" class="import-loading-overlay">
|
|
<i class="el-icon-loading"></i>
|
|
<p>正在导入中,请稍候...</p>
|
|
</div>
|
|
|
|
<el-form label-position="top" size="medium">
|
|
<el-form-item label="导入说明">
|
|
<div class="scene-tips">
|
|
<p v-for="item in sceneTips" :key="item">{{ item }}</p>
|
|
</div>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="选择文件">
|
|
<el-upload
|
|
ref="upload"
|
|
:limit="1"
|
|
accept=".xlsx, .xls"
|
|
:headers="headers"
|
|
:action="uploadUrl"
|
|
:disabled="isUploading"
|
|
:on-progress="handleFileUploadProgress"
|
|
:on-success="handleFileSuccess"
|
|
:on-error="handleFileError"
|
|
:on-change="handleFileChange"
|
|
:on-remove="handleFileRemove"
|
|
:auto-upload="false"
|
|
drag
|
|
>
|
|
<i class="el-icon-upload"></i>
|
|
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
|
<div class="el-upload__tip" slot="tip">
|
|
仅支持 .xls 和 .xlsx 格式,文件大小不超过 10MB
|
|
</div>
|
|
</el-upload>
|
|
</el-form-item>
|
|
|
|
<el-form-item>
|
|
<el-link type="primary" :underline="false" @click="handleDownloadTemplate">
|
|
<i class="el-icon-download"></i>
|
|
下载导入模板
|
|
</el-link>
|
|
</el-form-item>
|
|
</el-form>
|
|
|
|
<div slot="footer" class="dialog-footer">
|
|
<el-button
|
|
type="primary"
|
|
icon="el-icon-upload2"
|
|
:loading="isUploading"
|
|
:disabled="!isFileSelected"
|
|
@click="handleSubmit"
|
|
>
|
|
{{ isUploading ? '导入中...' : '开始导入' }}
|
|
</el-button>
|
|
<el-button :disabled="isUploading" icon="el-icon-close" @click="handleCancel">
|
|
取 消
|
|
</el-button>
|
|
</div>
|
|
</el-dialog>
|
|
|
|
<import-result-dialog
|
|
:visible.sync="importResultVisible"
|
|
:content="importResultContent"
|
|
title="导入结果"
|
|
@close="handleImportResultClose"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { getToken } from "@/utils/auth";
|
|
import {
|
|
getEnterpriseRelationImportStatus,
|
|
getPersonImportStatus
|
|
} from "@/api/ccdiIntermediary";
|
|
import ImportResultDialog from "@/components/ImportResultDialog.vue";
|
|
|
|
const PERSON_SCENE = "person";
|
|
const ENTERPRISE_RELATION_SCENE = "enterpriseRelation";
|
|
|
|
export default {
|
|
name: "ImportDialog",
|
|
components: { ImportResultDialog },
|
|
props: {
|
|
visible: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
title: {
|
|
type: String,
|
|
default: "数据导入"
|
|
},
|
|
scene: {
|
|
type: String,
|
|
default: PERSON_SCENE
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
headers: { Authorization: "Bearer " + getToken() },
|
|
isUploading: false,
|
|
isFileSelected: false,
|
|
importResultVisible: false,
|
|
importResultContent: "",
|
|
pollingTimer: null,
|
|
currentTaskId: null
|
|
};
|
|
},
|
|
computed: {
|
|
sceneConfig() {
|
|
if (this.scene === ENTERPRISE_RELATION_SCENE) {
|
|
return {
|
|
uploadPath: "/ccdi/intermediary/importEnterpriseRelationData",
|
|
templatePath: "ccdi/intermediary/importEnterpriseRelationTemplate",
|
|
templateName: "中介实体关联关系导入模板",
|
|
statusApi: getEnterpriseRelationImportStatus,
|
|
tips: [
|
|
"只导入中介与机构关系;",
|
|
"统一社会信用代码必须已存在于系统机构表。"
|
|
]
|
|
};
|
|
}
|
|
return {
|
|
uploadPath: "/ccdi/intermediary/importPersonData",
|
|
templatePath: "ccdi/intermediary/importPersonTemplate",
|
|
templateName: "中介和亲属信息导入模板",
|
|
statusApi: getPersonImportStatus,
|
|
tips: [
|
|
"personSubType 为字典下拉;",
|
|
"本人行 relatedNumId 为空;",
|
|
"亲属行 relatedNumId 填关联中介本人证件号码。"
|
|
]
|
|
};
|
|
},
|
|
uploadUrl() {
|
|
const baseUrl = process.env.VUE_APP_BASE_API;
|
|
return `${baseUrl}${this.sceneConfig.uploadPath}`;
|
|
},
|
|
sceneTips() {
|
|
return this.sceneConfig.tips;
|
|
}
|
|
},
|
|
methods: {
|
|
handleDialogOpen() {
|
|
this.isFileSelected = false;
|
|
},
|
|
handleDialogClose() {
|
|
if (this.$refs.upload) {
|
|
this.$refs.upload.clearFiles();
|
|
}
|
|
this.isFileSelected = false;
|
|
this.$emit("close");
|
|
},
|
|
handleCancel() {
|
|
this.$emit("update:visible", false);
|
|
},
|
|
handleDownloadTemplate() {
|
|
this.download(
|
|
this.sceneConfig.templatePath,
|
|
{},
|
|
`${this.sceneConfig.templateName}_${new Date().getTime()}.xlsx`
|
|
);
|
|
},
|
|
handleFileUploadProgress() {
|
|
this.isUploading = true;
|
|
},
|
|
handleFileChange(file, fileList) {
|
|
this.isFileSelected = fileList.length > 0;
|
|
},
|
|
handleFileRemove(file, fileList) {
|
|
this.isFileSelected = fileList.length > 0;
|
|
},
|
|
handleFileSuccess(response) {
|
|
this.isUploading = false;
|
|
|
|
if (response.code === 200 && response.data && response.data.taskId) {
|
|
const taskId = response.data.taskId;
|
|
this.currentTaskId = taskId;
|
|
|
|
this.$notify({
|
|
title: "导入任务已提交",
|
|
message: "正在后台处理中,处理完成后将通知您",
|
|
type: "info",
|
|
duration: 3000
|
|
});
|
|
|
|
this.$emit("task-created", {
|
|
scene: this.scene,
|
|
taskId,
|
|
status: "PROCESSING"
|
|
});
|
|
this.$emit("update:visible", false);
|
|
this.$emit("success", { scene: this.scene, taskId });
|
|
|
|
if (this.$refs.upload) {
|
|
this.$refs.upload.clearFiles();
|
|
}
|
|
|
|
this.startImportStatusPolling(taskId);
|
|
} else {
|
|
this.$modal.msgError(response.msg || "导入失败");
|
|
}
|
|
},
|
|
handleImportResultClose() {
|
|
this.importResultVisible = false;
|
|
this.importResultContent = "";
|
|
},
|
|
handleFileError() {
|
|
this.isUploading = false;
|
|
this.$modal.msgError("导入失败,请检查文件格式是否正确");
|
|
if (this.$refs.upload) {
|
|
this.$refs.upload.clearFiles();
|
|
}
|
|
},
|
|
handleSubmit() {
|
|
this.$emit("clear-import-history", this.scene);
|
|
this.$refs.upload.submit();
|
|
},
|
|
startImportStatusPolling(taskId) {
|
|
let pollCount = 0;
|
|
const maxPolls = 150;
|
|
|
|
this.pollingTimer = setInterval(async () => {
|
|
try {
|
|
pollCount++;
|
|
if (pollCount > maxPolls) {
|
|
clearInterval(this.pollingTimer);
|
|
this.$modal.msgWarning("导入任务处理超时,请联系管理员");
|
|
return;
|
|
}
|
|
|
|
const response = await this.sceneConfig.statusApi(taskId);
|
|
if (response.data && response.data.status !== "PROCESSING") {
|
|
clearInterval(this.pollingTimer);
|
|
this.handleImportComplete(response.data);
|
|
}
|
|
} catch (error) {
|
|
clearInterval(this.pollingTimer);
|
|
this.$modal.msgError("查询导入状态失败: " + error.message);
|
|
}
|
|
}, 2000);
|
|
},
|
|
handleImportComplete(statusResult) {
|
|
if (statusResult.status === "SUCCESS") {
|
|
this.$notify({
|
|
title: "导入完成",
|
|
message: `全部成功!共导入${statusResult.totalCount}条数据`,
|
|
type: "success",
|
|
duration: 5000
|
|
});
|
|
} else if (statusResult.failureCount > 0) {
|
|
this.$notify({
|
|
title: "导入完成",
|
|
message: `成功${statusResult.successCount}条,失败${statusResult.failureCount}条`,
|
|
type: "warning",
|
|
duration: 5000
|
|
});
|
|
}
|
|
|
|
this.$emit("import-complete", {
|
|
scene: this.scene,
|
|
taskId: statusResult.taskId,
|
|
hasFailures: statusResult.failureCount > 0,
|
|
totalCount: statusResult.totalCount,
|
|
successCount: statusResult.successCount,
|
|
failureCount: statusResult.failureCount
|
|
});
|
|
}
|
|
},
|
|
beforeDestroy() {
|
|
if (this.pollingTimer) {
|
|
clearInterval(this.pollingTimer);
|
|
this.pollingTimer = null;
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
::v-deep .el-form {
|
|
.el-form-item {
|
|
margin-bottom: 22px;
|
|
}
|
|
|
|
.el-upload {
|
|
width: 100%;
|
|
|
|
.el-upload-dragger {
|
|
width: 100% !important;
|
|
height: 140px;
|
|
box-sizing: border-box;
|
|
|
|
.el-icon-upload {
|
|
font-size: 50px;
|
|
color: #409EFF;
|
|
margin: 15px 0 10px;
|
|
}
|
|
|
|
.el-upload__text {
|
|
font-size: 14px;
|
|
color: #606266;
|
|
|
|
em {
|
|
color: #409EFF;
|
|
font-style: normal;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.el-upload__tip {
|
|
font-size: 12px;
|
|
color: #909399;
|
|
margin-top: 8px;
|
|
line-height: 1.5;
|
|
}
|
|
}
|
|
|
|
.scene-tips {
|
|
padding: 12px 14px;
|
|
background: #f8fafc;
|
|
border: 1px solid #dde3ec;
|
|
border-radius: 3px;
|
|
color: #606266;
|
|
line-height: 1.7;
|
|
|
|
p {
|
|
margin: 0;
|
|
}
|
|
}
|
|
|
|
.dialog-footer {
|
|
text-align: center;
|
|
padding: 5px 0 0;
|
|
|
|
.el-button {
|
|
min-width: 110px;
|
|
margin: 0 8px;
|
|
border-radius: 4px;
|
|
}
|
|
}
|
|
|
|
.import-loading-overlay {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background-color: rgba(255, 255, 255, 0.9);
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: 10000;
|
|
|
|
.el-icon-loading {
|
|
font-size: 48px;
|
|
color: #409EFF;
|
|
animation: rotating 2s linear infinite;
|
|
}
|
|
|
|
p {
|
|
margin-top: 15px;
|
|
font-size: 14px;
|
|
color: #606266;
|
|
}
|
|
}
|
|
|
|
@keyframes rotating {
|
|
from {
|
|
transform: rotate(0deg);
|
|
}
|
|
to {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
|
|
::v-deep .import-dialog-wrapper {
|
|
border-radius: 6px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
::v-deep .import-dialog-wrapper .el-dialog__header {
|
|
border-bottom: 1px solid #dde3ec;
|
|
background: #ffffff;
|
|
}
|
|
|
|
::v-deep .import-dialog-wrapper .el-dialog__body {
|
|
background: #f8fafc;
|
|
}
|
|
</style>
|