Browse Source

feat:新增生成租户数据文件接口,确认生成完成接口,下载压缩包接口。修改导出工程文件逻辑。

韩帛霖 1 year ago
parent
commit
01e54f3c02

+ 7 - 7
zkqy-admin/pom.xml

@@ -38,7 +38,7 @@
             <version>1.6.2</version>
         </dependency>
 
-         <!-- Mysql驱动包 -->
+        <!-- Mysql驱动包 -->
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
@@ -81,15 +81,15 @@
                     </execution>
                 </executions>
             </plugin>
-            <plugin>   
-                <groupId>org.apache.maven.plugins</groupId>   
-                <artifactId>maven-war-plugin</artifactId>   
-                <version>3.1.0</version>   
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <version>3.1.0</version>
                 <configuration>
                     <failOnMissingWebXml>false</failOnMissingWebXml>
                     <warName>${project.artifactId}</warName>
-                </configuration>   
-           </plugin>   
+                </configuration>
+            </plugin>
         </plugins>
         <finalName>${project.artifactId}</finalName>
     </build>

+ 114 - 0
zkqy-admin/src/main/java/com/zkqy/web/controller/projcetzip/ExportController.java

@@ -0,0 +1,114 @@
+package com.zkqy.web.controller.projcetzip;
+
+import com.zkqy.common.config.ZkqyConfig;
+import com.zkqy.common.core.domain.AjaxResult;
+import com.zkqy.common.core.domain.entity.SysUser;
+import com.zkqy.common.utils.SecurityUtils;
+import com.zkqy.web.controller.tool.DownloadController;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+import com.zkqy.common.core.domain.entity.DataSource;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+@RestController
+@RequestMapping("/export/project-db")
+public class ExportController {
+
+    @Autowired
+    private ThreadPoolTaskExecutor taskExecutor;
+    private static final String MYSQLDUMP_PATH = "/usr/local/mysql/bin/mysqldump";
+    private static final String SQL_OUTPUT_PATH = "sql";
+
+    @Autowired
+    private DownloadController downloadController; // 注入DownloadController
+
+    @PostMapping("/start")
+    public AjaxResult startExport(@RequestBody List<String> databaseNames) {
+        String sourceFilePath = ZkqyConfig.getUploadPath() + "/engineeringdownload/";
+        DataSource datasourceInfo = SecurityUtils.getDatasourceInfo();
+        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
+        String tenantid = sysUser.getTenant().getTenantId().toString();
+//        if (databaseNames == null || databaseNames.isEmpty()) {
+        databaseNames = Arrays.asList("ry-vue-call", datasourceInfo.getDatabaseName());
+//        }
+        try {
+            // 获取数据库信息等
+            exportDatabases(databaseNames, sourceFilePath, datasourceInfo, tenantid);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return AjaxResult.error("数据生成失败!请联系管理员操作!");
+        }
+        // 导出完成后,设置导出状态为 true
+        downloadController.setExportCompleted(true);
+        return AjaxResult.success("数据生成成功!");
+    }
+
+    private void exportDatabases(List<String> databaseNames, String sourceFilePath, DataSource dataSource, String tenantId) {
+        try {
+            // 并行导出多个数据库
+            CompletableFuture.allOf(
+                    databaseNames.stream()
+                            .map(databaseName ->
+                                    CompletableFuture.runAsync(() ->
+                                            exportDatabase(databaseName, sourceFilePath, dataSource, tenantId), taskExecutor)
+                            )
+                            .toArray(CompletableFuture[]::new)
+            ).get(); // 等待所有导出完成
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    private void exportDatabase(String databaseName, String sourceFilePath, DataSource dataSource, String tenantId) {
+        String outputPath = sourceFilePath + SQL_OUTPUT_PATH + File.separator + tenantId;
+        try {
+            Files.createDirectories(Paths.get(outputPath));
+            String dumpFileName = outputPath + File.separator + databaseName + ".sql";
+            List<String> cmd = buildMysqldumpCommand(databaseName, dataSource);
+            ProcessBuilder pb = new ProcessBuilder(cmd);
+            pb.redirectOutput(new File(dumpFileName));
+            Process process = pb.start();
+            // 设置导出超时时间为10分钟
+            if (!process.waitFor(10, TimeUnit.MINUTES)) {
+                process.destroyForcibly(); // 超时则强制销毁进程
+                throw new TimeoutException("导出数据库超时");
+            }
+            int exitCode = process.exitValue();
+
+            if (exitCode == 0) {
+                System.out.println("数据库备份成功。导出文件:" + dumpFileName);
+            } else {
+                System.err.println("执行mysqldump命令时发生错误。退出代码:" + exitCode);
+            }
+        } catch (IOException | InterruptedException | TimeoutException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private List<String> buildMysqldumpCommand(String databaseName, DataSource dataSource) {
+        // 使用 Arrays.asList 创建不可变 List
+        return new ArrayList<>(Arrays.asList(
+                MYSQLDUMP_PATH,
+                "-h", dataSource.getDatabaseIp(),
+                "-u", dataSource.getUsername(),
+                "-p" + dataSource.getPassword(),
+                databaseName
+        ));
+    }
+}

+ 72 - 95
zkqy-admin/src/main/java/com/zkqy/web/controller/system/SysEngineeringController.java

@@ -1,6 +1,7 @@
 package com.zkqy.web.controller.system;
 
 import java.io.*;
+import java.net.URLEncoder;
 import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -8,7 +9,11 @@ import java.nio.file.Paths;
 import java.util.*;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
+import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletResponse;
+
+import cn.hutool.core.io.FileUtil;
+import com.zkqy.common.annotation.Anonymous;
 import com.zkqy.common.config.ZkqyConfig;
 import com.zkqy.common.core.domain.entity.DataSource;
 import com.zkqy.common.core.domain.entity.SysUser;
@@ -16,19 +21,14 @@ import com.zkqy.common.utils.DateUtils;
 import com.zkqy.common.utils.SecurityUtils;
 import com.zkqy.common.utils.ZipUtils;
 import io.swagger.annotations.ApiOperation;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.core.io.Resource;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 import com.zkqy.common.annotation.Log;
 import com.zkqy.common.core.controller.BaseController;
 import com.zkqy.common.core.domain.AjaxResult;
@@ -119,12 +119,39 @@ public class SysEngineeringController extends BaseController {
         return toAjax(sysEngineeringService.deleteSysEngineeringByIds(ids));
     }
 
+
+    @GetMapping("/largeFile")
+    public ResponseEntity<Resource> downloadLargeFile() {
+        // 调用Service层获取文件
+        File name = new File("/Users/zrwj/Downloads/123.zip");
+        // 调用 FileDownloadService 中的方法获取文件
+        if (Objects.isNull(name)) {
+            throw new RuntimeException("文件名称不能为空");
+        }
+        // directoryPath为服务器文件路径
+        String path = "" + name;
+        File file = new File(path);
+        HttpHeaders headers = new HttpHeaders();
+        headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
+        headers.add("Content-Disposition", "attachment; filename=" + file.getName());
+        headers.add("Pragma", "no-cache");
+        headers.add("Expires", "0");
+        headers.add("Last-Modified", new Date().toString());
+        headers.add("ETag", String.valueOf(System.currentTimeMillis()));
+        return ResponseEntity
+                .ok()
+                .headers(headers)
+                .contentLength(file.length())
+                .contentType(MediaType.parseMediaType("application/octet-stream"))
+                .body(new FileSystemResource(file));
+
+    }
+
     /**
      * 下载压缩包
      */
     @GetMapping("/download")
     public ResponseEntity<StreamingResponseBody> downloadZip() {
-        System.err.println("开始调用" + DateUtils.getTime());
         // 指定要打包的文件或目录路径
         String sourceFilePath = ZkqyConfig.getUploadPath() + "/engineeringdownload/";
 
@@ -136,19 +163,16 @@ public class SysEngineeringController extends BaseController {
                 System.out.println("目录 '" + sourceFilePath + "' 创建失败.");
             }
         }
-
         //当前用户数据源信息
         DataSource datasourceInfo = SecurityUtils.getDatasourceInfo();
         //导出数据库集合
         Set<String> databaseList = new LinkedHashSet<>();
         databaseList.add("ry-vue-call");
-//        databaseList.add("zkqy-template");
+        //        databaseList.add("zkqy-template");
 //        databaseList.add("zkqy-call");
         databaseList.add(datasourceInfo.getDatabaseName());
         //将sql文件导出到指定目录下
-        System.err.println("SQL文件开始生成" + DateUtils.getTime());
         exportMultipleDatabasesToLocal(databaseList, sourceFilePath, datasourceInfo);
-        System.err.println("SQL文件生成完毕" + DateUtils.getTime());
         //下载成功插入数据
         SysUser sysUser = SecurityUtils.getLoginUser().getUser();
         SysEngineering sysEngineering = new SysEngineering();
@@ -168,35 +192,23 @@ public class SysEngineeringController extends BaseController {
                 .body(outputStream -> {
                     try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Paths.get(sourceFilePath));
                          ZipOutputStream zipOut = new ZipOutputStream(outputStream)) {
-                        System.err.println("开始导出文件" + DateUtils.getTime());
                         addFilesToZipRecursively(zipOut, Paths.get(sourceFilePath), directoryStream);
-                        System.err.println("成功导出文件" + DateUtils.getTime());
                     } catch (IOException e) {
                         throw new RuntimeException("Failed to create the ZIP stream.", e);
                     }
                 });
     }
 
+
     /**
      * 下载压缩包
      */
+
+    @Anonymous
     @GetMapping("/download1")
     public void downloadZip1(HttpServletResponse response) {
-        System.err.println("开始调用" + DateUtils.getTime());
-
         // 指定要打包的文件或目录路径
         String sourceFilePath = ZkqyConfig.getUploadPath() + "/engineeringdownload/";
-
-        File dir = new File(sourceFilePath);
-        // 判断文件夹路径是否存在,不存在创建
-        if (!dir.exists()) {
-            boolean isCreated = dir.mkdirs();
-            if (!isCreated) {
-                System.out.println("目录 '" + sourceFilePath + "' 创建失败.");
-            }
-        }
-
-
         //当前用户数据源信息
         DataSource datasourceInfo = SecurityUtils.getDatasourceInfo();
         //导出数据库集合
@@ -204,10 +216,7 @@ public class SysEngineeringController extends BaseController {
         databaseList.add("ry-vue-call");
         databaseList.add(datasourceInfo.getDatabaseName());
         //将sql文件导出到指定目录下
-        System.err.println("SQL文件开始生成" + DateUtils.getTime());
         exportMultipleDatabasesToLocal(databaseList, sourceFilePath, datasourceInfo);
-        System.err.println("SQL文件生成完毕" + DateUtils.getTime());
-
         //下载成功插入数据
         SysUser sysUser = SecurityUtils.getLoginUser().getUser();
         SysEngineering sysEngineering = new SysEngineering();
@@ -216,12 +225,12 @@ public class SysEngineeringController extends BaseController {
         sysEngineering.setEngineeringName(sysUser.getTenantName() + "-mes");
         sysEngineeringService.insertSysEngineering(sysEngineering);
         List<Map<String, String>> fileList = listFiles(sourceFilePath);
-        System.err.println("开始导出文件" + DateUtils.getTime());
         ZipUtils.createZip(response, fileList);
-        System.err.println("成功导出文件" + DateUtils.getTime());
     }
 
-    private void addFilesToZipRecursively(ZipOutputStream zipOut, Path rootPath, DirectoryStream<Path> dirStream) throws IOException {
+
+    private void addFilesToZipRecursively(ZipOutputStream zipOut, Path rootPath, DirectoryStream<Path> dirStream) throws
+            IOException {
         for (Path filePath : dirStream) {
             if (Files.isDirectory(filePath)) {
                 // 添加目录条目到ZIP
@@ -254,74 +263,49 @@ public class SysEngineeringController extends BaseController {
     /**
      * 导出数据库文件
      */
-    public void exportMultipleDatabasesToLocal(Set<String> databaseNames, String outputPath, DataSource dataSource) {
-        outputPath = outputPath + "sql/";
+    private static final String MYSQLDUMP_PATH = "/usr/local/mysql/bin/mysqldump";
+//    private static final String OUTPUT_PATH = "sql/";
 
-        File dir = new File(outputPath);
-        // 判断文件夹路径是否存在,不存在创建
-        if (!dir.exists()) {
-            boolean isCreated = dir.mkdirs();
-            if (!isCreated) {
-                System.out.println("目录 '" + outputPath + "' 创建失败.");
-            }
-        }
-        for (String databaseName : databaseNames) {
-            try {
-                // 构建命令参数列表
-                List<String> cmd = new ArrayList<>();
-//                cmd.add("mysqldump");
-                cmd.add("/usr/local/mysql/bin/mysqldump");
-//                cmd.add("--column-statistics=0");
-                cmd.add("-h");
-                cmd.add(dataSource.getDatabaseIp());
-                cmd.add("-u");
-                cmd.add(dataSource.getUsername());
-                cmd.add("-p" + dataSource.getPassword());
-                cmd.add(databaseName);
+    public void exportMultipleDatabasesToLocal(Set<String> databaseNames, String sourceFilePath, DataSource dataSource) {
 
-                ProcessBuilder pb = new ProcessBuilder(cmd);
-                // 设置MySQL bin目录到PATH环境变量,确保mysqldump可执行文件能找到
-//                Map<String, String> env = pb.environment();
-//                env.put("PATH", env.get("PATH") + File.pathSeparator + "\\usr\\local\\mysql\\bin");
+        String outputPath = sourceFilePath + "sql/" + SecurityUtils.getTenantId();
 
-                // 创建进程并获取输出流
-                Process process = pb.start();
+        try {
+            Files.createDirectories(Paths.get(outputPath));
 
-                // 将mysqldump的输出重定向到文件
-                OutputStream outStream = new FileOutputStream(Paths.get(outputPath + databaseName + ".sql").toFile());
-                InputStream processOutput = process.getInputStream();
-                byte[] buffer = new byte[4096];
-                int read;
-                while ((read = processOutput.read(buffer)) != -1) {
-                    outStream.write(buffer, 0, read);
-                }
-                outStream.close();
-                processOutput.close();
-
-                // 获取错误流,并打印或处理任何错误信息
-                InputStream errorStream = process.getErrorStream();
-                BufferedReader errorReader = new BufferedReader(new InputStreamReader(errorStream));
-                String line;
-                while ((line = errorReader.readLine()) != null) {
-                    System.err.println(line);
-                }
-                errorReader.close();
-                errorStream.close();
+            for (String databaseName : databaseNames) {
+                String dumpFileName = outputPath + "/" + databaseName + ".sql";
+                List<String> cmd = buildMysqldumpCommand(databaseName, dataSource);
+
+                ProcessBuilder pb = new ProcessBuilder(cmd);
+                pb.redirectOutput(new File(dumpFileName));
 
-                // 等待进程结束并检查退出码
+                Process process = pb.start();
                 int exitCode = process.waitFor();
+
                 if (exitCode == 0) {
-                    System.out.println("数据库备份成功,导出文件: " + outputPath);
+                    System.out.println("数据库备份成功,导出文件: " + dumpFileName);
                 } else {
                     System.err.println("mysqldump命令执行失败,退出代码: " + exitCode);
                 }
-
-            } catch (IOException | InterruptedException e) {
-                e.printStackTrace();
             }
+        } catch (IOException | InterruptedException e) {
+            e.printStackTrace();
         }
     }
 
+    private List<String> buildMysqldumpCommand(String databaseName, DataSource dataSource) {
+        List<String> cmd = new ArrayList<>();
+        cmd.add(MYSQLDUMP_PATH);
+        cmd.add("-h");
+        cmd.add(dataSource.getDatabaseIp());
+        cmd.add("-u");
+        cmd.add(dataSource.getUsername());
+        cmd.add("-p" + dataSource.getPassword());
+        cmd.add(databaseName);
+        return cmd;
+    }
+
     public static List<Map<String, String>> listFiles(String directoryPath) {
         List<Map<String, String>> fileList = new ArrayList<>();
         File directory = new File(directoryPath);
@@ -350,12 +334,5 @@ public class SysEngineeringController extends BaseController {
         }
     }
 
-    public static void main(String[] args) {
-        String directoryPath = "/path/to/your/directory"; // 替换为你的文件夹路径
-        List<Map<String, String>> fileList = listFiles(directoryPath);
 
-        for (Map<String, String> fileMap : fileList) {
-            System.out.println("FileName: " + fileMap.get("fileName") + ", FilePath: " + fileMap.get("filePath"));
-        }
-    }
 }

+ 1 - 1
zkqy-admin/src/main/java/com/zkqy/web/controller/system/SysLoginController.java

@@ -124,7 +124,7 @@ public class SysLoginController {
             SysTenant sysTenant = sysTenantService.selectSysTenantByTenantId(user.getTenantId());
             ajax.put("tenant", sysTenant);
             //数据源信息
-            //DataSource dataSource = dataSourceService.selectById(sysTenant.getDatasourceId());
+            // DataSource dataSource = dataSourceService.selectById(sysTenant.getDatasourceId());
             ajax.put("dataSource", null);
         }
         return ajax;

+ 106 - 0
zkqy-admin/src/main/java/com/zkqy/web/controller/tool/DownloadController.java

@@ -0,0 +1,106 @@
+package com.zkqy.web.controller.tool;
+
+import com.zkqy.common.config.ZkqyConfig;
+import com.zkqy.common.utils.ZipUtils;
+import com.zkqy.system.service.ISysEngineeringService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.locks.ReentrantLock;
+
+@RestController
+@RequestMapping("/download/project-db")
+public class DownloadController {
+
+    @Autowired
+    private ISysEngineeringService sysEngineeringService;
+
+    // 使用ReentrantLock确保多线程访问时的同步性
+    private static final ReentrantLock lock = new ReentrantLock();
+    private boolean exportCompleted = false;
+
+
+    @GetMapping("/status")
+    public ResponseEntity<String> checkExportStatus() {
+        lock.lock();
+        try {
+            if (exportCompleted) {
+                return ResponseEntity.ok("导出已完成。您现在可以触发下载");
+            } else {
+                return ResponseEntity.status(HttpStatus.NOT_FOUND).body("出口仍在进行中。请稍候。。。");
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    @GetMapping("/download")
+    public void downloadZip(HttpServletResponse response) {
+        String sourceFilePath = ZkqyConfig.getUploadPath() + "/engineeringdownload/";
+        lock.lock();
+        try {
+            // 检查导出是否完成
+            if (exportCompleted) {
+                try {
+                    // 获取文件列表等
+                    List<Map<String, String>> fileList = listFiles(sourceFilePath);
+                    ZipUtils.createZip(response, fileList);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+                }
+            } else {
+                // 如果导出未完成,可以返回相应的错误信息给前端
+                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
+                // 或者抛出异常等处理方式
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    private List<Map<String, String>> listFiles(String directoryPath) {
+        List<Map<String, String>> fileList = new ArrayList<>();
+        File directory = new File(directoryPath);
+        if (directory.exists() && directory.isDirectory()) {
+            listFilesRecursively(directory, fileList);
+        }
+        return fileList;
+    }
+
+    private static void listFilesRecursively(File directory, List<Map<String, String>> fileList) {
+        File[] files = directory.listFiles();
+        if (files != null) {
+            for (File file : files) {
+                if (file.isFile()) {
+                    Map<String, String> fileMap = new HashMap<>();
+                    fileMap.put("fileName", file.getName());
+                    fileMap.put("filePath", file.getAbsolutePath());
+                    fileList.add(fileMap);
+                } else if (file.isDirectory()) {
+                    listFilesRecursively(file, fileList);
+                }
+            }
+        }
+    }
+
+    // 设置导出状态的方法,确保在同步块内进行
+    public void setExportCompleted(boolean value) {
+        lock.lock();
+        try {
+            exportCompleted = value;
+        } finally {
+            lock.unlock();
+        }
+    }
+}

+ 175 - 0
zkqy-admin/src/main/java/com/zkqy/web/controller/tool/daochuController.java

@@ -0,0 +1,175 @@
+package com.zkqy.web.controller.tool;
+
+import com.zkqy.common.config.ZkqyConfig;
+import com.zkqy.common.core.domain.entity.DataSource;
+import com.zkqy.common.core.domain.entity.SysUser;
+import com.zkqy.common.utils.DateUtils;
+import com.zkqy.common.utils.SecurityUtils;
+import com.zkqy.common.utils.ZipUtils;
+import com.zkqy.system.domain.SysEngineering;
+import com.zkqy.system.service.ISysEngineeringService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+@RestController
+@RequestMapping("/download/project-db")
+public class daochuController {
+
+    @Autowired
+    private ISysEngineeringService sysEngineeringService;
+    @Autowired
+    private ThreadPoolTaskExecutor taskExecutor;
+    private static final String MYSQLDUMP_PATH = "/usr/local/mysql/bin/mysqldump";
+    private static final String SQL_OUTPUT_PATH = "sql";
+
+
+    @GetMapping("/zip")
+    public void downloadZip1(HttpServletResponse response) {
+        String sourceFilePath = ZkqyConfig.getUploadPath() + "/engineeringdownload/";
+        DataSource datasourceInfo = SecurityUtils.getDatasourceInfo();
+        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
+        String tenantid = sysUser.getTenant().getTenantId().toString();
+        // 使用 Arrays.asList 转换数组为集合
+        List<String> databaseList = Arrays.asList("ry-vue-call", datasourceInfo.getDatabaseName());
+        List<CompletableFuture<Void>> exportFutures = databaseList.stream()
+                .map(databaseName -> CompletableFuture.runAsync(
+                                () -> exportDatabase(databaseName, sourceFilePath, datasourceInfo, tenantid), taskExecutor)
+                        .exceptionally(throwable -> {
+                            throwable.printStackTrace();
+                            return null;
+                        })
+                )
+                .collect(Collectors.toList());
+        CompletableFuture<Void> allOf = CompletableFuture.allOf(
+                exportFutures.toArray(new CompletableFuture[0])
+        );
+        try {
+            allOf.get(10, TimeUnit.MINUTES);
+        } catch (InterruptedException | ExecutionException | TimeoutException e) {
+            e.printStackTrace();
+        }
+        SysEngineering sysEngineering = new SysEngineering();
+        sysEngineering.setCreateTime(DateUtils.getNowDate());
+        sysEngineering.setDownloadTime(DateUtils.getNowDate());
+        sysEngineering.setEngineeringName(sysUser.getTenantName() + "-MES");
+        sysEngineering.setTenantId(sysUser.getTenantId());
+        sysEngineeringService.insertSysEngineering(sysEngineering);
+        List<Map<String, String>> fileList = listFiles(sourceFilePath);
+        ZipUtils.createZip(response, fileList);
+    }
+
+
+    private void addFilesToZipRecursively(ZipOutputStream zipOut, Path rootPath, DirectoryStream<Path> dirStream) throws
+            IOException {
+        for (Path filePath : dirStream) {
+            if (Files.isDirectory(filePath)) {
+                // 添加目录条目到ZIP
+                String entryName = filePath.toString().substring(rootPath.toString().length() + 1) + "/";
+                zipOut.putNextEntry(new ZipEntry(entryName));
+                zipOut.closeEntry();
+                // 递归处理子目录中的文件
+                try (DirectoryStream<Path> subDirStream = Files.newDirectoryStream(filePath)) {
+                    addFilesToZipRecursively(zipOut, rootPath, subDirStream);
+                }
+            } else if (Files.isRegularFile(filePath)) {
+                // 添加文件到ZIP
+                String entryName = filePath.toString().substring(rootPath.toString().length() + 1);
+                zipOut.putNextEntry(new ZipEntry(entryName));
+                try (InputStream fileIn = Files.newInputStream(filePath)) {
+                    byte[] buffer = new byte[4096];
+                    int read;
+                    while ((read = fileIn.read(buffer)) != -1) {
+                        zipOut.write(buffer, 0, read);
+                    }
+                }
+                zipOut.closeEntry();
+            }
+        }
+    }
+
+    private List<String> buildMysqldumpCommand(String databaseName, DataSource dataSource) {
+        // 使用 Arrays.asList 创建不可变 List
+        return new ArrayList<>(Arrays.asList(
+                MYSQLDUMP_PATH,
+                "-h", dataSource.getDatabaseIp(),
+                "-u", dataSource.getUsername(),
+                "-p" + dataSource.getPassword(),
+                databaseName
+        ));
+    }
+
+    public static List<Map<String, String>> listFiles(String directoryPath) {
+        List<Map<String, String>> fileList = new ArrayList<>();
+        File directory = new File(directoryPath);
+        if (directory.exists() && directory.isDirectory()) {
+            listFilesRecursively(directory, fileList);
+        }
+        return fileList;
+    }
+
+    private static void listFilesRecursively(File directory, List<Map<String, String>> fileList) {
+        File[] files = directory.listFiles();
+        if (files != null) {
+            for (File file : files) {
+                if (file.isFile()) {
+                    Map<String, String> fileMap = new HashMap<>();
+                    fileMap.put("fileName", file.getName());
+                    fileMap.put("filePath", file.getAbsolutePath());
+                    fileList.add(fileMap);
+                } else if (file.isDirectory()) {
+                    listFilesRecursively(file, fileList);
+                }
+            }
+        }
+    }
+
+    private void exportDatabase(String databaseName, String sourceFilePath, DataSource dataSource, String tenantId) {
+        String outputPath = sourceFilePath + SQL_OUTPUT_PATH + File.separator + tenantId;
+        try {
+            Files.createDirectories(Paths.get(outputPath));
+            String dumpFileName = outputPath + File.separator + databaseName + ".sql";
+            List<String> cmd = buildMysqldumpCommand(databaseName, dataSource);
+            ProcessBuilder pb = new ProcessBuilder(cmd);
+            pb.redirectOutput(new File(dumpFileName));
+            Process process = pb.start();
+            // 设置导出超时时间为10分钟
+            if (!process.waitFor(10, TimeUnit.MINUTES)) {
+                process.destroyForcibly(); // 超时则强制销毁进程
+                throw new TimeoutException("导出数据库超时");
+            }
+            int exitCode = process.exitValue();
+
+            if (exitCode == 0) {
+                System.out.println("数据库备份成功。导出文件:" + dumpFileName);
+            } else {
+                System.err.println("执行mysqldump命令时发生错误。退出代码:" + exitCode);
+            }
+        } catch (IOException | InterruptedException | TimeoutException e) {
+            e.printStackTrace();
+        }
+    }
+
+}

+ 1 - 1
zkqy-common/src/main/java/com/zkqy/common/constant/Constants.java

@@ -132,7 +132,7 @@ public class Constants
     /**
      * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
      */
-    public static final String[] JOB_WHITELIST_STR = { "com.ruoyi" };
+    public static final String[] JOB_WHITELIST_STR = { "com.zkqy" };
 
     /**
      * 定时任务违规的字符

+ 87 - 17
zkqy-common/src/main/java/com/zkqy/common/utils/ZipUtils.java

@@ -6,6 +6,7 @@ import org.apache.tools.zip.ZipOutputStream;
 
 import javax.servlet.http.HttpServletResponse;
 import java.io.BufferedInputStream;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
@@ -23,33 +24,102 @@ public class ZipUtils {
     public static void createZip(HttpServletResponse response, List<Map<String, String>> fileList) {
 
         try {
-            //设置下载的文件名称, 注意中文名需要做编码类型转换
             response.setContentType("application/x-octet-stream");
-            response.setHeader("Content-Disposition", "attachment;");
+            response.setHeader("Content-Disposition", "attachment; filename=\"download.zip\"");
             response.setCharacterEncoding("utf-8");
-            //创建zip输出流
+
             ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
             byte[] buffer = new byte[1024];
-            BufferedInputStream bufferStream = null;
-            int index = 1;
-            for (int i = 0; i < fileList.size(); i++) {
-                //设置zip里面每个文件的名称
-                zos.putNextEntry(new ZipEntry(fileList.get(i).get("fileName").toString()));
-                //根据文件地址获取输入流
-                InputStream is = new URL("file:///" + fileList.get(i).get("filePath").toString()).openConnection().getInputStream();
-                int length;
-                while ((length = is.read(buffer)) > 0) {
-                    zos.write(buffer, 0, length);
+
+            for (Map<String, String> fileMap : fileList) {
+                String fileName = fileMap.get("fileName");
+                String filePath = fileMap.get("filePath");
+
+                // 使用 File.separator 来实现跨平台兼容性
+                String relativePath = fileName;
+
+                // 在 Zip 中创建带有相对路径的 ZipEntry
+                zos.putNextEntry(new ZipEntry(relativePath));
+
+                try (InputStream is = new FileInputStream(filePath)) {
+                    int length;
+                    while ((length = is.read(buffer)) > 0) {
+                        zos.write(buffer, 0, length);
+                    }
+                } catch (IOException e) {
+                    e.printStackTrace();
                 }
-                is.close();
-                index++;
+
+                zos.closeEntry();
             }
-            zos.closeEntry();
+
             zos.close();
             zos.flush();
         } catch (IOException e) {
             e.printStackTrace();
         }
-
     }
+
+    // 222
+//    public static void createZip(HttpServletResponse response, List<Map<String, String>> fileList) {
+//        try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
+//            response.setContentType("application/x-octet-stream");
+//            response.setHeader("Content-Disposition", "attachment; filename=\"download.zip\"");
+//            response.setCharacterEncoding("utf-8");
+//
+//            byte[] buffer = new byte[1024];
+//            for (Map<String, String> file : fileList) {
+//                // 设置zip里面每个文件的名称
+//                ZipEntry entry = new ZipEntry(file.get("fileName").toString());
+//                zos.putNextEntry(entry);
+//
+//                try (InputStream is = new FileInputStream(file.get("filePath").toString())) {
+//                    int length;
+//                    while ((length = is.read(buffer)) > 0) {
+//                        zos.write(buffer, 0, length);
+//                    }
+//                }
+//
+//                zos.closeEntry();
+//            }
+//
+//            zos.flush();
+//        } catch (IOException e) {
+//            e.printStackTrace();
+//        }
+//    }
+
+    // 111
+//    public static void createZip(HttpServletResponse response, List<Map<String, String>> fileList) {
+//
+//        try {
+//            //设置下载的文件名称, 注意中文名需要做编码类型转换
+//            response.setContentType("application/x-octet-stream");
+//            response.setHeader("Content-Disposition", "attachment;");
+//            response.setCharacterEncoding("utf-8");
+//            //创建zip输出流
+//            ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
+//            byte[] buffer = new byte[1024];
+//            BufferedInputStream bufferStream = null;
+//            int index = 1;
+//            for (int i = 0; i < fileList.size(); i++) {
+//                //设置zip里面每个文件的名称
+//                zos.putNextEntry(new ZipEntry(fileList.get(i).get("fileName").toString()));
+//                //根据文件地址获取输入流
+//                InputStream is = new URL("file:///" + fileList.get(i).get("filePath").toString()).openConnection().getInputStream();
+//                int length;
+//                while ((length = is.read(buffer)) > 0) {
+//                    zos.write(buffer, 0, length);
+//                }
+//                is.close();
+//                index++;
+//            }
+//            zos.closeEntry();
+//            zos.close();
+//            zos.flush();
+//        } catch (IOException e) {
+//            e.printStackTrace();
+//        }
+//
+//    }
 }

+ 16 - 21
zkqy-system/src/main/java/com/zkqy/system/service/impl/SysEngineeringServiceImpl.java

@@ -1,6 +1,7 @@
 package com.zkqy.system.service.impl;
 
 import com.zkqy.common.utils.DateUtils;
+import com.zkqy.common.utils.SecurityUtils;
 import com.zkqy.system.domain.SysEngineering;
 import com.zkqy.system.mapper.SysEngineeringMapper;
 import com.zkqy.system.service.ISysEngineeringService;
@@ -11,87 +12,81 @@ import java.util.List;
 
 /**
  * 工程部署Service业务层处理
- * 
+ *
  * @author zkqy
  * @date 2024-01-03
  */
 @Service
-public class SysEngineeringServiceImpl implements ISysEngineeringService 
-{
+public class SysEngineeringServiceImpl implements ISysEngineeringService {
     @Autowired
     private SysEngineeringMapper sysEngineeringMapper;
 
     /**
      * 查询工程部署
-     * 
+     *
      * @param id 工程部署主键
      * @return 工程部署
      */
     @Override
-    public SysEngineering selectSysEngineeringById(Long id)
-    {
+    public SysEngineering selectSysEngineeringById(Long id) {
         return sysEngineeringMapper.selectSysEngineeringById(id);
     }
 
     /**
      * 查询工程部署列表
-     * 
+     *
      * @param sysEngineering 工程部署
      * @return 工程部署
      */
     @Override
-    public List<SysEngineering> selectSysEngineeringList(SysEngineering sysEngineering)
-    {
+    public List<SysEngineering> selectSysEngineeringList(SysEngineering sysEngineering) {
+        sysEngineering.setTenantId(SecurityUtils.getTenantId());
         return sysEngineeringMapper.selectSysEngineeringList(sysEngineering);
     }
 
     /**
      * 新增工程部署
-     * 
+     *
      * @param sysEngineering 工程部署
      * @return 结果
      */
     @Override
-    public int insertSysEngineering(SysEngineering sysEngineering)
-    {
+    public int insertSysEngineering(SysEngineering sysEngineering) {
         sysEngineering.setCreateTime(DateUtils.getNowDate());
         return sysEngineeringMapper.insertSysEngineering(sysEngineering);
     }
 
     /**
      * 修改工程部署
-     * 
+     *
      * @param sysEngineering 工程部署
      * @return 结果
      */
     @Override
-    public int updateSysEngineering(SysEngineering sysEngineering)
-    {
+    public int updateSysEngineering(SysEngineering sysEngineering) {
         sysEngineering.setUpdateTime(DateUtils.getNowDate());
         return sysEngineeringMapper.updateSysEngineering(sysEngineering);
     }
 
     /**
      * 批量删除工程部署
-     * 
+     *
      * @param ids 需要删除的工程部署主键
      * @return 结果
      */
     @Override
-    public int deleteSysEngineeringByIds(Long[] ids)
-    {
+    public int deleteSysEngineeringByIds(Long[] ids) {
         return sysEngineeringMapper.deleteSysEngineeringByIds(ids);
     }
 
     /**
      * 删除工程部署信息
-     * 
+     *
      * @param id 工程部署主键
      * @return 结果
      */
     @Override
-    public int deleteSysEngineeringById(Long id)
-    {
+    public int deleteSysEngineeringById(Long id) {
         return sysEngineeringMapper.deleteSysEngineeringById(id);
     }
 }

+ 38 - 1
zkqy-ui/src/api/system/engineering.js

@@ -46,8 +46,45 @@ export function delEngineering(id) {
 // 下载工程部署
 export function downloadEngineering() {
   return request({
-    url: '/system/engineering/download',
+    // url: '/system/engineering/download1',
+    url: '/download/project-db/zip',
     method: 'get',
     responseType: 'blob'
   })
 }
+
+// 下载工程部署
+export function downloadEngineering2() {
+  return request({
+    url: '/api/files/download',
+    method: 'get',
+    responseType: 'blob'
+  })
+}
+
+// 检查工程文件是否准备完毕
+export function checkExportStatus() {
+  return request({
+    url: '/download/project-db/status',
+    method: 'get',
+  })
+}
+
+// 导出工程文件
+export function downloadZip() {
+  return request({
+    url: '/download/project-db/download',
+    method: 'get',
+    responseType: 'blob'
+  })
+}
+
+// 生成当前租户对应的数据sql脚本
+export function startExport(data) {
+  return request({
+    url: '/export/project-db/start',
+    method: 'post',
+    data: data
+  })
+}
+

+ 50 - 0
zkqy-ui/src/views/system/engineeringManage/adss.html

@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <title>春节倒计时</title>
+  <style>
+    body {
+      font-family: Arial, sans-serif;
+      text-align: center;
+      margin: 50px;
+    }
+    #countdown {
+      font-size: 24px;
+      font-weight: bold;
+      color: #333;
+    }
+  </style>
+</head>
+<body>
+
+<h1>春节倒计时</h1>
+<div id="countdown"></div>
+
+<script>
+  // 目标日期,春节的日期(假设是2024年的春节,你可以根据实际情况修改)
+  const targetDate = new Date("2024-02-10T00:00:00Z").getTime();
+
+  // 更新倒计时
+  function updateCountdown() {
+    const currentDate = new Date().getTime();
+    const timeDifference = targetDate - currentDate;
+
+    const days = Math.floor(timeDifference / (1000 * 60 * 60 * 24));
+    const hours = Math.floor((timeDifference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
+    const minutes = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60));
+    const seconds = Math.floor((timeDifference % (1000 * 60)) / 1000);
+
+    document.getElementById("countdown").innerHTML = `${days} 天 ${hours} 小时 ${minutes} 分钟 ${seconds} 秒`;
+  }
+
+  // 每秒更新一次倒计时
+  setInterval(updateCountdown, 1000);
+
+  // 初始加载
+  updateCountdown();
+</script>
+
+</body>
+</html>

+ 196 - 164
zkqy-ui/src/views/system/engineeringManage/index.vue

@@ -1,99 +1,23 @@
 <template>
   <div class="app-container">
-    <el-form
-      :model="queryParams"
-      ref="queryForm"
-      size="small"
-      :inline="true"
-      v-show="showSearch"
-      label-width="68px"
-    >
-      <el-form-item label="工程名称" prop="engineeringName">
-        <el-input
-          v-model="queryParams.engineeringName"
-          placeholder="请输入工程名称"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="备注" prop="remark">
-        <el-input
-          v-model="queryParams.remark"
-          placeholder="请输入备注"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item>
-        <el-button
-          type="primary"
-          icon="el-icon-search"
-          size="mini"
-          @click="handleQuery"
-          >搜索
-        </el-button>
-        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery"
-          >重置
-        </el-button>
-      </el-form-item>
-    </el-form>
-
     <el-row :gutter="10" class="mb8">
       <el-col :span="1.5">
+
+        <div>
+          <button @click="startExport1" :disabled="exporting">开始导出</button>
+          <button @click="checkExportStatus1">检查导出状态</button>
+          <el-progress v-if="exporting" :percentage="progress" :status="progressStatus"></el-progress>
+          <button @click="handleDownloadEnd" :disabled="!exportCompleted">Download Zip</button>
+        </div>
+
         <el-button
           type="primary"
           plain
-          icon="el-icon-plus"
-          size="mini"
-          @click="handleAdd"
-          v-hasPermi="['system:engineering:add']"
-          >新增
-        </el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="success"
-          plain
-          icon="el-icon-edit"
-          size="mini"
-          :disabled="single"
-          @click="handleUpdate"
-          v-hasPermi="['system:engineering:edit']"
-          >修改
-        </el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="danger"
-          plain
-          icon="el-icon-delete"
-          size="mini"
-          :disabled="multiple"
-          @click="handleDelete"
-          v-hasPermi="['system:engineering:remove']"
-          >删除
-        </el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="warning"
-          plain
-          icon="el-icon-download"
-          size="mini"
-          @click="handleExport"
-          v-hasPermi="['system:engineering:export']"
-          >导出
-        </el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="info"
-          plain
           icon="el-icon-download"
           size="mini"
           @click="handleDownloadEnd"
           v-hasPermi="['system:engineering:download']"
-          >下载
+        >工程下载
         </el-button>
       </el-col>
       <right-toolbar
@@ -107,61 +31,16 @@
       :data="engineeringList"
       @selection-change="handleSelectionChange"
     >
-      <el-table-column type="selection" width="55" align="center" />
-      <el-table-column label="编号" align="center" prop="id" />
-      <!-- <el-table-column label="工程key" align="center" prop="engineeringKey" /> -->
-      <el-table-column label="工程名称" align="center" prop="engineeringName" />
-      <el-table-column label="下载次数" align="center" prop="downloadNumber" />
-      <el-table-column
-        label="下载时间"
-        align="center"
-        prop="downloadTime"
-        width="180"
-      >
-        <template slot-scope="scope">
-          <span>{{ parseTime(scope.row.downloadTime, "{y}-{m}-{d}") }}</span>
-        </template>
-      </el-table-column>
-      <el-table-column label="更新时间" align="center" prop="updateTime" />
-      <!-- <el-table-column label="租户编号" align="center" prop="tenantId" />
-      <el-table-column label="备注" align="center" prop="remark" />
-      <el-table-column label="创建者ID" align="center" prop="createById" />
-      <el-table-column label="更新者ID" align="center" prop="updateById" /> -->
-      <el-table-column
-        label="操作"
-        align="center"
-        class-name="small-padding fixed-width"
-      >
+      <el-table-column type="selection" width="55" align="center"/>
+      <el-table-column label="工程名称" align="center" prop="engineeringName"/>
+      <el-table-column label="下载时间" align="center" prop="downloadTime">
         <template slot-scope="scope">
-          <el-dropdown>
-            <el-button type="warning" plain size="small">
-              处理<i class="el-icon-arrow-down el-icon--right"></i>
-            </el-button>
-            <el-dropdown-menu slot="dropdown">
-              <el-dropdown-item>
-                <el-button
-                  size="mini"
-                  type="text"
-                  icon="el-icon-edit"
-                  @click="handleUpdate(scope.row)"
-                  v-hasPermi="['system:engineering:edit']"
-                  >修改
-                </el-button>
-              </el-dropdown-item>
-              <el-dropdown-item>
-                <el-button
-                  size="mini"
-                  type="text"
-                  icon="el-icon-delete"
-                  @click="handleDelete(scope.row)"
-                  v-hasPermi="['system:engineering:remove']"
-                  >删除
-                </el-button>
-              </el-dropdown-item>
-            </el-dropdown-menu>
-          </el-dropdown>
+          <span>{{
+              parseTime(scope.row.downloadTime, "{y}-{m}-{d} {h}:{i}:{s}")
+            }}</span>
         </template>
       </el-table-column>
+
     </el-table>
 
     <pagination
@@ -175,9 +54,7 @@
     <!-- 添加或修改工程部署对话框 -->
     <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
       <el-form ref="form" :model="form" :rules="rules" label-width="80px">
-        <!-- <el-form-item label="工程key" prop="engineeringKey">
-          <el-input v-model="form.engineeringKey" placeholder="请输入工程key" />
-        </el-form-item> -->
+
         <el-form-item label="工程名称" prop="engineeringName">
           <el-input
             v-model="form.engineeringName"
@@ -201,23 +78,11 @@
           </el-date-picker>
         </el-form-item>
         <el-form-item label="更新时间" prop="updateTime">
-          <el-input v-model="form.updateTime" placeholder="请输入修改时间" />
-        </el-form-item>
-        <!-- <el-form-item label="租户编号" prop="tenantId">
-          <el-input v-model="form.tenantId" placeholder="请输入租户编号" />
+          <el-input v-model="form.updateTime" placeholder="请输入修改时间"/>
         </el-form-item>
-        <el-form-item label="备注" prop="remark">
-          <el-input v-model="form.remark" placeholder="请输入备注" />
-        </el-form-item> -->
         <el-form-item label="是否删除" prop="delFlag">
-          <el-input v-model="form.delFlag" placeholder="请输入是否删除" />
+          <el-input v-model="form.delFlag" placeholder="请输入是否删除"/>
         </el-form-item>
-        <!--  <el-form-item label="创建者ID" prop="createById">
-          <el-input v-model="form.createById" placeholder="请输入创建者ID" />
-        </el-form-item>
-        <el-form-item label="更新者ID" prop="updateById">
-          <el-input v-model="form.updateById" placeholder="请输入更新者ID" />
-        </el-form-item> -->
       </el-form>
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="submitForm">确 定</el-button>
@@ -228,10 +93,15 @@
 </template>
 
 <script>
-import { Message, Loading } from "element-ui";
+import {getToken} from '@/utils/auth'
+import {Message, Loading} from "element-ui";
 import service from "@/utils/request";
-import { tansParams, blobValidate } from "@/utils/zkqy";
+import {tansParams, blobValidate} from "@/utils/zkqy";
+import {mapState} from 'vuex'
 import {
+  checkExportStatus,
+  downloadZip,
+  startExport,
   listEngineering,
   getEngineering,
   delEngineering,
@@ -240,10 +110,15 @@ import {
   downloadEngineering,
 } from "@/api/system/engineering";
 import axios from "axios";
+
 export default {
   name: "Engineering",
   data() {
     return {
+      exporting: false,
+      exportCompleted: false,
+      progress: 0,
+      progressStatus: 'success',
       // 遮罩层
       loading: true,
       // 选中数组
@@ -284,16 +159,54 @@ export default {
   created() {
     this.getList();
   },
+  computed: {
+    ...mapState({dataBaseName: state => dataBaseName => state.user.dataSource.databaseName})
+  },
   methods: {
-    handleDownloadEnd(row) {
+    startExport1() {
+      this.exporting = true;
+      this.progress = 0;
+
+      // 模拟导出过程
+      const interval = setInterval(() => {
+        if (this.progress < 100) {
+          this.progress += 10;
+        } else {
+          clearInterval(interval);
+          this.exporting = false;
+          this.exportCompleted = true;
+        }
+      }, 1000);
+      let databaseNames = []
+      // databaseNames.push("ry-vue-call")
+      // // databaseNames.push(this.dataBaseName)
+      // console.log(databaseNames);
+      // console.log(this.$store.state);
+
+      // return;
+      // 执行导出接口
+      startExport(databaseNames).then(response => {
+        console.log(response);
+        // 根据后端返回的数据更新状态或进行其他操作
+      })
+    },
+    checkExportStatus1() {
+      // 调用后端接口检查导出状态
+      checkExportStatus().then(response => {
+        console.log(response);
+        // 根据后端返回的数据更新状态或进行其他操作
+        // this.exportCompleted = response.data.includes('completed');
+      })
+    },
+    handleDownloadEnd() {
+      // 调用后端接口下载文件
       this.loading = true;
       let applicationType = "application/zip";
       var fileTheName = `engineering_${new Date().getTime()}.zip`;
-
-      downloadEngineering().then((res) => {
+      downloadZip().then((res) => {
         if (res) {
           const content = res;
-          const blob = new Blob([content], { type: applicationType });
+          const blob = new Blob([content], {type: applicationType});
           const fileName = fileTheName;
           if ("download" in document.createElement("a")) {
             // 非IE下载
@@ -413,7 +326,8 @@ export default {
           this.getList();
           this.$modal.msgSuccess("删除成功");
         })
-        .catch(() => {});
+        .catch(() => {
+        });
     },
     /** 导出按钮操作 */
     handleExport() {
@@ -444,7 +358,7 @@ export default {
       downloadEngineering().then(async (data) => {
         const isBlob = blobValidate(data);
         if (isBlob) {
-          const blob = new Blob([data], { type: "application/zip" });
+          const blob = new Blob([data], {type: "application/zip"});
           // saveAs(blob, filename);
           if ("download" in document.createElement("a")) {
             // 非IE下载
@@ -535,7 +449,125 @@ export default {
       //     Message.error("下载文件出现错误,请联系管理员!");
       //     downloadLoadingInstance.close();
       //   });
+
+      // this.download(
+      //   "/system/engineering/download1",
+      //   {
+      //   },
+      //   `type_${new Date().getTime()}.zip`
+      // );
+      // return;
+      // downloadFile() {
+      //   // window.location.header = {
+      //   //   "Authorization": `Bearer ${getToken()}`
+      //   // }
+      //   // window.location.href = `http://192.168.110.59:8066/system/engineering/download1`
+      //
+      //
+      //   // Fetch API 获取文件
+      //   // fetch('http://192.168.110.59:8066/system/engineering/download1', {
+      //   //   headers: {
+      //   //     'Authorization': `Bearer ${getToken()}`,
+      //   //   },
+      //   //   method: 'GET',
+      //   //   mode: 'cors',
+      //   //   redirect: 'follow',
+      //   //   referrerPolicy: 'no-referrer',
+      //   // }).then(response => {
+      //   //   if (response.ok) {
+      //   //     // 监听下载进度
+      //   //     const reader = response.body.getReader();
+      //   //     let receivedLength = 0;
+      //   //     return new ReadableStream({
+      //   //       start(controller) {
+      //   //         function push() {
+      //   //           reader.read().then(({done, value}) => {
+      //   //             if (done) {
+      //   //               controller.close();
+      //   //               console.log('Fetch completed');
+      //   //             } else {
+      //   //               receivedLength += value.length;
+      //   //               // 这里只是打印了接收到的数据大小,你可以根据实际情况展示下载进度
+      //   //               console.log(`Received ${receivedLength} bytes`);
+      //   //               controller.enqueue(value);
+      //   //               push();
+      //   //             }
+      //   //           });
+      //   //         }
+      //   //
+      //   //         push();
+      //   //       }
+      //   //     }).pipeThrough(new Response([new Blob()])).blob();
+      //   //   } else {
+      //   //     throw new Error('Error fetching file');
+      //   //   }
+      //   // }).then(blob => {
+      //   //   // 创建下载链接并模拟点击
+      //   //   const url = window.URL.createObjectURL(blob);
+      //   //   const a = document.createElement('a');
+      //   //   a.href = url;
+      //   //   a.download = 'myfile.zip';
+      //   //   a.style.display = 'none'; // 隐藏a标签
+      //   //   document.body.appendChild(a);
+      //   //   a.click();
+      //   //   setTimeout(() => {
+      //   //     window.URL.revokeObjectURL(url);
+      //   //     document.body.removeChild(a);
+      //   //   }, 0);
+      //   // });
+      //
+      //   // return;
+      //   // axios({
+      //   //   // url: 'http://192.168.110.59:8066/api/download/largeFile',
+      //   //   url: 'http://localhost:8066/system/engineering/largeFile',
+      //   //   method: 'GET',
+      //   //   responseType: 'blob', // 设置响应类型为Blob
+      //   //   headers: {
+      //   //     'Range': 'bytes=0-' // 设置Range头部,表示下载整个文件,可以根据需求调整
+      //   //   },
+      //   // })
+      //   //   .then(response => {
+      //   //     // 创建Blob对象并触发下载
+      //   //     const blob = new Blob([response.data], {type: 'application/octet-stream'});
+      //   //     const link = document.createElement('a');
+      //   //     link.href = window.URL.createObjectURL(blob);
+      //   //     link.download = 'largeFile.zip';
+      //   //     document.body.appendChild(link);
+      //   //     link.click();
+      //   //     document.body.removeChild(link);
+      //   //   })
+      //   //   .catch(error => {
+      //   //     console.error('Error downloading file:', error);
+      //   //   });
+      //
+      //
+      //   // .then((response) => {
+      //   //   // 创建Blob对象并生成一个指向该对象的URL
+      //   //   const blob = new Blob([response.data], {type: 'application/zip'});
+      //   //   const url = window.URL.createObjectURL(blob);
+      //   //   // 创建隐藏的可下载链接
+      //   //   const link = document.createElement('a');
+      //   //   link.style.display = 'none';
+      //   //   link.href = url;
+      //   //   link.download = 'download.zip'; // 自定义下载后的文件名
+      //   //   // 触发点击事件以开始下载
+      //   //   document.body.appendChild(link);
+      //   //   link.click();
+      //   //   setTimeout(() => {
+      //   //     // 下载完成后再移除DOM元素和释放内存
+      //   //     document.body.removeChild(link);
+      //   //     window.URL.revokeObjectURL(url);
+      //   //   }, 0);
+      //   // })
+      //   // .catch((error) => {
+      //   //   console.error('下载失败:', error);
+      //   // });
+      //
+      // },
+
     },
-  },
-};
+  }
+  ,
+}
+;
 </script>