2025-08-15 16:03:42 +08:00
|
|
|
<template>
|
2025-09-11 11:03:14 +08:00
|
|
|
<el-dialog
|
|
|
|
|
v-model="dialogVisible"
|
|
|
|
|
:title="parameter.title"
|
|
|
|
|
:destroy-on-close="true"
|
|
|
|
|
width="450px"
|
|
|
|
|
:close-on-click-modal="!parameter.progressBar"
|
2025-09-19 16:18:10 +08:00
|
|
|
:show-close="!disable"
|
2025-09-11 11:03:14 +08:00
|
|
|
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">
|
2025-09-19 16:18:10 +08:00
|
|
|
<el-button type="primary" :disabled="fileDisabled" icon="Upload">点击上传</el-button>
|
2025-09-11 11:03:14 +08:00
|
|
|
</slot>
|
|
|
|
|
<template #tip>
|
|
|
|
|
<slot name="tip">
|
|
|
|
|
<div class="el-upload__tip">请上传 .zip 标准格式文件</div>
|
|
|
|
|
</slot>
|
|
|
|
|
</template>
|
|
|
|
|
</el-upload>
|
2025-09-19 16:18:10 +08:00
|
|
|
|
2025-09-11 11:03:14 +08:00
|
|
|
<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>
|
2025-09-19 16:18:10 +08:00
|
|
|
<el-progress
|
|
|
|
|
style="margin-top: 10px; margin-bottom: 10px"
|
|
|
|
|
v-if="parameter.progressBar"
|
|
|
|
|
:status="progressData.status"
|
|
|
|
|
:percentage="progressData.percentage"
|
|
|
|
|
:stroke-width="10"
|
|
|
|
|
striped
|
|
|
|
|
striped-flow
|
|
|
|
|
></el-progress>
|
2025-09-11 11:03:14 +08:00
|
|
|
|
2025-08-27 20:21:55 +08:00
|
|
|
<template #footer v-if="parameter.confirmMessage">
|
|
|
|
|
<el-button :disabled="disable" type="primary" @click="uploadSubmit">开始导入</el-button>
|
|
|
|
|
</template>
|
2025-08-15 16:03:42 +08:00
|
|
|
</el-dialog>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts" name="ImportZip">
|
|
|
|
|
import { ref } from 'vue'
|
2025-08-27 20:21:55 +08:00
|
|
|
import type { UploadInstance, UploadProps, UploadRequestOptions } from 'element-plus'
|
2025-09-11 11:03:14 +08:00
|
|
|
import http from '@/api'
|
2025-08-15 16:03:42 +08:00
|
|
|
|
|
|
|
|
export interface ZipParameterProps {
|
|
|
|
|
title: string // 标题
|
|
|
|
|
patternId?: string // 模式ID
|
2025-09-11 11:03:14 +08:00
|
|
|
planId?: string // 计划ID
|
2025-08-15 16:03:42 +08:00
|
|
|
importApi?: (params: any) => Promise<any> // 批量导入的Api
|
2025-08-27 20:21:55 +08:00
|
|
|
confirmMessage?: string // 提示信息
|
2025-09-11 11:03:14 +08:00
|
|
|
progressBar?: boolean // 进度条
|
2025-08-15 16:03:42 +08:00
|
|
|
}
|
|
|
|
|
// dialog状态
|
|
|
|
|
const dialogVisible = ref(false)
|
2025-08-27 20:21:55 +08:00
|
|
|
const disable = ref(true)
|
2025-09-11 11:03:14 +08:00
|
|
|
const fileDisabled = ref(false)
|
2025-08-27 20:21:55 +08:00
|
|
|
const uploadRef = ref<UploadInstance>()
|
|
|
|
|
|
2025-08-15 16:03:42 +08:00
|
|
|
// 父组件传过来的参数
|
|
|
|
|
const parameter = ref<ZipParameterProps>({
|
|
|
|
|
title: ''
|
|
|
|
|
})
|
|
|
|
|
const emit = defineEmits<{
|
|
|
|
|
(e: 'result', data: boolean): void
|
|
|
|
|
}>()
|
|
|
|
|
// 接收父组件参数
|
|
|
|
|
const acceptParams = (params: ZipParameterProps) => {
|
|
|
|
|
parameter.value = { ...parameter.value, ...params }
|
|
|
|
|
dialogVisible.value = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 文件上传
|
2025-09-11 11:03:14 +08:00
|
|
|
const uploadZip = (param: UploadRequestOptions) => {
|
2025-08-15 16:03:42 +08:00
|
|
|
let zipFormData = new FormData()
|
|
|
|
|
zipFormData.append('file', param.file)
|
|
|
|
|
if (parameter.value.patternId) {
|
|
|
|
|
zipFormData.append('patternId', parameter.value.patternId)
|
|
|
|
|
}
|
2025-09-11 11:03:14 +08:00
|
|
|
if (parameter.value.planId) {
|
|
|
|
|
zipFormData.append('planId', parameter.value.planId)
|
|
|
|
|
}
|
|
|
|
|
if (parameter.value.progressBar) {
|
|
|
|
|
initSSE()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setTimeout(() => {
|
2025-09-19 16:18:10 +08:00
|
|
|
parameter.value.importApi!(zipFormData)
|
|
|
|
|
.then(res => handleImportResponse(res))
|
|
|
|
|
.catch(err => {
|
|
|
|
|
fileDisabled.value = false
|
|
|
|
|
disable.value = false
|
|
|
|
|
})
|
2025-09-11 11:03:14 +08:00
|
|
|
}, 1000)
|
2025-08-15 16:03:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleImportResponse = (res: any) => {
|
2025-09-11 11:03:14 +08:00
|
|
|
if (!parameter.value.progressBar) {
|
|
|
|
|
if (res.code === 'A0000') {
|
|
|
|
|
ElMessage.success('导入成功')
|
2025-09-25 11:16:57 +08:00
|
|
|
emit('result', true)
|
2025-09-19 16:18:10 +08:00
|
|
|
dialogVisible.value = false
|
2025-09-11 11:03:14 +08:00
|
|
|
} else {
|
|
|
|
|
ElMessage.error(res.message)
|
2025-09-19 16:18:10 +08:00
|
|
|
fileDisabled.value = false
|
|
|
|
|
disable.value = false
|
2025-09-11 11:03:14 +08:00
|
|
|
}
|
2025-08-15 16:03:42 +08:00
|
|
|
} else {
|
2025-09-19 16:18:10 +08:00
|
|
|
if (res.code !== 'A0000') {
|
|
|
|
|
ElMessage.error(res.message)
|
|
|
|
|
}
|
2025-08-15 16:03:42 +08:00
|
|
|
}
|
|
|
|
|
}
|
2025-09-11 11:03:14 +08:00
|
|
|
|
2025-08-27 20:21:55 +08:00
|
|
|
const uploadSubmit = () => {
|
|
|
|
|
if (!uploadRef.value) {
|
|
|
|
|
return ElMessage.warning('请选择文件!')
|
|
|
|
|
}
|
2025-09-11 11:03:14 +08:00
|
|
|
progressData.value = {
|
|
|
|
|
percentage: 0,
|
|
|
|
|
status: '',
|
|
|
|
|
message: ''
|
|
|
|
|
}
|
2025-08-27 20:21:55 +08:00
|
|
|
ElMessageBox.confirm(parameter.value.confirmMessage, '温馨提示', {
|
|
|
|
|
confirmButtonText: '确定',
|
|
|
|
|
cancelButtonText: '取消',
|
|
|
|
|
type: 'warning'
|
|
|
|
|
})
|
|
|
|
|
.then(() => {
|
2025-09-11 11:03:14 +08:00
|
|
|
disable.value = true
|
|
|
|
|
fileDisabled.value = true
|
2025-08-27 20:21:55 +08:00
|
|
|
uploadRef.value?.submit()
|
|
|
|
|
})
|
2025-09-11 11:03:14 +08:00
|
|
|
.catch(() => {
|
|
|
|
|
disable.value = false
|
|
|
|
|
fileDisabled.value = false
|
|
|
|
|
})
|
2025-08-27 20:21:55 +08:00
|
|
|
}
|
|
|
|
|
const handleChange: UploadProps['onChange'] = (uploadFile, uploadFiles) => {
|
|
|
|
|
disable.value = uploadFiles.length === 0
|
2025-09-11 11:03:14 +08:00
|
|
|
progressData.value = {
|
|
|
|
|
percentage: 0,
|
|
|
|
|
status: '',
|
|
|
|
|
message: ''
|
|
|
|
|
}
|
2025-08-27 20:21:55 +08:00
|
|
|
}
|
|
|
|
|
const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
|
|
|
|
|
disable.value = uploadFiles.length === 0
|
2025-09-11 11:03:14 +08:00
|
|
|
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('导入成功')
|
|
|
|
|
emit('result', true)
|
2025-09-25 11:16:57 +08:00
|
|
|
dialogVisible.value = false
|
2025-09-11 11:03:14 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
eventSource.value.onerror = error => {
|
|
|
|
|
console.warn('SSE 连接出错:', error)
|
|
|
|
|
eventSource.value!.close()
|
|
|
|
|
}
|
2025-08-27 20:21:55 +08:00
|
|
|
}
|
2025-09-11 11:03:14 +08:00
|
|
|
// 添加一个手动关闭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()
|
|
|
|
|
})
|
2025-08-15 16:03:42 +08:00
|
|
|
defineExpose({
|
|
|
|
|
acceptParams
|
|
|
|
|
})
|
|
|
|
|
</script>
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
@use './index.scss';
|
|
|
|
|
</style>
|