src/main/java/com/zy/crm/common/utils/FileSaveExampleUtil.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/zy/crm/manager/controller/PlanController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/webapp/static/js/FileSaver.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/webapp/static/js/plan/plan.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/webapp/static/js/priOnline/priOnline.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/webapp/views/plan/plan.html | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/webapp/views/priOnline/priOnline.html | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/main/java/com/zy/crm/common/utils/FileSaveExampleUtil.java
@@ -1,14 +1,23 @@ package com.zy.crm.common.utils; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.*; import org.springframework.core.io.Resource; import java.net.URLEncoder; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import lombok.Data; import javax.servlet.http.HttpServletResponse; import org.springframework.core.io.UrlResource; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.nio.file.Path; import lombok.Data; public class FileSaveExampleUtil { @@ -81,6 +90,128 @@ } } // public static FileDTO downloadFile(String directoryPath,HttpServletResponse response) { // File file = new File(directoryPath); // if (file.exists()) { // try { // response.setContentType("application/vnd.ms-excel"); // response.setHeader("Content-Disposition", "attachment; filename=" + file.getName()); // // FileInputStream fileInputStream = new FileInputStream(file); // OutputStream outputStream = response.getOutputStream(); // byte[] buffer = new byte[1024]; // int length; // while ((length = fileInputStream.read(buffer)) != -1) { // outputStream.write(buffer, 0, length); // } // outputStream.flush(); // outputStream.close(); // fileInputStream.close(); // // return new FileDTO(true, file.getName(), null); // } catch (IOException e) { // e.printStackTrace(); // } // } // // return new FileDTO(false, null, "文件不存在"); // // // } // public static void downloadFile(String directoryPath,HttpServletResponse response) { // try { //// File file = new File(directoryPath); //// InputStream inputStream = new FileInputStream(file); //// //输出文件 //// InputStream fis = new BufferedInputStream(inputStream); //// byte[] buffer = new byte[fis.available()]; //// fis.read(buffer); //// fis.close(); //// response.reset(); //// //// //获取文件的名字再浏览器下载页面 //// String name = file.getName(); //// response.addHeader("Content-Disposition", "attachment;filename=" + new String(name.getBytes(), "iso-8859-1")); //// response.addHeader("Content-Length", "" + file.length()); //// OutputStream out = new BufferedOutputStream(response.getOutputStream()); //// response.setContentType("application/octet-stream"); //// out.write(buffer); //// out.flush(); //// out.close(); // File file = new File(directoryPath); // if (!file.exists()) { // // 文件不存在,可以根据实际情况进行处理 // return; // } // // response.reset(); // response.setContentType("application/octet-stream"); // response.setContentLength((int) file.length()); // response.setHeader("Content-Disposition", "attachment;filename=" + file.getName()); // // BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); // BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream()); // byte[] buffer = new byte[4096]; // int bytesRead; // while ((bytesRead = bis.read(buffer)) != -1) { // bos.write(buffer, 0, bytesRead); // } // bos.flush(); // // bis.close(); // bos.close(); // } catch (IOException e) { // e.printStackTrace(); // } // } public static ResponseEntity<Resource> downloadFile(String filename, HttpServletResponse response) { try { File file = new File(filename); //获取文件的名字再浏览器下载页面 String name = file.getName(); // 构建文件路径 Path filePath = Paths.get(filename); Resource resource = new UrlResource(filePath.toUri()); if (resource.exists()) { // 设置响应头 HttpHeaders headers = new HttpHeaders(); // headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); response.setContentType("application/octet-stream"); headers.setContentDispositionFormData("attachment", filename); response.addHeader("Content-Disposition", "attachment;filename=" + new String(name.getBytes(), "UTF-8")); // headers.setContentDispositionFormData("attachment", URLEncoder.encode(name, "UTF-8")); // response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(name, "UTF-8")); // 返回文件响应 return ResponseEntity.ok() .headers(headers) .body(resource); // // 设置响应头 // HttpHeaders headers = new HttpHeaders(); // headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); // headers.setContentDispositionFormData("attachment", URLEncoder.encode(name, "UTF-8")); // response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(name, "UTF-8")); // // // 返回文件响应 // return ResponseEntity.ok() // .headers(headers) // .body(resource); } else { response.setStatus(HttpServletResponse.SC_NOT_FOUND); return null; } } catch (IOException e) { e.printStackTrace(); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return null; } } public static List<FileDTO> viewFileList(String directoryPath) { List<FileDTO> fileList = new ArrayList<>(); @@ -106,6 +237,8 @@ private String name; private long size; private String path; private boolean success; private String errorMessage; public FileDTO(String name, long size, String path) { this.name = name; @@ -119,6 +252,12 @@ // this.path = path; } public FileDTO(boolean success, String name, String errorMessage) { this.success = success; this.name = name; this.errorMessage = errorMessage; } // getters and setters } src/main/java/com/zy/crm/manager/controller/PlanController.java
@@ -36,6 +36,12 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import org.springframework.core.io.Resource; import org.springframework.core.io.FileSystemResource; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import javax.servlet.http.HttpServletResponse; import java.io.File; @@ -254,6 +260,19 @@ } } @RequestMapping(value = "/plan/download/file/auth") // @ManagerAuth public R downloadFile(@RequestParam("downloadUrl") String downloadUrl,HttpServletResponse response){ System.out.println("---开始---"); // MultipartFile try{ ResponseEntity<Resource> resourceResponseEntity = FileSaveExampleUtil.downloadFile(downloadUrl, response); return R.ok(resourceResponseEntity); }catch (Exception e){ return R.error(); } } @PostMapping(value = "/plan/approval/auth") src/main/webapp/static/js/FileSaver.js
New file @@ -0,0 +1,172 @@ /* * FileSaver.js * A saveAs() FileSaver implementation. * * By Eli Grey, http://eligrey.com * * License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT) * source : http://purl.eligrey.com/github/FileSaver.js */ // The one and only way of getting global scope in all environments // https://stackoverflow.com/q/3277182/1008999 var _global = typeof window === 'object' && window.window === window ? window : typeof self === 'object' && self.self === self ? self : typeof global === 'object' && global.global === global ? global : this function bom (blob, opts) { if (typeof opts === 'undefined') opts = { autoBom: false } else if (typeof opts !== 'object') { console.warn('Deprecated: Expected third argument to be a object') opts = { autoBom: !opts } } // prepend BOM for UTF-8 XML and text/* types (including HTML) // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { return new Blob([String.fromCharCode(0xFEFF), blob], { type: blob.type }) } return blob } function download (url, name, opts) { var xhr = new XMLHttpRequest() xhr.open('GET', url) xhr.responseType = 'blob' xhr.onload = function () { saveAs(xhr.response, name, opts) } xhr.onerror = function () { console.error('could not download file') } xhr.send() } function corsEnabled (url) { var xhr = new XMLHttpRequest() // use sync to avoid popup blocker xhr.open('HEAD', url, false) try { xhr.send() } catch (e) {} return xhr.status >= 200 && xhr.status <= 299 } // `a.click()` doesn't work for all browsers (#465) function click (node) { try { node.dispatchEvent(new MouseEvent('click')) } catch (e) { var evt = document.createEvent('MouseEvents') evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null) node.dispatchEvent(evt) } } // Detect WebView inside a native macOS app by ruling out all browsers // We just need to check for 'Safari' because all other browsers (besides Firefox) include that too // https://www.whatismybrowser.com/guides/the-latest-user-agent/macos var isMacOSWebView = _global.navigator && /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent) var saveAs = _global.saveAs || ( // probably in some web worker (typeof window !== 'object' || window !== _global) ? function saveAs () { /* noop */ } // Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView : ('download' in HTMLAnchorElement.prototype && !isMacOSWebView) ? function saveAs (blob, name, opts) { var URL = _global.URL || _global.webkitURL // Namespace is used to prevent conflict w/ Chrome Poper Blocker extension (Issue #561) var a = document.createElementNS('http://www.w3.org/1999/xhtml', 'a') name = name || blob.name || 'download' a.download = name a.rel = 'noopener' // tabnabbing // TODO: detect chrome extensions & packaged apps // a.target = '_blank' if (typeof blob === 'string') { // Support regular links a.href = blob if (a.origin !== location.origin) { corsEnabled(a.href) ? download(blob, name, opts) : click(a, a.target = '_blank') } else { click(a) } } else { // Support blobs a.href = URL.createObjectURL(blob) setTimeout(function () { URL.revokeObjectURL(a.href) }, 4E4) // 40s setTimeout(function () { click(a) }, 0) } } // Use msSaveOrOpenBlob as a second approach : 'msSaveOrOpenBlob' in navigator ? function saveAs (blob, name, opts) { name = name || blob.name || 'download' if (typeof blob === 'string') { if (corsEnabled(blob)) { download(blob, name, opts) } else { var a = document.createElement('a') a.href = blob a.target = '_blank' setTimeout(function () { click(a) }) } } else { navigator.msSaveOrOpenBlob(bom(blob, opts), name) } } // Fallback to using FileReader and a popup : function saveAs (blob, name, opts, popup) { // Open a popup immediately do go around popup blocker // Mostly only available on user interaction and the fileReader is async so... popup = popup || open('', '_blank') if (popup) { popup.document.title = popup.document.body.innerText = 'downloading...' } if (typeof blob === 'string') return download(blob, name, opts) var force = blob.type === 'application/octet-stream' var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent) if ((isChromeIOS || (force && isSafari) || isMacOSWebView) && typeof FileReader !== 'undefined') { // Safari doesn't allow downloading of blob URLs var reader = new FileReader() reader.onloadend = function () { var url = reader.result url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;') if (popup) popup.location.href = url else location = url popup = null // reverse-tabnabbing #460 } reader.readAsDataURL(blob) } else { var URL = _global.URL || _global.webkitURL var url = URL.createObjectURL(blob) if (popup) popup.location = url else location.href = url popup = null // reverse-tabnabbing #460 setTimeout(function () { URL.revokeObjectURL(url) }, 4E4) // 40s } } ) _global.saveAs = saveAs.saveAs = saveAs if (typeof module !== 'undefined') { module.exports = saveAs; } src/main/webapp/static/js/plan/plan.js
@@ -201,7 +201,7 @@ var uploadListIns = upload.render({ elem: '#data-btn-file2' ,elemList: $('#data-btn-file3') //列表元素对象 ,url: '/plan/insert/file/auth' //此处用的是第三方的 http 请求演示,实际使用时改成您自己的上传接口即可。 ,url: '/plan/insert/file/auth' ,accept: 'file' ,multiple: true ,number: 10 @@ -221,6 +221,7 @@ ,'<td>' ,'<button class="layui-btn layui-btn-xs demo-reload layui-hide">重传</button>' ,'<button class="layui-btn layui-btn-xs layui-btn-danger demo-delete">删除</button>' ,'<button id="file-download" class="layui-btn layui-btn-xs demo-reload layui-hide">下载</button>' ,'</td>' ,'</tr>'].join('')); @@ -561,12 +562,13 @@ tr.id = "upload-"+index; tr.innerHTML = '<td>' + file.name + '</td>' + '<td>' + (file.size / 1024).toFixed(1) + 'kb</td>' + '<td><div class="layui-progress" lay-filter="progress-demo-' + index + '"><div class="layui-progress-bar" lay-percent=""></div></div></td>' // + '<td><div class="layui-progress" lay-filter="progress-demo-' + index ,100 + '%'+ '"><div class="layui-progress-bar" lay-percent=""></div></div></td>' + '<td>'+'已完成'+'</td>' + '<td>' + '<button class="layui-btn layui-btn-xs demo-reload layui-hide">重传</button>' + '<button class="layui-btn layui-btn-xs layui-btn-danger demo-delete">删除</button>' // + '<button class="layui-btn layui-btn-xs layui-btn-danger demo-delete">删除</button>' + '<a href="' + file.path + '" download class="layui-btn layui-btn-xs layui-btn-primary">下载</a>' + '</td>'; // 将tr元素添加到目标table中 targetTable.appendChild(tr); }); @@ -582,6 +584,32 @@ } }); // 点击下载按钮时触发文件下载 $('#data-btn-file3').on('click', 'a', function() { var downloadUrl = $(this).attr('href'); console.log(downloadUrl) // 发起 AJAX 请求,获取文件 $.ajax({ url: '/plan/download/file/auth', type: 'POST', data: { downloadUrl: downloadUrl }, // 传递下载链接作为参数 success: function(response) { console.log(response) // window.open(baseUrl+response.msg) // 创建一个Blob对象 var blob = new Blob([response]); // 使用FileSaver保存文件 var fileName = downloadUrl.substring(downloadUrl.lastIndexOf('\\') + 1); console.log(fileName) saveAs(blob, fileName); }, error: function() { layer.msg('请求文件下载失败'); } }); return false; // 阻止默认的链接跳转行为 }); function approval(planId, plannerId, dIdx) { let loadIndex = layer.load(2); $.ajax({ src/main/webapp/static/js/priOnline/priOnline.js
@@ -1,5 +1,6 @@ var pageCurr; var admin; var treeCond; layui.config({ base: baseUrl + "/static/layui/lay/modules/" }).extend({ @@ -9,9 +10,67 @@ var $ = layui.jquery; var layer = layui.layer; var layDate = layui.laydate; var tree = layui.tree; var form = layui.form; var dropdown = layui.dropdown; admin = layui.admin; $('#organization').html(localStorage.getItem('nickname') + ' <i class="layui-icon"></i>'); // 部门人员 筛选 dropdown.render({ elem: '#organization' ,content: ['<div id="organizationTree" style="height: calc(100vh - 525px);border: none"></div>'].join('') ,style: 'width: 370px; height: 350px; padding: 0 15px; box-shadow: 1px 1px 30px rgb(0 0 0 / 12%);' ,ready: function(){ loadTree(); } }); // 树形图 var organizationTree; window.loadTree = function(condition){ var loadIndex = layer.load(2); $.ajax({ url: baseUrl+"/dept/user/tree/auth", headers: {'token': localStorage.getItem('token')}, data: { 'condition': condition }, method: 'POST', success: function (res) { layer.close(loadIndex); if (res.code === 200){ organizationTree = tree.render({ elem: '#organizationTree', id: 'organizationTree', onlyIconControl: true, data: res.data, click: function (obj) { treeCond = { key: obj.data.key, val: obj.data.id } $('#organization').html(obj.data.title + ' <i class="layui-icon"></i>'); $('#organizationTree').find('.ew-tree-click').removeClass('ew-tree-click'); $(obj.elem).children('.layui-tree-entry').addClass('ew-tree-click'); clearFormVal($('#search-box')); tableIns.reload({ where: {[obj.data.key]: obj.data.id}, page: {curr: 1} }); } }); treeData = res.data; } else if (res.code === 403){ top.location.href = baseUrl+"/"; } else { layer.msg(res.msg) } } }) } // 数据渲染 tableIns = table.render({ elem: '#priOnline', src/main/webapp/views/plan/plan.html
@@ -155,6 +155,7 @@ </scrpt> <script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script> <script type="text/javascript" src="../../static/js/FileSaver.js"></script> <script type="text/javascript" src="../../static/js/handlebars/handlebars-v4.5.3.js"></script> <script type="text/javascript" src="../../static/layui/layui.js" charset="utf-8"></script> <script type="text/javascript" src="../../static/js/common.js" charset="utf-8"></script> src/main/webapp/views/priOnline/priOnline.html
@@ -9,6 +9,21 @@ <link rel="stylesheet" href="../../static/layui/css/layui.css" media="all"> <link rel="stylesheet" href="../../static/css/admin.css?v=318" media="all"> <link rel="stylesheet" href="../../static/css/cool.css" media="all"> <link rel="stylesheet" href="../../static/css/tree.css" media="all"> <link rel="stylesheet" href="../../static/layui/lay/modules/formDesigner/coolForm.css" /> <style> .nav-box { position: absolute; top: 1px; left: 5px; } .nav-box-item { display: inline-block; vertical-align: middle; margin-right: 5px; } </style> </head> <body> @@ -16,6 +31,16 @@ <div class="layui-card"> <div class="layui-card-body"> <div id="search-box" class="layui-form toolbar" style="display: flex;justify-content: flex-end;position: relative"> <div class="nav-box"> <div class="nav-box-item"> <i class="layui-icon" style="color: #1890ff;font-weight: bold"></i> </div> <div class="nav-box-item"> <button id="organization" style="border: none;padding-right: 35px;" class="layui-btn layui-btn-primary icon-btn"> 未知 </button> </div> </div> <div class="layui-form-item"> <div class="layui-inline"> <div class="layui-input-inline">