UPDATE: 异步导出检测数据逻辑。

This commit is contained in:
贾同学
2025-09-19 16:18:10 +08:00
parent 3e7509cd44
commit a9156f0954
4 changed files with 150 additions and 15 deletions

View File

@@ -211,13 +211,19 @@ class RequestHttp {
const eventSource = new EventSourcePolyfill(requestUrl, { const eventSource = new EventSourcePolyfill(requestUrl, {
headers: { headers: {
Authorization: 'Bearer ' + userStore.accessToken Authorization: 'Bearer ' + userStore.accessToken
} },
// 增加超时时间到120秒
heartbeatTimeout: 120000
}) })
// 设置默认的Authorization头部 // 设置默认的Authorization头部
eventSource.addEventListener('open', function () { eventSource.addEventListener('open', function () {
console.log('SSE连接已建立') console.log('SSE连接已建立')
}) })
// 添加错误处理
eventSource.addEventListener('error', function (err) {
console.error('SSE连接错误:', err)
})
return eventSource return eventSource
} }

View File

@@ -136,7 +136,7 @@ export const importSubPlan = (params: Plan.ResPlan) => {
// 导出计划检测结果数据 // 导出计划检测结果数据
export const exportPlanCheckData = (params: any) => { export const exportPlanCheckData = (params: any) => {
return http.download( return http.post(
`/adPlan/exportPlanCheckData?planId=${params.id}&devIds=${params.devIds}&report=${params.report}` `/adPlan/exportPlanCheckData?planId=${params.id}&devIds=${params.devIds}&report=${params.report}`
) )
} }

View File

@@ -5,6 +5,7 @@
:destroy-on-close="true" :destroy-on-close="true"
width="450px" width="450px"
:close-on-click-modal="!parameter.progressBar" :close-on-click-modal="!parameter.progressBar"
:show-close="!disable"
draggable draggable
> >
<el-upload <el-upload
@@ -20,7 +21,7 @@
:disabled="fileDisabled" :disabled="fileDisabled"
> >
<slot name="empty"> <slot name="empty">
<el-button type="primary" icon="Upload">点击上传</el-button> <el-button type="primary" :disabled="fileDisabled" icon="Upload">点击上传</el-button>
</slot> </slot>
<template #tip> <template #tip>
<slot name="tip"> <slot name="tip">
@@ -28,11 +29,7 @@
</slot> </slot>
</template> </template>
</el-upload> </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"> <el-text v-if="parameter.progressBar && progressData.status === 'exception'" size="small" type="danger">
{{ progressData.message }} {{ progressData.message }}
</el-text> </el-text>
@@ -42,6 +39,15 @@
<el-text v-if="parameter.progressBar && progressData.status === ''" size="small" type="info"> <el-text v-if="parameter.progressBar && progressData.status === ''" size="small" type="info">
{{ progressData.message }} {{ progressData.message }}
</el-text> </el-text>
<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>
<template #footer v-if="parameter.confirmMessage"> <template #footer v-if="parameter.confirmMessage">
<el-button :disabled="disable" type="primary" @click="uploadSubmit">开始导入</el-button> <el-button :disabled="disable" type="primary" @click="uploadSubmit">开始导入</el-button>
@@ -96,7 +102,12 @@ const uploadZip = (param: UploadRequestOptions) => {
} }
setTimeout(() => { setTimeout(() => {
parameter.value.importApi!(zipFormData).then(res => handleImportResponse(res)) parameter.value.importApi!(zipFormData)
.then(res => handleImportResponse(res))
.catch(err => {
fileDisabled.value = false
disable.value = false
})
}, 1000) }, 1000)
} }
@@ -104,13 +115,17 @@ const handleImportResponse = (res: any) => {
if (!parameter.value.progressBar) { if (!parameter.value.progressBar) {
if (res.code === 'A0000') { if (res.code === 'A0000') {
ElMessage.success('导入成功') ElMessage.success('导入成功')
dialogVisible.value = false
emit('result', res.data)
} else { } else {
ElMessage.error(res.message) ElMessage.error(res.message)
fileDisabled.value = false
disable.value = false
} }
dialogVisible.value = false
emit('result', res.data)
} else { } else {
// if (res.code !== 'A0000') {
ElMessage.error(res.message)
}
} }
} }

View File

