ADD: 修改数据合并逻辑,新增 event-source-polyfill包,实现长连接通信,展示合并进度

This commit is contained in:
贾同学
2025-09-11 11:03:14 +08:00
parent d18e34d2c9
commit cfd8b072dd
6 changed files with 459 additions and 345 deletions

View File

@@ -1,33 +1,48 @@
<template>
<el-dialog v-model="dialogVisible" :title="parameter.title" :destroy-on-close="true" width="450px" draggable>
<el-form class="drawer-multiColumn-form" label-width="100px">
<el-form-item label="">
<el-upload
ref="uploadRef"
action="#"
class="upload"
:http-request="uploadZip"
accept=".zip"
:auto-upload="!parameter.confirmMessage"
:on-change="handleChange"
:on-remove="handleRemove"
>
<slot name="empty">
<el-icon class="el-icon--upload">
<upload-filled />
</el-icon>
<div class="el-upload__text">
<spam>点击上传</spam>
</div>
</slot>
<template #tip>
<slot name="tip">
<div class="el-upload__tip">请上传 .zip 标准格式文件</div>
</slot>
</template>
</el-upload>
</el-form-item>
</el-form>
<el-dialog
v-model="dialogVisible"
:title="parameter.title"
:destroy-on-close="true"
width="450px"
:close-on-click-modal="!parameter.progressBar"
draggable
>
<el-upload
ref="uploadRef"
action="#"
class="upload"
:limit="1"
:http-request="uploadZip"
accept=".zip"
:auto-upload="!parameter.confirmMessage"
:on-change="handleChange"
:on-remove="handleRemove"
:disabled="fileDisabled"
>
<slot name="empty">
<el-button type="primary" icon="Upload">点击上传</el-button>
</slot>
<template #tip>
<slot name="tip">
<div class="el-upload__tip">请上传 .zip 标准格式文件</div>
</slot>
</template>
</el-upload>
<el-progress
v-if="parameter.progressBar"
:status="progressData.status"
:percentage="progressData.percentage"
></el-progress>
<el-text v-if="parameter.progressBar && progressData.status === 'exception'" size="small" type="danger">
{{ progressData.message }}
</el-text>
<el-text v-if="parameter.progressBar && progressData.status === 'success'" size="small" type="success">
{{ progressData.message }}
</el-text>
<el-text v-if="parameter.progressBar && progressData.status === ''" size="small" type="info">
{{ progressData.message }}
</el-text>
<template #footer v-if="parameter.confirmMessage">
<el-button :disabled="disable" type="primary" @click="uploadSubmit">开始导入</el-button>
</template>
@@ -37,16 +52,20 @@
<script setup lang="ts" name="ImportZip">
import { ref } from 'vue'
import type { UploadInstance, UploadProps, UploadRequestOptions } from 'element-plus'
import http from '@/api'
export interface ZipParameterProps {
title: string // 标题
patternId?: string // 模式ID
planId?: string // 计划ID
importApi?: (params: any) => Promise<any> // 批量导入的Api
confirmMessage?: string // 提示信息
progressBar?: boolean // 进度条
}
// dialog状态
const dialogVisible = ref(false)
const disable = ref(true)
const fileDisabled = ref(false)
const uploadRef = ref<UploadInstance>()
// 父组件传过来的参数
@@ -63,44 +82,141 @@ const acceptParams = (params: ZipParameterProps) => {
}
// 文件上传
const uploadZip = async (param: UploadRequestOptions) => {
const uploadZip = (param: UploadRequestOptions) => {
let zipFormData = new FormData()
zipFormData.append('file', param.file)
if (parameter.value.patternId) {
zipFormData.append('patternId', parameter.value.patternId)
}
await parameter.value.importApi!(zipFormData).then(res => handleImportResponse(res))
if (parameter.value.planId) {
zipFormData.append('planId', parameter.value.planId)
}
if (parameter.value.progressBar) {
initSSE()
}
setTimeout(() => {
parameter.value.importApi!(zipFormData).then(res => handleImportResponse(res))
}, 1000)
}
const handleImportResponse = (res: any) => {
if (res.code === 'A0000') {
ElMessage.success('导入成功')
if (!parameter.value.progressBar) {
if (res.code === 'A0000') {
ElMessage.success('导入成功')
} else {
ElMessage.error(res.message)
}
dialogVisible.value = false
emit('result', res.data)
} else {
ElMessage.error(res.message)
//
}
dialogVisible.value = false
emit('result', res.data)
}
const uploadSubmit = () => {
if (!uploadRef.value) {
return ElMessage.warning('请选择文件!')
}
progressData.value = {
percentage: 0,
status: '',
message: ''
}
ElMessageBox.confirm(parameter.value.confirmMessage, '温馨提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
disable.value = true
fileDisabled.value = true
uploadRef.value?.submit()
})
.catch(() => {})
.catch(() => {
disable.value = false
fileDisabled.value = false
})
}
const handleChange: UploadProps['onChange'] = (uploadFile, uploadFiles) => {
disable.value = uploadFiles.length === 0
progressData.value = {
percentage: 0,
status: '',
message: ''
}
}
const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
disable.value = uploadFiles.length === 0
progressData.value = {
percentage: 0,
status: '',
message: ''
}
}
const progressData = ref({
percentage: 0,
status: '',
message: ''
})
const eventSource = ref<EventSource | null>(null)
const initSSE = () => {
eventSource.value = http.sse('/sse/createSse')
eventSource.value.onmessage = event => {
console.log('收到消息内容是:', event.data)
const res = JSON.parse(event.data)
progressData.value.percentage = res.data
progressData.value.message = res.message
if (res.code === 'A0002') {
fileDisabled.value = false
disable.value = false
progressData.value.status = 'exception'
ElMessage.error(res.message)
}
if (progressData.value.percentage === 100) {
progressData.value.status = 'success'
eventSource.value!.close()
ElMessage.success('导入成功')
dialogVisible.value = false
emit('result', true)
}
}
eventSource.value.onerror = error => {
console.warn('SSE 连接出错:', error)
eventSource.value!.close()
}
}
// 添加一个手动关闭EventSource的函数
const closeEventSource = () => {
if (eventSource.value) {
eventSource.value.close()
eventSource.value = null
console.log('SSE连接已关闭')
}
}
// 监听 dialogVisible 的变化,确保在对话框关闭时清理资源
watch(dialogVisible, newVal => {
if (!newVal) {
// 延迟执行,确保在组件完全关闭后清理
setTimeout(() => {
closeEventSource()
fileDisabled.value = false
disable.value = false
progressData.value = {
percentage: 0,
status: '',
message: ''
}
}, 100)
}
})
onUnmounted(() => {
closeEventSource()
})
defineExpose({
acceptParams
})