From 96bc199be40d87a23a2b1245588011aca8d97914 Mon Sep 17 00:00:00 2001 From: qiankanghui Date: Fri, 10 Jul 2026 11:44:56 +0800 Subject: [PATCH] =?UTF-8?q?feat(eam):=20=E6=96=B0=E5=A2=9E=E7=BB=B4?= =?UTF-8?q?=E4=BF=9D=E9=A1=B9=E7=9B=AE=E5=AF=BC=E5=85=A5=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E5=B9=B6=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5=E4=BD=93=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加维保项目明细导入API接口和模板下载功能 - 实现导入对话框防止重复提交功能 - 优化导入结果显示,支持换行错误信息展示 - 新增导入维保项目和点检项目的独立操作入口 - 统一导入流程的状态管理和错误处理机制 - 优化导入对话框样式和用户体验 --- src/api/eam/eam.js | 2 + src/views/modules/eam/eamMaintenanceItem.vue | 33 +- src/views/modules/eam/eamMaintenanceModel.vue | 320 ++++++++++++++++-- src/views/modules/eam/eamPropertiesItem.vue | 44 ++- src/views/modules/eam/eamPropertiesModel.vue | 74 +++- 5 files changed, 424 insertions(+), 49 deletions(-) diff --git a/src/api/eam/eam.js b/src/api/eam/eam.js index 582a53d..e2b1bf4 100644 --- a/src/api/eam/eam.js +++ b/src/api/eam/eam.js @@ -83,6 +83,8 @@ export const downloadEamPropertiesItemDetailTemplate = () => createAPI(`/pms/eam //---------------维保项目------------------------ export const uploadEamMaintenanceItemExcel = data => createAPI(`/pms/eam/uploadEamMaintenanceItemExcel`,'post',data) export const downloadEamMaintenanceItemTemplate = () => createAPI(`/pms/eam/downloadEamMaintenanceItemTemplate`,'get',{},'download') +export const uploadEamMaintenanceItemDetailExcel = data => createAPI(`/pms/eam/uploadEamMaintenanceItemDetailExcel`,'post',data) +export const downloadEamMaintenanceItemDetailTemplate = () => createAPI(`/pms/eam/downloadEamMaintenanceItemDetailTemplate`,'get',{},'download') //---------------点检模板------------------- export const eamPropertiesModelSearch = data => createAPI(`/pms/eam/eamPropertiesModelSearch`,'post',data) diff --git a/src/views/modules/eam/eamMaintenanceItem.vue b/src/views/modules/eam/eamMaintenanceItem.vue index c4ea21b..2f65be8 100644 --- a/src/views/modules/eam/eamMaintenanceItem.vue +++ b/src/views/modules/eam/eamMaintenanceItem.vue @@ -276,8 +276,8 @@ - 保存 - 关闭 + 保存 + 关闭 @@ -712,6 +712,7 @@ uploadFileName: '', uploadFile: null, uploadBu: '', // 上传时选择的BU + uploadSubmitting: false, // 防止重复提交 } }, @@ -1181,6 +1182,11 @@ // 确认上传 confirmUpload () { + // 防止重复提交 + if (this.uploadSubmitting) { + return + } + // 验证BU是否选择 if (!this.uploadBu || this.uploadBu === '') { this.$message.warning('请先选择BU') @@ -1198,6 +1204,9 @@ formData.append('site', this.uploadBu.split('_')[0]) // 从BU中提取site formData.append('buNo', this.uploadBu.split('_')[1]) // 从BU中提取buNo + // 设置提交状态 + this.uploadSubmitting = true + // 调用后端导入接口 uploadEamMaintenanceItemExcel(formData).then(({data}) => { if (data.code === 0) { @@ -1216,8 +1225,23 @@ } }).catch((error) => { console.error('导入失败:', error) - const errorMsg = (error.response && error.response.data && error.response.data.msg) || error.message || '未知错误' - this.$message.error('导入失败: ' + errorMsg) + + const errorMsg = + (error.response && error.response.data && error.response.data.msg) + || error.message + || '未知错误' + + this.$alert( + ('导入失败: ' + errorMsg).replace(/\n/g, '
'), + '导入结果', + { + confirmButtonText: '确定', + dangerouslyUseHTMLString: true + } + ) + }).finally(() => { + // 恢复提交状态 + this.uploadSubmitting = false }) }, @@ -1278,6 +1302,7 @@ this.uploadFileName = '' this.uploadFile = null this.uploadBu = '' // 清空BU选择 + this.uploadSubmitting = false // 重置提交状态 if (this.$refs.uploadFile) { this.$refs.uploadFile.clearFiles() } diff --git a/src/views/modules/eam/eamMaintenanceModel.vue b/src/views/modules/eam/eamMaintenanceModel.vue index 921b5ed..164a4b0 100644 --- a/src/views/modules/eam/eamMaintenanceModel.vue +++ b/src/views/modules/eam/eamMaintenanceModel.vue @@ -41,7 +41,8 @@ 查询 新增 - 导入 + 导入模板 + 导入维保项目 {{'导出'}} {{'导出明细'}} @@ -428,8 +429,50 @@ - 保存 - 关闭 + 保存 + 关闭 + + + + + + @@ -455,6 +498,8 @@ goDownItemEam, uploadEamMaintenanceModelExcel, // 导入维保模板Excel downloadEamMaintenanceModelTemplate, // 下载维保模板导入模板 + uploadEamMaintenanceItemDetailExcel, // 导入维保项目清单Excel + downloadEamMaintenanceItemDetailTemplate // 下载维保项目清单导入模板 } from "@/api/eam/eam.js" import {getTableDefaultListLanguage, getTableUserListLanguage} from "@/api/table.js" import Chooselist from '@/views/modules/common/Chooselist_eam' @@ -1252,6 +1297,12 @@ uploadFileName: '', uploadFile: null, uploadBu: '', // 上传时选择的BU + uploadSubmitting: false, // 防止重复提交 + // 导入维保项目相关 + uploadItemDialogVisible: false, + uploadItemFileName: '', + uploadItemFile: null, + uploadItemSubmitting: false, // 防止重复提交 } }, @@ -1881,6 +1932,11 @@ // 确认上传 confirmUpload () { + // 防止重复提交 + if (this.uploadSubmitting) { + return + } + // 验证BU是否选择 if (!this.uploadBu || this.uploadBu === '') { this.$message.warning('请先选择BU') @@ -1898,6 +1954,9 @@ formData.append('site', this.uploadBu.split('_')[0]) // 从BU中提取site formData.append('buNo', this.uploadBu.split('_')[1]) // 从BU中提取buNo + // 设置提交状态 + this.uploadSubmitting = true + // 调用后端导入接口 uploadEamMaintenanceModelExcel(formData).then(({data}) => { if (data.code === 0) { @@ -1912,12 +1971,104 @@ } this.getDataList() } else { - this.$message.error(data.msg || '导入失败') - } + this.$alert( + (data.msg || '导入失败').replace(/\n/g, '
'), + '导入结果', + { + confirmButtonText: '确定', + dangerouslyUseHTMLString: true + } + ) + } }).catch((error) => { console.error('导入失败:', error) const errorMsg = (error.response && error.response.data && error.response.data.msg) || error.message || '未知错误' - this.$message.error('导入失败: ' + errorMsg) + this.$alert( + ('导入失败: ' + errorMsg).replace(/\n/g, '
'), + '导入结果', + { + confirmButtonText: '确定', + dangerouslyUseHTMLString: true + } + ) + }).finally(() => { + // 恢复提交状态 + this.uploadSubmitting = false + }) + }, + + // 导入维保项目 + importItemExcel () { + this.uploadItemDialogVisible = true + this.uploadItemFileName = '' + this.uploadItemFile = null + // 清空el-upload组件的文件列表 + if (this.$refs.uploadItemFile) { + this.$refs.uploadItemFile.clearFiles() + } + }, + + // 维保项目文件选择变化 + handleItemFileChange (file) { + this.uploadItemFile = file.raw + this.uploadItemFileName = file.name + }, + + // 确认导入维保项目 + confirmItemUpload () { + // 防止重复提交 + if (this.uploadItemSubmitting) { + return + } + + if (!this.uploadItemFile) { + this.$message.warning('请先选择文件') + return + } + + const formData = new FormData() + formData.append('file', this.uploadItemFile) + formData.append('userId', this.$store.state.user.name) + + // 设置提交状态 + this.uploadItemSubmitting = true + + // 调用后端导入接口 + uploadEamMaintenanceItemDetailExcel(formData).then(({data}) => { + if (data.code === 0) { + this.$message.success(data.msg || '导入成功') + this.uploadItemDialogVisible = false + // 清空文件信息 + this.uploadItemFileName = '' + this.uploadItemFile = null + if (this.$refs.uploadItemFile) { + this.$refs.uploadItemFile.clearFiles() + } + this.getDataList() + } else { + this.$alert( + (data.msg || '导入失败').replace(/\n/g, '
'), + '导入结果', + { + confirmButtonText: '确定', + dangerouslyUseHTMLString: true + } + ) + } + }).catch((error) => { + console.error('导入失败:', error) + const errorMsg = (error.response && error.response.data && error.response.data.msg) || error.message || '未知错误' + this.$alert( + ('导入失败: ' + errorMsg).replace(/\n/g, '
'), + '导入结果', + { + confirmButtonText: '确定', + dangerouslyUseHTMLString: true + } + ) + }).finally(() => { + // 恢复提交状态 + this.uploadItemSubmitting = false }) }, @@ -1934,54 +2085,54 @@ const xhr = new XMLHttpRequest() xhr.open('GET', this.$http.adornUrl('/pms/eam/downloadEamMaintenanceModelTemplate'), true) xhr.responseType = 'blob' - + // 添加token const token = this.$cookie.get('token') if (token) { xhr.setRequestHeader('token', token) } - + xhr.onload = () => { loading.close() - + if (xhr.status === 200) { const blob = xhr.response - + // 验证Blob大小 if (blob.size === 0) { this.$message.error('模板文件为空,请联系管理员') return } - + // 创建下载链接 const url = window.URL.createObjectURL(blob) const link = document.createElement('a') link.href = url link.download = '维保模板导入模板.xlsx' link.style.display = 'none' - + document.body.appendChild(link) link.click() document.body.removeChild(link) - + // 释放URL对象 setTimeout(() => { window.URL.revokeObjectURL(url) }, 100) - + this.$message.success('模板下载成功') } else { console.error('模板下载失败,状态码:', xhr.status) this.$message.error('模板下载失败:服务器错误') } } - + xhr.onerror = () => { loading.close() console.error('网络错误') this.$message.error('模板下载失败:网络错误') } - + xhr.send() }, @@ -1990,10 +2141,85 @@ this.uploadFileName = '' this.uploadFile = null this.uploadBu = '' // 清空BU选择 + this.uploadSubmitting = false // 重置提交状态 if (this.$refs.uploadFile) { this.$refs.uploadFile.clearFiles() } }, + + // 关闭维保项目上传对话框时清空文件 + handleUploadItemDialogClose () { + this.uploadItemFileName = '' + this.uploadItemFile = null + this.uploadItemSubmitting = false // 重置提交状态 + if (this.$refs.uploadItemFile) { + this.$refs.uploadItemFile.clearFiles() + } + }, + + // 下载点检项目模板 + downloadItemTemplate () { + const loading = this.$loading({ + lock: true, + text: '正在下载模板...', + spinner: 'el-icon-loading', + background: 'rgba(0, 0, 0, 0.7)' + }) + + // 使用原生XMLHttpRequest处理文件下载,避免axios拦截器干扰 + const xhr = new XMLHttpRequest() + xhr.open('GET', this.$http.adornUrl('/pms/eam/downloadEamMaintenanceItemDetailTemplate'), true) + xhr.responseType = 'blob' + + // 添加token + const token = this.$cookie.get('token') + if (token) { + xhr.setRequestHeader('token', token) + } + + xhr.onload = () => { + loading.close() + + if (xhr.status === 200) { + const blob = xhr.response + + // 验证Blob大小 + if (blob.size === 0) { + this.$message.error('模板文件为空,请联系管理员') + return + } + + // 创建下载链接 + const url = window.URL.createObjectURL(blob) + const link = document.createElement('a') + link.href = url + link.download = '维保项目清单导入模板.xlsx' + link.style.display = 'none' + + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + + // 释放URL对象 + setTimeout(() => { + window.URL.revokeObjectURL(url) + }, 100) + + this.$message.success('模板下载成功') + } else { + console.error('模板下载失败,状态码:', xhr.status) + this.$message.error('模板下载失败:服务器错误') + } + } + + xhr.onerror = () => { + loading.close() + console.error('网络错误') + this.$message.error('模板下载失败:网络错误') + } + + xhr.send() + }, } } @@ -2003,37 +2229,69 @@ line-height: 1.5; } .simple-dialog >>> .el-dialog { - margin-top: 12vh !important; - max-height: 70vh; border-radius: 8px; } + +/* body顶格 */ .simple-dialog >>> .el-dialog__body { - padding: 10px 20px; - max-height: calc(70vh - 120px); - overflow-y: auto; + padding: 0px 20px 10px 20px !important; } -/* 导入对话框内部元素靠左对齐 */ + +/* 内容不要额外缩进 */ .simple-dialog >>> .el-dialog__body > div { - text-align: left; + margin-left: 0 !important; +} + + +/* 下载区域 */ +.download-area { + margin-top: 0; + margin-bottom: 0; } + +/* 下载按钮 */ +.download-btn { + width: 40%; +} + + +/* BU区域 */ +.bu-area { + margin-top: 0; + margin-bottom: 5px; +} + + +/* BU label */ .simple-dialog >>> .el-form-item__label { - text-align: left !important; + padding-bottom: 0; + line-height: 22px; +} + + +/* 去掉form自带间距 */ +.simple-dialog >>> .el-form-item { + margin-bottom: 0; } -/* 上传拖拽区域大小调整 */ + +/* 上传区域 */ +.upload-demo { + margin-top: 0; +} + + +/* 上传框 */ .upload-demo .el-upload-dragger { width: 100%; height: 150px; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; } -.upload-demo .el-upload-dragger .el-icon-upload { - margin-bottom: 10px; +.simple-dialog >>> .el-dialog__body { + padding-left: 10px !important; + padding-right: 0 !important; } diff --git a/src/views/modules/eam/eamPropertiesItem.vue b/src/views/modules/eam/eamPropertiesItem.vue index e1f8596..272d045 100644 --- a/src/views/modules/eam/eamPropertiesItem.vue +++ b/src/views/modules/eam/eamPropertiesItem.vue @@ -279,8 +279,8 @@ - 保存 - 关闭 + 保存 + 关闭 @@ -736,6 +736,7 @@ uploadFileName: '', uploadFile: null, uploadBu: '', // 上传时选择的BU + uploadSubmitting: false, // 防止重复提交 } }, @@ -1215,6 +1216,11 @@ // 确认上传 confirmUpload () { + // 防止重复提交 + if (this.uploadSubmitting) { + return + } + // 验证BU是否选择 if (!this.uploadBu || this.uploadBu === '') { this.$message.warning('请先选择BU') @@ -1232,6 +1238,9 @@ formData.append('site', this.uploadBu.split('_')[0]) // 从BU中提取site formData.append('buNo', this.uploadBu.split('_')[1]) // 从BU中提取buNo + // 设置提交状态 + this.uploadSubmitting = true + // 调用后端导入接口 uploadEamPropertiesItemExcel(formData).then(({data}) => { if (data.code === 0) { @@ -1250,8 +1259,34 @@ } }).catch((error) => { console.error('导入失败:', error) - const errorMsg = (error.response && error.response.data && error.response.data.msg) || error.message || '未知错误' - this.$message.error('导入失败: ' + errorMsg) + + let errorMsg = '' + + if (error.response && error.response.data) { + errorMsg = error.response.data.msg || error.response.data.message || '' + } + + if (!errorMsg) { + errorMsg = error.message || '未知错误' + } + + // 处理后端换行 + errorMsg = errorMsg + .replace(/\\n/g, '\n') // 处理转义换行 + .replace(/\n/g, '
') // html换行 + + this.$alert( + '导入失败:
' + errorMsg, + '导入结果', + { + confirmButtonText: '确定', + dangerouslyUseHTMLString: true, + customClass: 'import-error-dialog' + } + ) + }).finally(() => { + // 恢复提交状态 + this.uploadSubmitting = false }) }, @@ -1312,6 +1347,7 @@ this.uploadFileName = '' this.uploadFile = null this.uploadBu = '' // 清空BU选择 + this.uploadSubmitting = false // 重置提交状态 if (this.$refs.uploadFile) { this.$refs.uploadFile.clearFiles() } diff --git a/src/views/modules/eam/eamPropertiesModel.vue b/src/views/modules/eam/eamPropertiesModel.vue index 103efe2..9c0d58b 100644 --- a/src/views/modules/eam/eamPropertiesModel.vue +++ b/src/views/modules/eam/eamPropertiesModel.vue @@ -41,7 +41,7 @@ 查询 新增 - 导入 + 导入模板 导入点检项目 {{'导出'}} {{'导出明细'}} @@ -406,8 +406,8 @@ - 保存 - 关闭 + 保存 + 关闭 @@ -448,8 +448,8 @@ - 保存 - 关闭 + 保存 + 关闭 @@ -1273,11 +1273,13 @@ uploadFileName: '', uploadFile: null, uploadBu: '', // 上传时选择的BU + uploadSubmitting: false, // 防止重复提交 // 导入点检项目相关 uploadItemDialogVisible: false, uploadItemFileName: '', uploadItemFile: null, uploadItemBu: '', // 导入点检项目时选择的BU + uploadItemSubmitting: false, // 防止重复提交 } }, @@ -1871,6 +1873,11 @@ // 确认上传 confirmUpload () { + // 防止重复提交 + if (this.uploadSubmitting) { + return + } + // 验证BU是否选择 if (!this.uploadBu || this.uploadBu === '') { this.$message.warning('请先选择BU') @@ -1888,6 +1895,9 @@ formData.append('site', this.uploadBu.split('_')[0]) // 从BU中提取site formData.append('buNo', this.uploadBu.split('_')[1]) // 从BU中提取buNo + // 设置提交状态 + this.uploadSubmitting = true + // 调用后端导入接口 uploadEamPropertiesModelExcel(formData).then(({data}) => { if (data.code === 0) { @@ -1902,12 +1912,29 @@ } this.getDataList() } else { - this.$message.error(data.msg || '导入失败') - } + this.$alert( + (data.msg || '导入失败').replace(/\n/g, '
'), + '导入结果', + { + confirmButtonText: '确定', + dangerouslyUseHTMLString: true + } + ) + } }).catch((error) => { console.error('导入失败:', error) const errorMsg = (error.response && error.response.data && error.response.data.msg) || error.message || '未知错误' - this.$message.error('导入失败: ' + errorMsg) + this.$alert( + ('导入失败: ' + errorMsg).replace(/\n/g, '
'), + '导入结果', + { + confirmButtonText: '确定', + dangerouslyUseHTMLString: true + } + ) + }).finally(() => { + // 恢复提交状态 + this.uploadSubmitting = false }) }, @@ -1930,6 +1957,11 @@ // 确认导入点检项目 confirmItemUpload () { + // 防止重复提交 + if (this.uploadItemSubmitting) { + return + } + if (!this.uploadItemFile) { this.$message.warning('请先选择文件') return @@ -1939,6 +1971,9 @@ formData.append('file', this.uploadItemFile) formData.append('userId', this.$store.state.user.name) + // 设置提交状态 + this.uploadItemSubmitting = true + // 调用后端导入接口 uploadEamPropertiesItemDetailExcel(formData).then(({data}) => { if (data.code === 0) { @@ -1952,12 +1987,29 @@ } this.getDataList() } else { - this.$message.error(data.msg || '导入失败') + this.$alert( + (data.msg || '导入失败').replace(/\n/g, '
'), + '导入结果', + { + confirmButtonText: '确定', + dangerouslyUseHTMLString: true + } + ) } }).catch((error) => { console.error('导入失败:', error) const errorMsg = (error.response && error.response.data && error.response.data.msg) || error.message || '未知错误' - this.$message.error('导入失败: ' + errorMsg) + this.$alert( + ('导入失败: ' + errorMsg).replace(/\n/g, '
'), + '导入结果', + { + confirmButtonText: '确定', + dangerouslyUseHTMLString: true + } + ) + }).finally(() => { + // 恢复提交状态 + this.uploadItemSubmitting = false }) }, @@ -2094,6 +2146,7 @@ this.uploadFileName = '' this.uploadFile = null this.uploadBu = '' // 清空BU选择 + this.uploadSubmitting = false // 重置提交状态 if (this.$refs.uploadFile) { this.$refs.uploadFile.clearFiles() } @@ -2103,6 +2156,7 @@ handleUploadItemDialogClose () { this.uploadItemFileName = '' this.uploadItemFile = null + this.uploadItemSubmitting = false // 重置提交状态 if (this.$refs.uploadItemFile) { this.$refs.uploadItemFile.clearFiles() }