一、整体功能概述
这段代码实现了一个基于 Vue 3 和 Element Plus 组件库的文件导入及预览功能模块。主要包含了一个主导入对话框(用于上传文件、展示文件相关信息、进行导入操作等)以及一个用于预览文件内容的预览对话框。支持导入特定格式(.xlsx、.csv)且大小不超过 10M 的文件,能展示导入数据的统计情况并提供预览功能,方便用户在正式导入前查看文件内容。
二、模板结构分析
部分
主导入对话框(el-dialog):
标题为 “导入”,通过v-model绑定dialogVisible控制显示隐藏,设置了固定宽度且禁止点击模态框关闭。
内部包含文件上传区域(el-upload组件),可拖放文件,限制了文件类型、自动上传行为等,在文件改变时触发handleFileChange方法。
展示了文件类型提示、下载模板提示及链接(点击调用handleDownloadTemplate方法)。
根据是否有上传文件以及上传进度等情况,动态展示文件预览相关信息、导入数据统计情况等内容。
对话框底部定义了 “取消” 和 “确定” 按钮,“确定” 按钮根据上传进度和文件列表情况控制是否可用,点击分别调用handleClose和handleSubmit方法。
预览对话框(el-dialog):
通过v-model绑定previewVisible控制显示隐藏,设置了标题、宽度、自定义模态框类等属性。
根据importResult.fileText的值(如’attr’或’alarm’),使用不同的el-table结构来展示预览数据,数据来源于previewData。
对话框底部有 “返回” 按钮,点击调用handlePreviewClose方法关闭预览对话框。

父页面

importVisible:一个ref类型的响应式变量,用于控制导入弹窗的显示与隐藏,初始值为false,当用户点击 “导入” 按钮时,会将其设置为true以显示导入弹窗。
file:同样是ref类型变量,用于存储用户选择要上传的文件对象,在后续的文件上传等操作中会使用到该文件。
importDialogRef:ref类型,用于获取导入对话框组件的引用,方便后续调用组件内的方法来更新导入结果等相关操作。
pre_import:ref类型,作为一个标志位,在文件预览等操作流程中起到控制作用,初始值为false,在特定逻辑中会被修改其值。
三、主要函数分析
handleImport函数
javascript
const handleImport = async () => {
try {
importVisible.value = true;
} catch (error) {
console.error(‘导入组件加载失败:’, error);
ElMessage.error(‘导入功能加载失败,请刷新页面重试’);
}
};
这个函数是用户点击 “导入” 按钮时触发的操作。它的主要目的是尝试显示导入弹窗,即将importVisible的值设为true。如果在这个过程中出现错误(比如导入组件加载异常),会在控制台打印错误信息,并通过ElMessage组件向用户提示导入功能加载失败,让用户刷新页面重试。
handleDownloadTemplate函数
javascript
const handleDownloadTemplate = async () => {
const res = await DeviceModelApi.downloadAlarmTemplate();
const blob = new Blob([res.data], {
type: ‘application/vnd.openxmlformats-officedocument.spreadsheetml.sheet’
});
const filename = 告警知识库导入模板_${new Date().getTime()}.xlsx;
const url = window.URL.createObjectURL(blob);
downloadFile(url, filename);

ElMessage.success(‘下载成功’);
};
此函数用于处理下载导入模板的操作。它首先调用后端DeviceModelApi的downloadAlarmTemplate方法获取模板数据,将返回的数据包装成Blob对象,设置好对应的文件类型(适用于 Excel 文件格式)。接着生成一个唯一的文件名(包含当前时间戳),创建一个临时的 URL 对象,然后通过downloadFile函数实现文件下载,最后向用户提示下载成功的消息。
handleFileUpload函数
javascript
const handleFileUpload = async (uploadFile) => {
file.value = uploadFile;
try {
const formData = new FormData();
formData.append(‘file’, uploadFile);
formData.append(‘clear_existing’, ‘true’);
formData.append(‘thing_model_id’, props.detailId);
formData.append(‘pre_import’, pre_import.value);

const res = await DeviceModelApi.importAlarms(formData);let str = res.data.msg || '';
const successCount = Number(str.match(/成功导入(\d+)条/)?.[1] || 0);
const failCount = Number(str.match(/失败(\d+)条/)?.[1] || 0);
const totalCount = successCount + failCount;let errorList = [];
if (failCount > 0) {errorList = res.data.data.error;
}// 更新导入对话框的数据
importDialogRef.value?.updateImportResult({totalCount,successCount: Number(successCount),failCount: Number(failCount),errorList,fileText: 'alarm'
});

} catch (error) {
ElMessage.error(error.response?.data?.msg || error.message || ‘上传失败’);
}
};
该函数负责实际的文件上传操作,接收用户选择的文件对象作为参数。首先将传入的文件对象赋值给file.value以便后续使用。然后创建一个FormData对象,将文件以及其他相关参数(如是否清除现有数据、关联的模型 ID、预导入标志等)添加进去。接着调用后端DeviceModelApi的importAlarms方法进行文件上传,并处理返回结果:从返回消息中解析出成功导入和失败的记录数量,根据失败数量获取错误列表(如果有),最后通过导入对话框组件的引用调用updateImportResult方法更新导入对话框中显示的导入结果信息,包括总数、成功数、失败数、错误列表以及文件类型标识等内容。若上传过程出现错误,则向用户提示相应的错误消息。
handlePreview函数
javascript
const handlePreview = () => {
if (file.value) {
pre_import.value = true;
handleFileUpload(file.value)
.then(() => {
// 当handleFileUpload执行成功(Promise状态变为resolved)后,调用fetchList
return fetchList();
})
.catch((error) => {
ElMessage.error(error.response?.data?.msg || error.message || ‘文件上传或数据获取失败’);
});
}
};