@@ -172,6 +172,45 @@
<PlanPopup ref="planPopup" :refresh-table="proTable?.getTableList" @update:tab="addNewChildTab" /> <PlanPopup ref="planPopup" :refresh-table="proTable?.getTableList" @update:tab="addNewChildTab" />
<DevTransfer ref="devTransfer" @update:table="addNewChildTab" /> <DevTransfer ref="devTransfer" @update:table="addNewChildTab" />
<ImportZip ref="planCheckDataImportZip" @result="importResult" /> <ImportZip ref="planCheckDataImportZip" @result="importResult" />
<el-dialog
v-model="showProgress"
title="数据下载进度"
width="500"
draggable
:show-close="false"
:close-on-click-modal="false"
>
<el-row style="margin-top: 10px">
<el-text v-if="progressData.status === ''" type="info">
{{ progressData.message }}
</el-text>
<el-text v-if="progressData.status === 'exception'" type="danger">
{{ progressData.message }}
</el-text>
<el-text v-if="progressData.status === 'success'">文件所在目录:</el-text>
<el-link
v-if="progressData.status === 'success'"
type="primary"
title="点击打开目录"
:href="progressData.message"
@click="openDownloadLocation"
>
{{ progressData.message }}
</el-link>
</el-row>
<el-progress
style="margin-top: 10px; margin-bottom: 10px"
:status="progressData.status"
:percentage="progressData.percentage"
:stroke-width="10"
striped
striped-flow
></el-progress>
<template #footer>
<el-button :disabled="progressData.status === ''" @click="showProgress = false">关闭</el-button>
</template>
</el-dialog>
</template> </template>
<script lang="tsx" setup> <script lang="tsx" setup>
import { ElFormItem, ElMessage, ElMessageBox, ElSwitch, type TabPaneName } from 'element-plus' import { ElFormItem, ElMessage, ElMessageBox, ElSwitch, type TabPaneName } from 'element-plus'
@@ -195,6 +234,7 @@ import { useHandleData } from '@/hooks/useHandleData'
import router from '@/routers' import router from '@/routers'
import { useDownload } from '@/hooks/useDownload' import { useDownload } from '@/hooks/useDownload'
import ImportZip from '@/components/ImportZip/index.vue' import ImportZip from '@/components/ImportZip/index.vue'
import http from '@/api'
const dictStore = useDictStore() const dictStore = useDictStore()
const planFormContent = ref<Plan.ReqPlan>() const planFormContent = ref<Plan.ReqPlan>()
@@ -642,28 +682,103 @@ const exportPlan = async () => {
useDownload(exportSubPlan, `${subPlanFormContent.name}_子计划元信息`, params, false, '.zip') useDownload(exportSubPlan, `${subPlanFormContent.name}_子计划元信息`, params, false, '.zip')
) )
} }
const exportPlanCheckResultData = async (selectedListIds: string[]) => { const exportPlanCheckResultData = async (selectedListIds: string[]) => {
const params = { const params = {
id: planFormContent.value.id, id: planFormContent.value.id,
report: downloadReport.value, report: downloadReport.value,
devIds: selectedListIds.join(',') devIds: selectedListIds.join(',')
} }
progressData.value = {
percentage: 0,
status: '',
message: ''
}
initSSE()
ElMessageBox.confirm(vnode, '温馨提示', { ElMessageBox.confirm(vnode, '温馨提示', {
type: '', type: '',
distinguishCancelAndClose: true, distinguishCancelAndClose: true,
closeOnClickModal: false,
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消' cancelButtonText: '取消'
}) })
.then(() => { .then(() => {
params.report = downloadReport.value params.report = downloadReport.value
useDownload(exportPlanCheckData, `${planFormContent.value.name}_检测计划检测数据包`, params, false, '.zip') exportPlanCheckData(params).then(res => {
if (res.code !== 'A0000') {
ElMessage.error(res.message)
} else {
showProgress.value = true
}
})
}) })
.catch(action => { .catch(action => {
// 用户取消或关闭对话框 // 用户取消或关闭对话框
console.log('用户取消操作: ', action) closeEventSource()
}) })
} }
const eventSource = ref<EventSource | null>(null)
const showProgress = ref(false)
const filePath = ref('')
const progressData = ref({
percentage: 0,
status: '',
message: ''
})
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') {
progressData.value.status = 'exception'
ElMessage.error(res.message)
}
if (progressData.value.percentage === 100) {
progressData.value.status = 'success'
eventSource.value!.close()
filePath.value = res.message
}
}
eventSource.value.onerror = error => {
console.warn('SSE 连接出错:', error)
eventSource.value!.close()
}
}
const closeEventSource = () => {
if (eventSource.value) {
eventSource.value.close()
eventSource.value = null
console.log('SSE连接已关闭')
}
}
// 打开下载文件所在位置
const openDownloadLocation = () => {
try {
const Renderer = window.require && window.require('electron')
if (Renderer && Renderer.shell) {
if (filePath.value) {
// 打开指定文件所在的目录,并选中该文件
Renderer.shell.showItemInFolder(filePath.value)
} else {
// 使用默认下载路径
const downloadPath = Renderer.app.getPath('downloads')
Renderer.shell.openPath(downloadPath)
}
} else {
ElMessage.warning('当前运行环境不支持,请复制路径自行打开')
}
} catch (error) {
console.error('打开文件所在位置时出错:', error)
ElMessage.error('打开文件所在位置失败')
}
}
const importAndMergePlanCheckDataClick = () => { const importAndMergePlanCheckDataClick = () => {
const params = { const params = {
title: '合并检测计划检测结果', title: '合并检测计划检测结果',
@@ -675,7 +790,6 @@ const importAndMergePlanCheckDataClick = () => {
} }
planCheckDataImportZip.value?.acceptParams(params) planCheckDataImportZip.value?.acceptParams(params)
} }
const importResult = async (success: boolean | undefined) => { const importResult = async (success: boolean | undefined) => {
if (success) { if (success) {
await props.refreshTable!() await props.refreshTable!()