前端组件vue

最终效果
在这里插入图片描述

<template><div ><div class="file-list" v-if="existingFiles.length > 0"><div class="file-card" v-for="(file, index) in existingFiles" :key="file.id"><div class="file-preview"><i v-if="file.type === 'pdf'" class="el-icon-document pdf-preview"></i><i v-else-if="file.type === 'doc' || file.type === 'docx'" class="el-icon-document doc-preview"></i><i v-else-if="file.type === 'image'" class="el-icon-picture-outline"></i><i v-else class="el-icon-document other-preview"></i></div><div class="file-name">{{ file.originalFileName }}</div><div class="file-actions"><el-button type="primary" icon="el-icon-view" size="mini" circle @click="handlePreview(file)"></el-button><el-button type="success" icon="el-icon-download" size="mini" v-if="showDownLoadBut" circle @click="downloadFile(file)"></el-button><el-button type="danger" icon="el-icon-delete" size="mini" v-if="showDeleteBut" circle @click="handleDelete(file, index)"></el-button></div></div></div><el-alertv-elsetitle="当前尚未上传任何合同"type="warning"show-iconstyle="margin: 20px 0;"></el-alert><div class="upload-demo" v-if="existsUploadBut"><el-uploadref="upload":action="uploadUrl":headers="headers"multiple:on-success="handleUploadSuccess":show-file-list="false"accept=".pdf,.doc,.docx,.jpg,.jpeg,.png"><el-button size="medium" type="primary" icon="el-icon-plus">添加合同文件</el-button><div slot="tip" class="el-upload__tip" style="margin-top: 10px;">支持上传PDF、Word文档和图片文件,单个文件不超过10MB</div></el-upload></div><!-- 文件预览弹窗 --><el-dialog:title="previewTitle":visible.sync="previewVisible"width="80%"top="5vh"><div class="preview-container"><img v-if="previewType === 'image'" :src="previewUrl"><iframev-else-if="previewType === 'pdf'":src="previewUrl"class="preview-iframe"></iframe><div v-else><p>不支持在线预览,请下载后查看</p><el-button type="primary" icon="el-icon-download" @click="downloadFile(previewFile)">下载文件</el-button></div></div></el-dialog></div>
</template>
<script>export default {name: "FileUploadPreview",props:{// 上传文件目录fileDirectory: {type: String,require: true,default: ''},// 文件列表fileList:{type:Array,default:()=>[]},// 上传按钮existsUploadBut:{type: Boolean,default: false},// 下载按钮是否显示showDownLoadBut:{type: Boolean,default: false},// 删除按钮showDeleteBut:{type: Boolean,default: false}},data() {return {previewVisible: false,existingFiles: this.fileList,previewUrl: '',previewType: '',previewTitle: '查看附件',previewFile: null,// 请求头 - 包含认证Tokenheaders: {Authorization: 'Bearer ' + this.$store.getters.token},uploadUrl: process.env.VUE_APP_BASE_API + "/common/upload?fileDirectory="+this.fileDirectory,imageDialogVisible: false, // 图片弹窗可见性previewVisible: false, // 预览弹窗可见性previewImageUrl: '', // 预览图片URLtempImageList: [], // 临时图片列表};},created() {},methods: {// 移除待上传文件removeNewFile(index) {this.existingFiles.splice(index, 1);},// 预览文件handlePreview(file) {this.previewFile = file;this.previewTitle = `预览文件 - ${file.originalFileName}`;this.previewUrl = file.url==null?file.filePath:"";this.previewType = this.getFileType(file.originalFileName);this.previewVisible = true;},// 删除文件handleDelete(file, index) {this.$confirm(`确定要删除合同 "${file.originalFileName}"?`, '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {// 模拟API删除请求setTimeout(() => {this.existingFiles.splice(index, 1);this.$message.success(`合同 "${file.originalFileName}" 已删除`);}, 500);}).catch(() => {});},// 获取文件类型getFileType(filename) {const ext = filename.split('.').pop().toLowerCase();if (['jpg','jpeg','png','gif'].includes(ext)) return 'image';if (ext === 'pdf') return 'pdf';if (['doc','docx'].includes(ext)) return 'doc';return 'other';},// 格式化文件大小formatFileSize(bytes) {if (bytes === 0) return '0 Bytes';const k = 1024;const sizes = ['Bytes', 'KB', 'MB', 'GB'];const i = Math.floor(Math.log(bytes) / Math.log(k));return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];},// 下载文件downloadFile(file) {this.$message.info(`开始下载: ${file.originalFileName}`);// 实际项目中这里应该是文件下载逻辑this.$download.systemDownLoadFile(file.filePath,file.originalFileName);},// 打开图片弹窗openImageDialog(row) {this.imageDialogVisible = true;// 加载已有图片 (实际项目中从后端获取)getWarehouseFiles(row.uuid).then(resp=>{this.tempImageList = resp.data;});},// 图片上传前校验beforeImageUpload(file) {const isImage = file.type.startsWith('image/');const isPdf = file.type === 'application/pdf';const isLt10M = file.size / 1024 / 1024 < 10;if (!(isImage || isPdf)) {this.$message.error('只能上传图片或PDF文件!');return false;}if (!isLt10M) {this.$message.error('文件大小不能超过10MB!');return false;}return true;},// 图片上传成功处理handleUploadSuccess(response, file, fileList) {// 实际项目中根据接口返回调整//   this.newFiles = fileList.map(f => ({//     originalFileName: f.response?.originalFilename || f.originalFileName,//     newFileName: f.response?.newFileName || f.newFileName,//     filePath: f.response?.filePath || f.filePath,//     fileSize: f.response?.size || f.fileSize,//     fileShowSize: f.response?.showSize || f.fileShowSize,//     fileType: f.response?.fileType || f.fileType,//     warehouseManagerUuid: f.response?.warehouseManagerUuid || f.warehouseManagerUuid,//     url: f.response?.url || f.url,//   }));debuggerif(response.code==200){var tempData={originalFileName: response.originalFilename,newFileName:response.newFileName,filePath:response.filePath,fileSize:response.size,fileShowSize: response.showSize,fileType:response.fileType,name:response.originalFilename,url:response.url}this.existingFiles.push(tempData);}},// 预览图片handlePictureCardPreview(file) {this.previewImageUrl = file.url;this.previewVisible = true;},// 移除图片handleRemove(file, fileList) {this.tempImageList = fileList;},}
};
</script>
<style scoped>body {font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial, sans-serif;background-color: #f5f7fa;color: #333;padding: 20px;}.container {max-width: 1200px;margin: 0 auto;background: white;border-radius: 8px;box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);padding: 20px;}.header {display: flex;justify-content: space-between;align-items: center;padding: 15px 0;border-bottom: 1px solid #ebeef5;margin-bottom: 20px;}.header h1 {color: #409EFF;font-size: 24px;}.sub-title {color: #909399;margin: 10px 0 20px;}.contract-actions {display: flex;gap: 10px;margin-bottom: 20px;}.file-card {position: relative;border-radius: 6px;overflow: hidden;transition: all 0.3s;border: 1px solid #ebeef5;}.file-card:hover {box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);}.file-name {padding: 8px;font-size: 12px;text-align: center;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;background: #f8f8f8;}.file-actions {position: absolute;top: 5px;right: 5px;display: flex;gap: 5px;opacity: 0;transition: opacity 0.3s;}.file-card:hover .file-actions {opacity: 1;}.file-preview {display: flex;align-items: center;justify-content: center;height: 100px;background: #f5f7fa;}.file-preview i {font-size: 40px;color: #409EFF;}.pdf-preview {color: #F56C6C;}.doc-preview {color: #409EFF;}.other-preview {color: #909399;}.file-list {display: grid;grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));gap: 15px;margin-top: 20px;}.preview-container {width: 100%;height: 70vh;}.preview-container img {max-width: 100%;max-height: 100%;display: block;margin: 0 auto;}.preview-iframe {width: 100%;height: 100%;border: none;}.footer {margin-top: 20px;text-align: center;color: #909399;font-size: 14px;padding: 10px;border-top: 1px solid #ebeef5;}.upload-demo {margin-top: 20px;}.demo-table {margin-top: 20px;}.status-badge {display: inline-block;padding: 2px 8px;border-radius: 4px;font-size: 12px;}.status-success {background: #f0f9eb;color: #67c23a;}.status-warning {background: #fdf6ec;color: #e6a23c;}
</style>

使用浏览器确认保存路径

在这里插入图片描述在这里插入图片描述

systemDownLoadFile(filePath,fileName) {var url = baseURL + "/common/systemDownLoadFile?filePath=" + encodeURIComponent(filePath)+"&fileName="+encodeURIComponent(fileName);axios({method: 'get',url: url,responseType: 'blob',headers: { 'Authorization': 'Bearer ' + getToken() }}).then((res) => {const isBlob = blobValidate(res.data);if (isBlob) {const blob = new Blob([res.data])this.saveAs(blob, decodeURIComponent(res.headers['download-filename']))} else {this.printErrMsg(res.data);}})},

后端代码

 /*** 下载文件** @param filePath 文件路径* @param fileName 文件原始名* @param response* @param request*/@GetMapping("/systemDownLoadFile")public void systemDownLoadFile(@RequestParam("filePath") String filePath, @RequestParam("fileName") String fileName, HttpServletResponse response,HttpServletRequest request) {try {if (!FileUtils.checkAllowDownload(fileName)) {throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));}String configByKey = iSysConfigService.selectConfigByKey(SysConfigConstants.UPLOAD_ROOT);
//            String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);String fileAllPath = configByKey + filePath;// 上传文件路径if (StringUtils.isEmpty(configByKey)) {log.info("服务器文件上传地址不能为空,请检查参数设置的  {} 是否配置值", SysConfigConstants.UPLOAD_ROOT);return;}response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);FileUtils.setAttachmentResponseHeader(response, fileName);FileUtils.writeBytes(fileAllPath, response.getOutputStream());} catch (Exception e) {log.error("下载文件失败", e);}}

下载resources目录下的文件

在这里插入图片描述

@GetMapping("/downloadTemplates")ResponseEntity<Resource> downloadFile(@RequestParam("fileName") String fileName) {// 验证文件名安全(防止路径遍历攻击)if (!isValidFileName(fileName)) {throw new FileDownloadException("文件名不合法", HttpStatus.BAD_REQUEST);}// 从resources目录加载文件Resource resource = new ClassPathResource("templates/" + fileName);// 检查文件是否存在if (!resource.exists()) {throw new FileDownloadException("文件不存在", HttpStatus.NOT_FOUND);}try {// 设置响应头HttpHeaders headers = new HttpHeaders();headers.add(HttpHeaders.CONTENT_DISPOSITION,"attachment; filename=\"" + encodeFilename(fileName) + "\"");return ResponseEntity.ok().headers(headers).contentLength(resource.contentLength()).contentType(MediaType.APPLICATION_OCTET_STREAM).body(resource);} catch (IOException e) {return ResponseEntity.internalServerError().build();}}/*** 安全验证文件名(防止路径遍历攻击)** @param fileName* @return*/private boolean isValidFileName(String fileName) {return fileName != null &&!fileName.contains("..") &&!fileName.contains("/") &&!fileName.contains("\\");}/*** 处理中文文件名乱码问题** @param fileName* @return*/private String encodeFilename(String fileName) {return new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);}

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

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

相关文章

【CS创世SD NAND征文】SD NAND赋能新一代儿童智能玩具

基于全志F1C100S的高可靠存储方案 文章目录 基于全志F1C100S的高可靠存储方案[toc]前言 一、应用产品介绍&#xff1a;儿童智能玩具的需求演变二、技术方案介绍&#xff1a;构建智能玩具的"大脑"与"记忆库"三、核心技术模块分析3.1 主控芯片&#xff1a;全…

mac触摸板设置右键

在 Mac 笔记本上&#xff0c;触摸板默认没有物理左右键分区&#xff0c;但可以通过以下方式实现“右键”功能&#xff08;称为 辅助点按&#xff09;&#xff1a; 一、启用与使用右键&#xff08;辅助点按&#xff09; 步骤1&#xff1a;检查系统设置 点击屏幕左上角 &#x…

稳定币发行量创纪录地超过 Visa 交易量

稳定币发行量创纪录地超过 Visa 交易量 稳定币的崛起正在重塑全球金融格局&#xff0c;华夏基金首席执行官甘天&#xff08;Gan Tian&#xff09;强调了稳定币的快速增长&#xff0c;并指出稳定币的交易量在短短五年内就超过了Visa 40年的交易量。这凸显了货币使用的转变。 稳…

编程 IDE 混战简史:从 Copilot 到 Claude Code,一场重塑开发方式的战争

unsetunset引言&#xff1a;开发新纪元的序幕unsetunset 编程世界&#xff0c;从最初依赖打孔卡和简陋的命令行工具&#xff0c;到如今功能琳琅满目的集成开发环境&#xff08;IDE&#xff09;&#xff0c;每一步都见证了效率与智能的飞跃。IDE作为开发者与代码交互的核心界面&…

软测八股--计算机网络

计算机网络基础 局域网广域网 局域网&#xff1a;一个区域内由多台计算机互联成的计算机组&#xff08;学校&#xff0c;办公室&#xff0c;公司/学校等&#xff09;。可以实现文件管理&#xff0c;应用软件管理&#xff0c;答应及管理&#xff0c;扫描仪共享等。是封闭的&am…

某省职业院校技能大赛 高职组“信息安全管理与评估”赛项第二部分:应急响应

&#xff01;&#xff01;&#xff01;需要环境可私信博主&#xff01;&#xff01;&#xff01; &#xff01;&#xff01;&#xff01;若有错误欢迎指正&#xff01;:) 序号任务要求1提交攻击者的两个内网IP地址2提交网站管理员用户的用户名和密码3提交黑客得到 mysql 服务的…

OkHttp 简单配置

OkHttpClient 的简单配置&#xff0c;包含重试&#xff0c;线程池 Configuration public class OkHttpConfig {Bean("deSourceOkHttp")public OkHttpClient okHttpClient() {return new OkHttpClient.Builder().connectTimeout(60, TimeUnit.SECONDS).readTimeout(3…

群晖nas安装moodle跳坑记录

1&#xff0c;套件里面直接安装 会安装好几个依赖&#xff0c;包括php apach &#xff0c;数据库。这些安装的时间就比较长。 安装完成后自动安装 Moodle。 过程也很长数据库里面的表有接近500张。 2&#xff0c;安装位置 顺便提一下 nas程序的安装位置 这两个位置好像都不是…

鸿蒙HarmonyOS 5小游戏实践:打砖块游戏(附:源代码)

打砖块是一款经典的游戏&#xff0c;它简单易懂却又充满挑战性。本文将介绍如何使用ArkUI框架开发一个完整的打砖块游戏&#xff0c;涵盖游戏逻辑设计、UI实现和交互处理等核心内容。 游戏架构设计 我们的打砖块游戏采用了组件化设计&#xff0c;主要分为两个部分&#xff1a;…

Flutter MobX 响应式原理与实战详解

&#x1f4da; Flutter 状态管理系列文章目录 Flutter 状态管理(setState、InheritedWidget、 Provider 、Riverpod、 BLoC / Cubit、 GetX 、MobX 、Redux) setState() 使用详解&#xff1a;原理及注意事项 InheritedWidget 组件使用及原理 Flutter 中 Provider 的使用、注…

浅谈国产数据库多租户方案:提升云计算与SaaS的资源管理效率

近年来&#xff0c;“数据库多租户”这一概念在技术圈内频频出现&#xff0c;成为云计算和SaaS&#xff08;软件即服务&#xff09;架构中的重要组成部分。多租户架构不仅为企业提供了高效的资源隔离与共享解决方案&#xff0c;还能大幅降低成本&#xff0c;提高系统的可扩展性…

Wpf的Binding

前言 wpf的Binding就像一个桥梁&#xff0c;它的作用就是连接逻辑层与界面层&#xff0c;既能够把逻辑层的数据搬到界面层展示&#xff0c;又能将界面层的数据更改后传递到逻辑层&#xff0c;Binding的数据来源就是Binding的源&#xff0c;数据展示的地方就是Binding的目标。 …

嵌入式单片机中SPI串行外设接口控制与详解

串行外设接口(Serial Peripheral Interface)的简称也叫做SPI,是一种高速的、全双工同步通信的一种接口,串行外设接口一般是需要4根线来进行通信(NSS、MISO、MOSI、SCK),但是如果打算实现单向通信(最少3根线),就可以利用这种机制实现一对多或者一对一的通信。 第一:…

【世纪龙科技】新能源汽车动力电池总成装调与检修教学软件

在新能源汽车产业“技术迭代快、安全要求高、实操风险大”的背景下&#xff0c;职业院校如何以“项目式教学改革”为突破口&#xff0c;破解传统实训“高成本、高风险、低效率”的困局&#xff1f;江苏世纪龙科技以桌面VR沉浸式技术为支点&#xff0c;推出《新能源动力电池总成…

GO泛型编程面试题及参考答案

目录 什么是 Go 中的泛型?Go 从哪个版本开始支持泛型? 在 Go 中如何定义一个带类型参数的函数? 如何为结构体添加类型参数? 使用 any 关键字和自定义类型约束有什么区别? 泛型中~T 的语义及其实际应用是什么? 如何在函数中使用多个类型参数?举例说明。 Go 泛型支…

ReactRouter-404路由配置以及两种路由模式

404路由 场景&#xff1a;当浏览器输入url的路径在整个路由配置中都找不到对应的path&#xff0c;为了用户体验&#xff0c;可以使用404兜底组件进行渲染 实现步骤 准备一个404组件在路由表数组的末尾&#xff0c;以*号作为路由path配置路由 新建404组件 const NotFound (…

《Kubernetes》Service 详解+Ingress

主要介绍kubernetes的流量负载组件&#xff1a;Service和Ingress。 1. Service 1.1 Service介绍 在kubernetes中&#xff0c;pod是应用程序的载体&#xff0c;我们可以通过pod的ip来访问应用程序&#xff0c;但是pod的ip地址不是固定的&#xff0c;这也就意味着不方便直接采用…

常见网络知识,宽带、路由器

常见网络知识&#xff0c;宽带、路由器 1、关于光猫、桥接和路由接法 现在的光猫都带有路由功能&#xff0c;即光猫、路由一体。不需要路由器也能让设备连上&#xff0c;但是一般来说路由功能穿墙有限&#xff0c;放在弱电箱/多媒体箱里的光猫发射出来的wifi信号其实是很难在…

Android应用缓存清理利器:WorkManager深度实践指南

本文将带你全面掌握使用WorkManager实现缓存清理的技术方案&#xff0c;从基础原理到性能优化&#xff0c;提供完整代码实现和工程实践指南 一、缓存清理的必要性与挑战 在Android应用开发中&#xff0c;缓存管理是优化应用性能的关键环节。随着应用使用时间增长&#xff0c;缓…

如何理解构件“可独立部署”的特性

构件的“可独立部署”特性是其区别于普通代码模块的核心特征之一&#xff0c;我们可以通过生活案例和技术原理解释来理解这一特性&#xff1a; 一、生活类比&#xff1a;从“家电维修”看独立部署 假设你家的空调坏了&#xff0c;维修时只需拆开空调外机更换压缩机&#xff0…