这个函数用于文件预览功能。它首先判断是否已经选择了文件(即file.value是否有值),如果有文件,则将pre_import的值设为true,接着调用handleFileUpload函数进行文件上传操作。当handleFileUpload执行成功(Promise 状态变为resolved)后,会继续调用fetchList函数来获取相关数据(可能是用于展示预览内容的数据)。如果在整个过程中出现错误(文件上传或者获取数据失败),会通过ElMessage向用户提示相应的错误信息。

<ImportDialogref="importDialogRef"v-model:visible="importVisible"@success="handleSearch"@download-template="handleDownloadTemplate"@submit="handleFileUpload"@preview="handlePreview"
/>
<template><el-dialogtitle="导入"v-model="dialogVisible"width="600px":close-on-click-modal="false"@close="handleClose"><div class="upload-area"><el-uploadclass="upload-dragger"dragaction="#":auto-upload="false":show-file-list="false"accept=".xlsx,.csv":on-change="handleFileChange"><div class="upload-content"><el-icon class="upload-icon" :size="80"><upload-filled /></el-icon><div class="upload-text"><p>把文件拖放到此处或 <span class="upload-link">重新上传</span></p></div></div></el-upload></div><p class="file-type-tip text-left">支持扩展名:.xlsx、.csv,文件大小不超过10M</p><div class="download-tip text-left">下载导入模板,根据模板提示完善内容<el-link type="primary" @click="handleDownloadTemplate">下载模板</el-link></div><div v-if="fileList.length" class="file-preview"><div class="file-item"><div class="file-info"><div class="file-icon-wrapper"><span class="file-type-text">csv</span></div><span class="file-name">{{ fileList[0].name }}</span><div class="file-actions"><el-icon v-if="uploadProgress === 100" class="success-icon" :size="24" color="#67C23A"><circle-check/></el-icon><el-linkclass="preview-link"type="primary"v-if="uploadProgress === 100"@click="handlePreview">文件预览</el-link></div></div><el-progress :percentage="uploadProgress" :show-text="false" class="upload-progress" /><div class="import-info" v-if="uploadProgress === 100"><p>共导入数据{{ importResult.totalCount }}条数据...</p><p v-if="importResult.failCount > 0" class="error-text">错误数据{{ importResult.failCount }}...错误数据将无法导入!</p><p v-if="importResult.successCount > 0">是否将本次 {{ importResult.successCount }} 条有效数据导入?</p><p v-if="importResult.successCount == 0">本次0条有效数据,无有效数据无法导入,请重新上传文件!</p></div></div></div><template #footer><div class="dialog-footer"><el-button @click="handleClose">取消</el-button><el-buttontype="primary"@click="handleSubmit":disabled="uploadProgress === 100 && fileList.length ? false : true">确定</el-button></div></template></el-dialog><!-- 预览弹窗 --><el-dialogv-model="previewVisible"title="文件预览"width="80%":modal-class="'preview-dialog'":close-on-click-modal="false":before-close="handlePreviewClose"append-to-body><div class="preview-content"><template v-if="importResult.fileText == 'attr'"><el-table:header-cell-style="{backgroundColor: '#F2F3F5',fontSize: '14px'}":data="previewData"height="calc(100vh - 200px)"style="width: 100%"><el-table-column prop="identifier" label="属性标识" width="180"></el-table-column><el-table-column prop="name" label="属性名称" width="180"></el-table-column><el-table-column prop="data_type" label="数据类型" width="180"><template #default="{ row }"><span>{{{int: '整数',float: '浮点数',string: '字符串',bool: '布尔值',enum: '枚举'}[row.data_type]}}</span></template></el-table-column><el-table-column prop="unit" label="单位" width="180"><template #default="{ row }"><span>{{ ['int', 'float'].includes(row.data_type) ? row.unit || '' : '-' }}</span></template></el-table-column><el-table-column prop="precision" label="精度" width="180"><template #default="{ row }"><span>{{row.data_type === 'float'? row.precision? `小数点后${row.precision}`: '': '-'}}</span></template></el-table-column><el-table-column prop="data_source" label="数据来源" width="180"><template #default="{ row }"><span>{{{gateway: '数采网关',rule_engine: '规则引擎'}[row.data_source]}}</span></template></el-table-column><el-table-column prop="rw_permission" label="读写权限" width="180"><template #default="{ row }"><span>{{{r: '只读',w: '只写',rw: '读写'}[row.rw_permission]}}</span></template></el-table-column><el-table-column prop="description" label="属性描述" width="180"></el-table-column><el-table-column label="错误类型" width="180"><template #default="scope"><span v-if="scope.row.error && scope.row.error.length > 0">{{scope.row.error[0].error}}</span><span v-else>无错误</span></template></el-table-column></el-table></template><template v-if="importResult.fileText == 'alarm'"><el-table:header-cell-style="{backgroundColor: '#F2F3F5',fontSize: '14px'}":data="previewData"height="calc(100vh - 200px)"style="width: 100%"><el-table-column prop="identifier" label="告警编码" ></el-table-column><el-table-column prop="name" label="告警信息" ></el-table-column><el-table-column prop="physical_name" label="关联部位" ></el-table-column><el-table-column label="错误类型"><template #default="scope"><span v-if="scope.row.error && scope.row.error.length > 0">{{scope.row.error[0].error}}</span><span v-else>无错误</span></template></el-table-column></el-table></template></div><template #footer><div class="preview-footer"><el-button @click="handlePreviewClose">返回</el-button></div></template></el-dialog>
</template><script setup>
import { ref, watch } from 'vue'
import { Upload, CircleCheck } from '@element-plus/icons-vue'const props = defineProps({visible: {type: Boolean,default: false}
})const importResult = ref({totalCount: 0,successCount: 0,failCount: 0,errorList: [],fileText: ''
})
// 更新导入结果
const updateImportResult = (result) => {importResult.value = result// 当获取到导入结果时,将进度条设置为 100%uploadProgress.value = 100
}
// 暴露方法给父组件
defineExpose({updateImportResult
})const emit = defineEmits(['update:visible', 'success', 'download-template', 'submit', 'preview'])const dialogVisible = ref(false)
const fileList = ref([])// 监听弹窗显示状态
watch(() => props.visible,(val) => {dialogVisible.value = val},{ immediate: true } // 添加 immediate 选项确保首次渲染时同步状态
)const uploadProgress = ref(0)// 文件变化
const handleFileChange = (file) => {// 检查文件大小const isLt10M = file.size / 1024 / 1024 < 10if (!isLt10M) {ElMessage.error('文件大小不能超过 10MB!')return}fileList.value = [file]uploadProgress.value = 0// 模拟上传进度到 90%const timer = setInterval(() => {if (uploadProgress.value < 90) {uploadProgress.value += 10} else {clearInterval(timer)// 触发父组件的事件,传递原始文件对象emit('submit', file.raw)}}, 500)
}// 移除文件
const handleRemoveFile = (index) => {fileList.value.splice(index, 1)
}// 下载模板
const handleDownloadTemplate = () => {emit('download-template')
}// 关闭弹窗
const handleClose = () => {emit('update:visible', false)fileList.value = []uploadProgress.value = 0importResult.value = {totalCount: 0,successCount: 0,failCount: 0,errorList: [],fileText: ''}// emit('')
}// 提交
const handleSubmit = () => {emit('preview')handleClose()
}// 预览相关
const previewVisible = ref(false)
const previewData = ref([])// 预览方法
const handlePreview = async () => {if (importResult.value.failCount == 0) returntry {let data = importResult.value.errorListlet tableData = data.map((item) => ({...item.row,error: item.error}))previewData.value = tableDatapreviewVisible.value = true} catch (error) {ElMessage.error('文件预览失败')}
}
// 关闭预览弹窗
const handlePreviewClose = () => {previewVisible.value = false
}
</script><style scoped lang="scss">
.upload-area {border: 1px dashed #dcdfe6;border-radius: 6px;text-align: center;.upload-dragger {:deep(.el-upload) {width: 100%;}:deep(.el-upload-dragger) {width: 100%;height: auto;border: none;}}.upload-content {display: flex;flex-direction: column;align-items: center;:deep(.upload-icon) {color: #c0c4cc;margin-bottom: 24px;svg {width: 80px;height: 80px;}}.upload-text {color: #606266;font-size: 14px;.upload-link {color: #409eff;cursor: pointer;}.upload-tip {font-size: 12px;color: #909399;margin-top: 12px;}}}
}.text-left {text-align: left;
}.file-type-tip {margin-top: 12px;font-size: 14px;color: #909399;
}.download-tip {margin-top: 16px;font-size: 14px;color: #606266;
}.file-preview {margin-top: 20px;padding: 16px;.file-item {.upload-progress {:deep(.el-progress-bar__outer) {background-color: #e9ecef;height: 4px !important;border-radius: 2px;}:deep(.el-progress-bar__inner) {transition: width 0.3s ease;border-radius: 2px;background-color: #409eff;}:deep(.el-progress__text) {font-size: 13px;color: #606266;}}.file-info {display: flex;align-items: center;gap: 12px;background: #f5f7fa;padding: 12px;border-radius: 4px;.file-icon-wrapper {display: flex;align-items: center;gap: 4px;background: #409eff;padding: 4px 8px;border-radius: 4px;color: white;.file-type-icon {font-size: 16px;}.file-type-text {font-size: 12px;text-transform: uppercase;}}.file-name {flex: 1;font-size: 14px;color: #606266;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}.file-actions {display: flex;align-items: center;gap: 12px;.success-icon {color: #67c23a;}.preview-link {font-size: 14px;color: #409eff;text-decoration: none;&:hover {opacity: 0.8;}}}}.import-info {margin-top: 10px;font-size: 14px;color: #606266;line-height: 1.8;.error-text {color: #f56c6c;}}}
}.dialog-footer {display: flex;justify-content: flex-end;gap: 12px;
}.preview-dialog-container {:deep(.el-dialog) {position: fixed;top: 50% !important;left: 50% !important;transform: translate(-50%, -50%);margin: 0 !important;height: 100vh;max-height: 100vh;display: flex;flex-direction: column;}:deep(.el-dialog__body) {flex: 1;overflow: hidden;padding: 10px;}:deep(.el-dialog__footer) {padding: 10px 20px;border-width: 1px 0px 0px 0px;border-style: solid;border-color: #e5e6eb;}
}.preview-content {height: 100%;
}.preview-footer {text-align: right;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/86821.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/86821.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/86821.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenCV中创建Mat对象

第1章 创建Mat对象 1.1. 创建空的 Mat 对象 cv::Mat mat; 1.2. 创建灰度图像 // 创建一个 3 行 4 列、8位无符号单通道矩阵&#xff08;相当于灰度图&#xff09; cv::Mat mat(3, 4, CV_8UC1); 1.3. 创建彩色图像 // 创建三通道矩阵&#xff08;相当于彩色图像&#xff0…

10、做中学 | 五年级下期 Golang循环控制

一、一个小需求 我想要打印10遍hello world,你想怎么编写呢&#xff1f; // 需求&#xff1a;打印10遍"hello world"fmt.Println("hello world")fmt.Println("hello world")fmt.Println("hello world")fmt.Println("hello world…

机器学习算法-K近邻算法-KNN

1. K近邻算法是什么&#xff1f; 定义&#xff1a; K近邻是一种基于实例的懒惰学习&#xff08;Lazy Learning&#xff09;算法&#xff0c;用于分类和回归任务。 核心思想&#xff1a;“物以类聚”——通过计算样本间的距离&#xff0c;找到目标点的最近K个邻居&#xff0c;…

基于vue框架的法律知识咨询普及系统gwuv7(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,知识类型,律师,律师推荐,法律知识,新闻类型,法律新闻,咨询律师 开题报告内容 基于Vue框架的法律知识咨询普及系统开题报告 一、研究背景与意义 随着法治社会建设的深入推进&#xff0c;公众对法律知识的需求呈现爆发式增长。然而…

Netty 揭秘CompositeByteBuf:零拷贝优化核心技术

CompositeByteBuf 类 核心设计目标​​ ​​虚拟缓冲区​​&#xff1a;将多个 ByteBuf 合并为单一逻辑视图&#xff0c;减少数据复制。​​零拷贝优化​​&#xff1a;通过组合而非复制提升性能。​​引用计数管理​​&#xff1a;统一管理底层 ByteBuf 的生命周期。 核心成…

用css实现文字字体颜色渐变

用css实现文字字体颜色渐变 background-clip 是CSS3中新增的属性&#xff0c;可以用于指定背景图片或颜色的绘制范围。利用 background-clip 属性实现文字颜色从左到右、从绿到白的渐变效果&#xff1a; 代码如下&#xff1a; .gradient-color {background-image: linear-gr…

SpringBatch处理数据性能优化

SpringBatch的Step默认使用同步方式批量处理数据&#xff0c;也可以通过配置将读数改为同步&#xff0c;处理和写入改为异步方式。 1、同步处理Step SpringBatch的Step一般由ItemReader、ItemProcessor和ItemWriter组成&#xff0c;其中ItemProcessor是可选的。他的设计思路的…

【机器学习深度学习】前馈神经网络(单隐藏层)

目录 一、什么是前馈神经网络&#xff1f; 二、数学表达式是什么&#xff1f; 三、为什么需要“非线性函数”&#xff1f; 四、NumPy 实现前馈神经网络代码示例 五、 运行结果 六、代码解析 6.1 初始化部分 6.2 前向传播 6.3 计算损失&#xff08;Loss&#xff09; 6…

设计模式系列(08):创建型模式 - 原型模式

系列导读&#xff1a;完成创建型模式的学习&#xff0c;我们来看最后一个创建型模式——原型模式。它通过复制已有对象来创建新对象&#xff0c;是一种独特的创建方式。 解决什么问题&#xff1a;通过复制现有对象来创建新对象&#xff0c;而不是重新实例化。适用于对象创建成本…

区块链到底是什么?

区块链本质上是一种去中心化的分布式账本技术&#xff0c;具有以下核心特点&#xff1a; - 去中心化&#xff1a;没有中央管理机构&#xff0c;数据由网络中的多个节点共同维护&#xff0c;比如比特币网络中各个节点都保存着完整账本。 - 分布式存储&#xff1a;数据不是存在一…

系统架构设计师论文分享-论ATAM的使用

我的软考历程 摘要 2023年2月&#xff0c;我司通过了研发纱线MES系统的立项&#xff0c;该系统为国内纱线工厂提供SAAS服务&#xff0c;旨在提高纱线工厂的数字化和智能化水平。我在本项目中担任系统架构设计师&#xff0c;负责整个项目的架构设计工作。本文结合我在该项目中…

vue-28(服务器端渲染(SSR)简介及其优势)

服务器端渲染&#xff08;SSR&#xff09;简介及其优势 服务器端渲染&#xff08;SSR&#xff09;是现代网络应用的关键技术&#xff0c;特别是使用 Vue.js 等框架构建的应用。它通过在服务器上渲染初始应用状态来弥补传统单页应用&#xff08;SPA&#xff09;的局限性&#x…

工业电子 | 什么是SerDes,为何工业和汽车应用需要它?

重点内容速览&#xff1a; 1. 什么是SerDes&#xff1f; 2. ADI&#xff1a;私有协议的GMSL将向公有协议转变 3. TI&#xff1a;工业和汽车有两套SerDes解决方案 4. Microchip&#xff1a;推出通用协议SerDes芯片 5. 罗姆&#xff1a;主要针对汽车领域 6. 国产SerDes芯…

大事件项目记录4-用户接口开发-更新用户基本信息

4&#xff09;更新用户基本信息。 UserController.java&#xff1a; UserMapper.java&#xff1a; Update("update user set nickname #{nickname},email #{email},update_time #{updateTime} where id #{id}")void update(User user); UserServiceInterface…

Transformer结构--输入编码(BPE,PE)

在Transformer结构中&#xff0c;输入编码是模型处理文本数据的关键步骤&#xff0c;其中**BPE&#xff08;Byte Pair Encoding&#xff0c;字节对编码&#xff09;和PE&#xff08;Positional Encoding&#xff0c;位置编码&#xff09;**是两种重要的编码方式&#xff0c;它们…

Confluence-测试用例设计指导方法

测试经验知识库 典型的测试场景验证点各个项目有价值的经验和测试点 测试经验知识库 - 草稿测试用例执行量化指导建议 何时需要进行全量测试和如何定义和执行测试用例量的一些建议和标准 端对端&#xff08;E2E&#xff09;测试用例设计指导方案 在测试行业中&#xff0c;端到端…

浅析JVM

一、JVM运行流程 如图&#xff1a; JVM由四个部分构成&#xff1a; 1.类加载器 加载类文件到内存2.运行时数据区 写的程序需要加载到这里才能运行3.执行引擎 负责解释命令&#xff0c;提交操作系统执行4.本地接口 融合不同编程语言为java所用&#xff0c;如Java程序驱动打印…

多个 Job 并发运行时共享配置文件导致上下文污染,固化 Jenkins Job 上下文

基于 context.py 固化 Jenkins Job 上下文的完整方案&#xff0c;适用于你当前的工作流&#xff08;Python Jenkins Pipeline&#xff09;&#xff0c;解决&#xff1a; 多个 Job 并发运行时共享配置文件导致上下文污染&#xff1b;读取环境变量或 JSON 文件时被其他 Job 修改…

简木易支付系统 功能齐全,对接接口超多

简木易支付系统&#xff0c;作为一款引领行业潮流的卓越支付解决方案&#xff0c;依托先进的 PHP MySQL 技术架构精心打造。在开发过程中&#xff0c;它巧妙运用了功能强大的 ThinkPHP8 框架&#xff0c;完美融合前端主流技术 Vue、Element 以及 Layuiadmin&#xff0c;共同铸…

【软考高项论文】信息系统项目的人力资源管理

摘要 本文围绕信息系统项目的人力资源管理展开论述。以我在2024年参与的为大型国有企业构建供应链管理系统项目为例&#xff0c;阐述了项目人力资源管理的主要流程&#xff0c;包括规划、组建、建设和管理团队四个过程&#xff0c;以及所运用的工具和理论。同时&#xff0c;分…