中扬CRM客户关系管理系统
LSH
2023-07-31 b75de807123a59810a450cba923d42e19223556e
#售前规划申请单下载中道崩殂
1个文件已添加
6个文件已修改
463 ■■■■■ 已修改文件
src/main/java/com/zy/crm/common/utils/FileSaveExampleUtil.java 151 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/crm/manager/controller/PlanController.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/static/js/FileSaver.js 172 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/static/js/plan/plan.js 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/static/js/priOnline/priOnline.js 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/plan/plan.html 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/priOnline/priOnline.html 25 ●●●●● 补丁 | 查看 | 原始文档 | 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">&#xe61a;</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">&#xe61a;</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">&#xe613;</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">