From 10d6587ec3f5c4779f40bcc1afe54d441db68711 Mon Sep 17 00:00:00 2001
From: lxp <1928192722@qq.com>
Date: 星期三, 12 三月 2025 15:35:30 +0800
Subject: [PATCH] 报告编制修改

---
 inspect-server/src/main/java/com/ruoyi/inspect/controller/InsReportApproveConfigController.java    |   39 +
 ruoyi-common/src/main/java/com/ruoyi/common/enums/AttachmentType.java                              |   53 +
 ruoyi-common/src/main/java/com/ruoyi/common/config/MinioConfig.java                                |    1 
 inspect-server/src/main/java/com/ruoyi/inspect/controller/InsReportController.java                 |  217 +++++++
 ruoyi-common/src/main/java/com/ruoyi/common/pojo/AttachmentTable.java                              |   36 +
 ruoyi-common/src/main/java/com/ruoyi/common/controller/AttachmentTypeController.java               |   74 ++
 inspect-server/src/main/java/com/ruoyi/inspect/service/InsReportService.java                       |   54 +
 ruoyi-common/src/main/java/com/ruoyi/common/mapper/AttachmentTableMapper.java                      |   10 
 inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsReportServiceImpl.java              |  876 +++++++++++++++++++++++++++++
 ruoyi-system/src/main/resources/mapper/system/UserMapper.xml                                       |   24 
 performance-server/src/main/resources/mapper/PerformanceShiftMapper.xml                            |    7 
 inspect-server/src/main/java/com/ruoyi/inspect/service/InsReportApproveConfigService.java          |   24 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/UserMapper.java                                 |    3 
 inspect-server/pom.xml                                                                             |    5 
 ruoyi-common/src/main/java/com/ruoyi/common/service/impl/AttachmentTableServiceImpl.java           |  218 +++++++
 inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsReportApproveConfigServiceImpl.java |   92 +++
 ruoyi-common/src/main/java/com/ruoyi/common/service/AttachmentTableService.java                    |   23 
 17 files changed, 1,753 insertions(+), 3 deletions(-)

diff --git a/inspect-server/pom.xml b/inspect-server/pom.xml
index ecadd7d..30dc02e 100644
--- a/inspect-server/pom.xml
+++ b/inspect-server/pom.xml
@@ -45,6 +45,11 @@
             <groupId>com.ruoyi</groupId>
             <artifactId>performance-server</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>cnas-process</artifactId>
+        </dependency>
+
 
         <!-- poi-tl鍖呯敓鎴愭姤鍛� -->
         <dependency>
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/controller/InsReportApproveConfigController.java b/inspect-server/src/main/java/com/ruoyi/inspect/controller/InsReportApproveConfigController.java
new file mode 100644
index 0000000..fbe24e2
--- /dev/null
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/controller/InsReportApproveConfigController.java
@@ -0,0 +1,39 @@
+package com.ruoyi.inspect.controller;
+
+import com.ruoyi.common.core.domain.Result;
+import com.ruoyi.inspect.dto.ApproveConfigDTO;
+import com.ruoyi.inspect.service.InsReportApproveConfigService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/approveConfig")
+@Api(tags = "鎶ュ憡瀹℃壒绛惧悕閰嶇疆")
+public class InsReportApproveConfigController {
+
+    @Autowired
+    private InsReportApproveConfigService insReportApproveConfigService;
+
+    @ApiOperation("瀹℃壒绛惧悕閰嶇疆鎸夐挳")
+    @GetMapping("/getApproveConfigList")
+    public Result getApproveConfigList(){
+        return Result.success(insReportApproveConfigService.getApproveConfigList());
+    }
+
+    @ApiOperation("鏌ヨ浜哄憳")
+    @GetMapping("/getUserList")
+    public Result getUserList(){
+        return Result.success(insReportApproveConfigService.getUserList());
+    }
+
+    @ApiOperation("鏇存柊瀹℃壒绛惧悕閰嶇疆")
+    @PostMapping("/updateApproveConfig")
+    public Result updateApproveConfig(@RequestBody ApproveConfigDTO approveConfigDTO){
+        return Result.success(insReportApproveConfigService.updateApproveConfig(approveConfigDTO));
+    }
+
+
+
+}
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/controller/InsReportController.java b/inspect-server/src/main/java/com/ruoyi/inspect/controller/InsReportController.java
new file mode 100644
index 0000000..c1824d4
--- /dev/null
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/controller/InsReportController.java
@@ -0,0 +1,217 @@
+package com.ruoyi.inspect.controller;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson2.JSON;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.domain.Result;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.JackSonUtil;
+import com.ruoyi.framework.exception.ErrorException;
+import com.ruoyi.inspect.dto.BatchApprovalReportDTO;
+import com.ruoyi.inspect.dto.ReportPageDto;
+import com.ruoyi.inspect.pojo.InsReport;
+import com.ruoyi.inspect.service.InsReportService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.logging.log4j.util.Strings;
+import org.apache.poi.hssf.record.SSTRecord;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Scanner;
+
+@RestController
+@RequestMapping("/insReport")
+@Api(tags = "妫�楠屾姤鍛�")
+public class InsReportController {
+
+
+    @Resource
+    private InsReportService insReportService;
+
+    @Value("${wordUrl}")
+    private String wordUrl;
+
+    @ApiOperation(value = "鏌ョ湅妫�楠屾姤鍛婂垪琛�")
+    @GetMapping("/pageInsReport")
+    public Result pageInsReport(Page page , ReportPageDto reportPageDto) throws Exception {
+        return Result.success(insReportService.pageInsReport(page, reportPageDto));
+    }
+
+
+    @ApiOperation(value = "涓�閿鎵规寜閽�")
+    @PostMapping("/batchApprovalReport")
+    @Log(title = "妫�楠屾姤鍛�", businessType = BusinessType.UPDATE)
+    public Result batchApprovalReport(@RequestBody BatchApprovalReportDTO batchApprovalReportDTO){
+        try {
+            insReportService.batchApprovalReport(batchApprovalReportDTO.getIds());
+        }catch (Exception e){
+            throw new RuntimeException(e);
+        }
+        return Result.success();
+    }
+
+    @ApiOperation(value = "鑾峰彇瀹℃壒杩涘害")
+    @GetMapping("/getBatchApprovalProgress")
+    public Result getBatchApprovalProgress(){
+        return Result.success(insReportService.getBatchApprovalProgress());
+    }
+
+
+    @ApiOperation(value = "鏌ョ湅妫�楠屾姤鍛婃暟閲忎俊鎭�")
+    @GetMapping("/getReportCountInfo")
+    public Result getReportCountInfo(@RequestParam Map<String, Object> params) throws Exception {
+        ReportPageDto reportPageDto = JackSonUtil.unmarshal(JackSonUtil.marshal(params), ReportPageDto.class);
+        return Result.success(insReportService.getReportCountInfo(reportPageDto));
+    }
+
+    @ApiOperation(value = "涓婁紶鎸夐挳")
+    @PostMapping("/inReport")
+    @Log(title = "妫�楠屾姤鍛�", businessType = BusinessType.IMPORT)
+    public Result inReport(MultipartFile file, Integer id) {
+        String urlString;
+        String pathName;
+        try {
+            String path = wordUrl;
+            File realpath = new File(path);
+            if (!realpath.exists()) {
+                realpath.mkdirs();
+            }
+            InsReport insReport = insReportService.getById(id);
+            // 濡傛灉URLS鏈夊�� 鍏堝皢璇ユ枃浠跺垹闄�
+            if(Strings.isNotEmpty(insReport.getUrlS())){
+                String url = wordUrl + File.separator + insReport.getUrlS().replace("/word/", "");
+                File file1 = new File(url);
+                if(file1.exists()) {
+                    file1.delete();
+                }
+            }
+            String code = insReport.getCode().replace("/", "") + ".docx";
+            pathName = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyMMddHHmmss")) + "_" + code;
+            urlString = realpath + "/" + pathName;
+            file.transferTo(new File(urlString));
+            return Result.success(insReportService.inReport("/word/" + pathName, id));
+        } catch (Exception e) {
+            throw new ErrorException("鏂囦欢涓婁紶澶辫触");
+        }
+    }
+    //涓嬭浇
+    @GetMapping("/downReport")
+    @Log(title = "妫�楠屾姤鍛�", businessType = BusinessType.EXPORT)
+    public void downReport(@RequestParam("id") Integer id,@RequestParam("type") Integer type,  HttpServletResponse response) {
+        insReportService.downReport(id,type, response);
+    }
+
+
+
+    @ApiOperation(value = "杩樺師鎸夐挳")
+    @PostMapping("/upReportUrl")
+    @Log(title = "妫�楠屾姤鍛�", businessType = BusinessType.UPDATE)
+    public Result upReportUrl(Integer id,Integer type) {
+        insReportService.upReportUrl(id,type);
+        return Result.success();
+    }
+
+    @ApiOperation(value = "缂栧埗鎸夐挳")
+    @GetMapping("/upReportFile")
+    @Log(title = "妫�楠屾姤鍛�", businessType = BusinessType.UPDATE)
+    public Result upReportFile() {
+        return Result.success();
+    }
+
+    @ApiOperation(value = "鎻愪氦鎸夐挳")
+    @PostMapping("/writeReport")
+    @Log(title = "妫�楠屾姤鍛�", businessType = BusinessType.UPDATE)
+    public Result writeReport(Integer id) {
+
+        return Result.success(insReportService.writeReport(id));
+    }
+
+    @ApiOperation(value = "瀹℃牳鎸夐挳")
+    @PostMapping("/examineReport")
+    @Log(title = "妫�楠屾姤鍛�", businessType = BusinessType.UPDATE)
+    public Result examineReport(Integer id, Integer isExamine, String examineTell) {
+        return Result.success(insReportService.examineReport(id, isExamine, examineTell));
+    }
+
+    @ApiOperation(value = "鎵瑰噯鎸夐挳")
+    @PostMapping("/ratifyReport")
+    @Log(title = "妫�楠屾姤鍛�", businessType = BusinessType.UPDATE)
+    public Result ratifyReport(Integer id, Integer isRatify, String ratifyTell) {
+        return Result.success(insReportService.ratifyReport(id, isRatify, ratifyTell));
+    }
+
+    @RequestMapping("/onlyOffice/save")
+    @Log(title = "妫�楠屾姤鍛�", businessType = BusinessType.OTHER)
+    public void saveFile(@RequestParam String fileName, HttpServletRequest request, HttpServletResponse response) {
+        PrintWriter writer = null;
+        try {
+            writer = response.getWriter();
+            // 鑾峰彇浼犺緭鐨刯son鏁版嵁
+            Scanner scanner = new Scanner(request.getInputStream()).useDelimiter("\\A");
+            String body = scanner.hasNext() ? scanner.next() : "";
+            JSONObject jsonObject = JSONObject.parseObject(body);
+
+            if (jsonObject.containsKey("url")) {
+                String jsonArray = jsonObject.get("lastsave").toString(); // 鏇存柊鏃堕棿
+                String fileUrl = jsonObject.get("url").toString(); // 鏇存柊鏂囦欢url
+                HttpUtil.downloadFile(fileUrl, FileUtil.file(wordUrl + "/" + fileName));
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            writer.write("{\"error\":-1}");
+            return;
+        }
+        /*
+         * status = 1锛屾垜浠粰onlyOffice鐨勬湇鍔¤繑鍥瀧"error":"0"}鐨勪俊鎭��
+         * 杩欐牱onlyOffice浼氳涓哄洖璋冩帴鍙f槸娌¢棶棰樼殑锛岃繖鏍峰氨鍙互鍦ㄧ嚎缂栬緫鏂囨。浜嗭紝鍚﹀垯鐨勮瘽浼氬脊鍑虹獥鍙h鏄�
+         */
+        if (Objects.nonNull(writer)) {
+            writer.write("{\"error\":0}");
+        }
+    }
+
+    @ApiOperation(value = "鎵归噺涓嬭浇鎸夐挳")
+    @GetMapping("/downAll")
+    @Log(title = "妫�楠屾姤鍛�", businessType = BusinessType.EXPORT)
+    public Result downAll(String ids) {
+        return Result.success(insReportService.downAll(ids));
+    }
+
+    @ApiOperation(value = "鎵归噺涓婁紶鎸夐挳")
+    @PostMapping("/upAll")
+    @Log(title = "妫�楠屾姤鍛�", businessType = BusinessType.IMPORT)
+    public Result upAll(MultipartFile file) throws IOException {
+        return Result.success(insReportService.upAll(file));
+    }
+
+    @ApiOperation(value = "鎾ゅ洖鎸夐挳")
+    @PostMapping("/withdraw")
+    @Log(title = "妫�楠屾姤鍛�", businessType = BusinessType.UPDATE)
+    public Result withdraw(@RequestBody Map<String,Object> map) {
+        insReportService.withdraw(map);
+        return  Result.success();
+    }
+
+    @GetMapping("/getLaboratoryByReportId")
+    public Result getLaboratoryByReportId(Integer id) {
+        return Result.success(insReportService.getLaboratoryByReportId(id));
+    }
+
+
+
+}
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/service/InsReportApproveConfigService.java b/inspect-server/src/main/java/com/ruoyi/inspect/service/InsReportApproveConfigService.java
new file mode 100644
index 0000000..ec87c5a
--- /dev/null
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/service/InsReportApproveConfigService.java
@@ -0,0 +1,24 @@
+package com.ruoyi.inspect.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.inspect.dto.ApproveConfigDTO;
+import com.ruoyi.inspect.pojo.InsReportApproveConfig;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author 27233
+ * @description 閽堝琛ㄣ�恑ns_report_approve_config(鎶ュ憡瀹℃壒绛惧悕閰嶇疆)銆戠殑鏁版嵁搴撴搷浣淪ervice
+ * @createDate 2024-12-10 09:36:10
+ */
+public interface InsReportApproveConfigService extends IService<InsReportApproveConfig> {
+
+    List<InsReportApproveConfig> getApproveConfigList();
+
+    InsReportApproveConfig getApproveConfigByLaboratory(String laboratory);
+
+    Map<String, List<Map<String,Object>>> getUserList();
+
+    boolean updateApproveConfig(ApproveConfigDTO approveConfigDTO);
+}
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/service/InsReportService.java b/inspect-server/src/main/java/com/ruoyi/inspect/service/InsReportService.java
new file mode 100644
index 0000000..7ac2eba
--- /dev/null
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/service/InsReportService.java
@@ -0,0 +1,54 @@
+package com.ruoyi.inspect.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.inspect.dto.ReportPageDto;
+import com.ruoyi.inspect.pojo.InsReport;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Administrator
+ * @description 閽堝琛ㄣ�恑ns_report(妫�楠屾姤鍛�)銆戠殑鏁版嵁搴撴搷浣淪ervice
+ * @createDate 2024-03-17 22:10:02
+ */
+public interface InsReportService extends IService<InsReport> {
+
+    IPage<ReportPageDto> pageInsReport(Page page, ReportPageDto reportPageDto);
+
+    int inReport(String url, Integer id);
+
+    void upReportUrl(Integer id,Integer type);
+    // 涓嬭浇
+    void downReport(Integer id, Integer type , HttpServletResponse response);
+
+    //鎻愪氦
+    int writeReport(Integer id);
+
+    //瀹℃牳
+    int examineReport(Integer id, Integer isExamine, String examineTell);
+
+    //鎵瑰噯
+    int ratifyReport(Integer id, Integer isRatify, String ratifyTell);
+
+    int wordInsertUrl(Map<String, Object> map, String url);
+
+    String downAll(String ids);
+
+    int upAll(MultipartFile file) throws IOException;
+
+    void withdraw(Map<String,Object> map);
+
+    List<Map<String,Object>> getLaboratoryByReportId(Integer id);
+
+    Map<String,Object> getReportCountInfo(ReportPageDto reportPageDto);
+
+    void batchApprovalReport(List<Integer> ids);
+
+    Map<String,Object> getBatchApprovalProgress();
+}
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsReportApproveConfigServiceImpl.java b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsReportApproveConfigServiceImpl.java
new file mode 100644
index 0000000..8ccc3f3
--- /dev/null
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsReportApproveConfigServiceImpl.java
@@ -0,0 +1,92 @@
+package com.ruoyi.inspect.service.impl;
+
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.core.domain.entity.User;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.inspect.dto.ApproveConfigDTO;
+import com.ruoyi.inspect.mapper.InsOrderMapper;
+import com.ruoyi.inspect.mapper.InsReportApproveConfigMapper;
+import com.ruoyi.inspect.pojo.InsReportApproveConfig;
+import com.ruoyi.inspect.service.InsReportApproveConfigService;
+import com.ruoyi.system.mapper.UserMapper;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author 27233
+ * @description 閽堝琛ㄣ�恑ns_report_approve_config(鎶ュ憡瀹℃壒绛惧悕閰嶇疆)銆戠殑鏁版嵁搴撴搷浣淪ervice瀹炵幇
+ * @createDate 2024-12-10 09:36:10
+ */
+@Service
+public class InsReportApproveConfigServiceImpl extends ServiceImpl<InsReportApproveConfigMapper, InsReportApproveConfig>
+        implements InsReportApproveConfigService {
+
+
+    @Autowired
+    private UserMapper userMapper;
+
+    @Autowired
+    private InsOrderMapper insOrderMapper;
+
+    @Override
+    public List<InsReportApproveConfig> getApproveConfigList() {
+        Integer userId = Integer.parseInt(SecurityUtils.getUserId()+"");
+        User user = userMapper.selectById(userId);//褰撳墠鐧诲綍鐨勪汉
+        //鑾峰彇褰撳墠浜烘墍灞炲疄楠屽id
+        String departLimsId = user.getDepartLimsId();
+        String laboratory = null;
+        if (ObjectUtils.isNotEmpty(departLimsId) && !departLimsId.isEmpty()) {
+            String[] split = departLimsId.split(",");
+            //鏌ヨ瀵瑰簲鏋舵瀯鍚嶇О(閫氫俊瀹為獙瀹�,鐢靛姏瀹為獙瀹�,妫�娴嬪姙)
+            String departLims = insOrderMapper.seldepLimsId(Integer.parseInt(split[split.length - 1]));
+            if (departLims.contains("瀹為獙瀹�")) {
+                laboratory = departLims;
+            }
+        }
+        return baseMapper.selectList(Wrappers.<InsReportApproveConfig>lambdaQuery()
+                .eq(StringUtils.isNotBlank(laboratory),InsReportApproveConfig::getLaboratory,laboratory));
+    }
+
+    @Override
+    public InsReportApproveConfig getApproveConfigByLaboratory(String laboratory) {
+        return baseMapper.selectOne(Wrappers.<InsReportApproveConfig>lambdaQuery()
+                .eq(StringUtils.isNotBlank(laboratory),InsReportApproveConfig::getLaboratory,laboratory));
+    }
+
+    @Override
+    public Map<String, List<Map<String,Object>>> getUserList() {
+        //鏌ヨ閫氫俊鍜岀數鍔涗笅鐨勪汉鍛樹俊鎭�
+        //鏌ヨ褰撳墠鐧诲綍浜哄憳鐨勬灦鏋�
+        Integer userId = Integer.parseInt(SecurityUtils.getUserId()+"");
+        //鍒ゆ柇鍏ㄩ儴,涓汉,缁勭粐鐨勬潈闄�
+        User user = userMapper.selectById(userId);//褰撳墠鐧诲綍鐨勪汉
+        //鑾峰彇褰撳墠浜烘墍灞炲疄楠屽id
+        String laboratory = "";
+        String departLimsId = user.getDepartLimsId();
+        if (org.apache.commons.lang3.ObjectUtils.isNotEmpty(departLimsId)) {
+            String[] split = departLimsId.split(",");
+            //鏌ヨ瀵瑰簲鏋舵瀯鍚嶇О(閫氫俊瀹為獙瀹�,鐢靛姏瀹為獙瀹�,妫�娴嬪姙)
+            String departLims = userMapper.seldepLimsId(Integer.parseInt(split[split.length - 1]));
+            if (departLims.contains("瀹為獙瀹�")) {
+                laboratory = departLims;
+            }
+        }
+        return userMapper.getPersonList(laboratory).stream().collect(Collectors.groupingBy(m->m.get("depName").toString()));
+    }
+
+    @Override
+    public boolean updateApproveConfig(ApproveConfigDTO approveConfigDTO) {
+        if(!approveConfigDTO.getConfigList().isEmpty()){
+            approveConfigDTO.getConfigList().forEach(config->baseMapper.updateById(config));
+            return true;
+        }
+        throw new RuntimeException("鏇存柊澶辫触");
+    }
+}
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsReportServiceImpl.java b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsReportServiceImpl.java
new file mode 100644
index 0000000..735cbaa
--- /dev/null
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsReportServiceImpl.java
@@ -0,0 +1,876 @@
+package com.ruoyi.inspect.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSONArray;
+import com.aspose.words.License;
+import com.aspose.words.SaveFormat;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.deepoove.poi.XWPFTemplate;
+import com.deepoove.poi.data.FilePictureRenderData;
+import com.itextpdf.text.BadElementException;
+import com.itextpdf.text.DocumentException;
+import com.itextpdf.text.pdf.PdfContentByte;
+import com.itextpdf.text.pdf.PdfReader;
+import com.itextpdf.text.pdf.PdfStamper;
+import com.ruoyi.common.config.MinioConfig;
+import com.ruoyi.common.core.domain.entity.User;
+import com.ruoyi.common.enums.AttachmentType;
+import com.ruoyi.common.mapper.AttachmentTableMapper;
+import com.ruoyi.common.pojo.AttachmentTable;
+import com.ruoyi.common.service.AttachmentTableService;
+import com.ruoyi.common.utils.QueryWrappers;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.framework.exception.ErrorException;
+import com.ruoyi.inspect.dto.ReportPageDto;
+import com.ruoyi.inspect.mapper.*;
+import com.ruoyi.inspect.pojo.InsOrder;
+import com.ruoyi.inspect.pojo.InsOrderState;
+import com.ruoyi.inspect.pojo.InsReport;
+import com.ruoyi.process.pojo.ProcessReport;
+import com.ruoyi.inspect.service.InsReportService;
+import com.ruoyi.process.mapper.ProcessReportMapper;
+import com.ruoyi.system.mapper.UserMapper;
+import io.minio.MinioClient;
+import io.minio.PutObjectArgs;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import javax.imageio.ImageIO;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.math.BigDecimal;
+import java.net.URLEncoder;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * @author Administrator
+ * @description 閽堝琛ㄣ�恑ns_report(妫�楠屾姤鍛�)銆戠殑鏁版嵁搴撴搷浣淪ervice瀹炵幇
+ * @createDate 2024-03-17 22:10:02
+ */
+@Service
+@Slf4j
+public class InsReportServiceImpl extends ServiceImpl<InsReportMapper, InsReport>
+        implements InsReportService {
+
+    @Resource
+    private AttachmentTableMapper attachmentTableMapper;
+
+    @Resource
+    private AttachmentTableService attachmentTableService;
+
+    @Resource
+    private MinioConfig minioConfig;
+
+
+
+    @Resource
+    private UserMapper userMapper;
+
+    @Resource
+    private InsReportMapper insReportMapper;
+
+    @Resource
+    ProcessReportMapper processReportMapper;
+
+    @Value("${wordUrl}")
+    private String wordUrl;
+
+    @Value("${file.licenseUrl}")
+    private String licenseUrl;
+
+    @Value("${file.path}")
+    private String imgUrl;
+
+    @Resource
+    private InsOrderMapper insOrderMapper;
+
+    @Resource
+    private RedisTemplate<String, Object> redisTemplate;
+
+    @Resource
+    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
+
+    @Resource
+    private InsOrderStateMapper insOrderStateMapper;
+
+    private static final String SYNC_REPORT_KEY_PREFIX = "syncApprovalReport_lock_";
+
+    @Resource
+    private InsReportApproveConfigMapper insReportApproveConfigMapper;
+
+    @Override
+    public IPage<ReportPageDto> pageInsReport(Page page, ReportPageDto reportPageDto) {
+        User user = userMapper.selectById(SecurityUtils.getUserId());//褰撳墠鐧诲綍鐨勪汉
+        //鑾峰彇褰撳墠浜烘墍灞炲疄楠屽id
+        String departLimsId = user.getDepartLimsId();
+        String laboratory = null;
+        if (ObjectUtils.isNotEmpty(departLimsId) && !departLimsId.isEmpty()) {
+            String[] split = departLimsId.split(",");
+            //鏌ヨ瀵瑰簲鏋舵瀯鍚嶇О(閫氫俊瀹為獙瀹�,鐢靛姏瀹為獙瀹�,妫�娴嬪姙)
+            String departLims = insOrderMapper.seldepLimsId(Integer.parseInt(split[split.length - 1]));
+            if (departLims.contains("瀹為獙瀹�")) {
+                laboratory = departLims;
+            }
+        }
+        QueryWrapper<ReportPageDto> wrapper = QueryWrappers.queryWrappers(reportPageDto);
+        if(Objects.nonNull(reportPageDto) && Objects.nonNull(reportPageDto.getCreateTimeRange())){
+            wrapper.gt(reportPageDto.getCreateTimeRange().size()>1,"create_time",reportPageDto.getCreateTimeRange().get(0))
+                    .lt(reportPageDto.getCreateTimeRange().size()>1,"create_time",reportPageDto.getCreateTimeRange().get(1));
+        }
+        IPage<ReportPageDto> iPage = insReportMapper.pageInsReport(page, wrapper, laboratory);
+        return iPage;
+    }
+
+    @Override
+    public int inReport(String url, Integer id) {
+        InsReport insReport = new InsReport();
+        insReport.setId(id);
+        insReport.setUrlS(url);
+        return insReportMapper.updateById(insReport);
+    }
+
+    // 杩樺師
+    @Override
+    public void upReportUrl(Integer id,Integer type) {
+        List<AttachmentTable> attachmentTables = attachmentTableMapper.selectList(new LambdaQueryWrapper<AttachmentTable>()
+                .eq(AttachmentTable::getSubclassId, id)
+                .eq(AttachmentTable::getOtherTableName, AttachmentType.getAttachmentValue(type))
+                .orderByAsc(AttachmentTable::getId));
+        if(CollectionUtils.isNotEmpty(attachmentTables)) {
+           // 鑾峰彇鎵�鏈夌殑id
+            List<Integer> collect = attachmentTables.stream().map(AttachmentTable::getId).collect(Collectors.toList());
+            // 闄や簡绗竴涓叏閮ㄥ垹闄� 鍒犻櫎鎵�鏈夌殑闄勪欢
+            collect.remove(0);
+            if(collect.size() > 0) {
+                attachmentTableMapper.deleteBatchIds(collect);
+            }
+        }
+    }
+
+    @Override
+    public void downReport(Integer id,Integer type, HttpServletResponse response) {
+        InsReport insReport = insReportMapper.selectById(id);
+        String url = "";
+        // 0 涓嬭浇docx 1 涓嬭浇pdf
+        if(type == 0) {
+            url  = Strings.isNotEmpty(insReport.getUrlS()) ? insReport.getUrlS() : insReport.getUrl();
+        }else {
+            url = insReport.getTempUrlPdf();
+        }
+        if(Strings.isEmpty(url)){
+            throw new ErrorException("鎶ュ憡鍦板潃涓虹┖");
+        }
+        File file = new File(wordUrl + File.separator + url.replace("/word/", ""));
+        try {
+            String fileName = file.getName();
+            if(fileName.indexOf("_") != -1) {
+                fileName = fileName.split("_")[1];
+            }
+            fileName = URLEncoder.encode(fileName, "UTF-8");
+            response.setContentType("application/octet-stream");
+            response.setHeader("Content-disposition","attachment;filename=" + fileName);
+            ServletOutputStream stream = response.getOutputStream();
+            FileInputStream fileInputStream = new FileInputStream(file);
+            byte[] bytes = new byte[1024];
+            int byteRead;
+            while((byteRead = fileInputStream.read(bytes)) != -1){
+                stream.write(bytes, 0, byteRead);
+                stream.flush();
+            }
+            fileInputStream.close();
+            stream.close();
+        }catch (Exception e){
+            throw new ErrorException("涓嬭浇澶辫触");
+        }
+    }
+
+
+
+
+
+    //鎻愪氦
+    @Override
+    public int writeReport(Integer id) {
+        int userId = Integer.parseInt(SecurityUtils.getUserId() + "");
+        InsReport insReport = insReportMapper.selectById(id);
+        insReport.setId(id);
+        insReport.setState(1);
+        insReport.setWriteTime(LocalDateTime.now());//鎻愪氦鏃堕棿
+        insReport.setWriteUserId(userId);//鎻愪氦浜�
+        return insReportMapper.updateById(insReport);
+    }
+
+    /**
+     * 鍒涘缓涓存椂鏂囦欢
+     * @param inputStream 杈撳叆娴�
+     * @param suffix 鍚庣紑
+     * @return
+     */
+    public String temporaryFile(InputStream inputStream,String suffix) {
+        String tempFilePath = "";
+        try {
+            File tempFile = File.createTempFile(UUID.randomUUID().toString(), suffix);
+            tempFile.deleteOnExit();
+            // 灏嗚緭鍏ユ祦鍐呭璧嬪�肩殑涓存椂鏂囦欢
+            try(FileOutputStream fileInputStream = new FileOutputStream(tempFile)) {
+                byte[] bytes = new byte[1024];
+                int len;
+                while((len = inputStream.read(bytes)) != -1) {
+                    fileInputStream.write(bytes,0,len);
+                }
+                // 鑾峰彇涓存椂鏂囦欢鐨勮矾寰�
+                tempFilePath = tempFile.getAbsolutePath();
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        return tempFilePath;
+    }
+
+
+    /**
+     * 灏嗘枃浠朵笂浼犲埌Minio
+     * @return
+     */
+    public void  uploadMinio(String url,Integer id) {
+        String suffix = url.substring(url.lastIndexOf("."));
+        // 閲嶆柊涓婁紶鍒癕inIo
+        File file = new File(url);
+        String fileName = UUID.randomUUID().toString() + suffix;
+        FileInputStream stream = null;
+        try {
+            MinioClient build = MinioClient.builder().endpoint(minioConfig.getEndpoint(), minioConfig.getPort(), minioConfig.getSecure())
+                    .credentials(minioConfig.getAccessKey(), minioConfig.getSecretKey())
+                    .build();
+            stream = new FileInputStream(file);
+            build.putObject(
+                    PutObjectArgs.builder()
+                            .bucket(minioConfig.getBucketName())
+                            .object(fileName)
+                            .stream(stream, file.length(), -1)
+                            .contentType("application/octet-stream")
+                            .userMetadata(Collections.singletonMap("Content-Disposition", "attachment; filename=\"" + fileName + "\""))
+                            .build()
+            );
+            // 淇濆瓨鍒版暟鎹簱
+            AttachmentTable attachmentTable = new AttachmentTable();
+            attachmentTable.setBucketName(minioConfig.getBucketName());
+            attachmentTable.setFileName(fileName);
+            attachmentTable.setSubclassId(id);
+            attachmentTable.setOtherTableName(AttachmentType.getAttachmentValue(1));
+            attachmentTableMapper.insert(attachmentTable);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+
+
+    //瀹℃牳
+    @Override
+    public int examineReport(Integer id, Integer isExamine, String examineTell) {
+        int userId = Integer.parseInt(SecurityUtils.getUserId() + "");
+        InsReport insReport = insReportMapper.selectById(id);
+        insReport.setIsExamine(isExamine);
+        if (ObjectUtils.isNotEmpty(examineTell)) {
+            insReport.setExamineTell(examineTell);
+        }
+        insReport.setExamineUserId(userId);//瀹℃牳浜�
+        insReport.setExamineTime(LocalDateTime.now());//瀹℃牳鏃堕棿
+        if (isExamine == 0) {
+            //濡傛灉瀹℃牳涓嶉�氳繃
+            insReport.setState(0);//鎻愪氦鐘舵�佹敼涓哄緟鎻愪氦
+            return insReportMapper.updateById(insReport);
+        }
+        //鑾峰彇瀹℃牳浜虹殑绛惧悕鍦板潃
+        String signatureUrl;
+        try {
+            signatureUrl = userMapper.selectById(insReport.getExamineUserId()).getSignatureUrl();
+        } catch (Exception e) {
+            throw new ErrorException("鎵句笉鍒板鏍镐汉鐨勭鍚�");
+        }
+        //绯荤粺鐢熸垚鎶ュ憡鍦板潃
+        String url = insReport.getUrl();
+        //鎵嬪姩涓婁紶鎶ュ憡鍦板潃
+        String urlS = insReport.getUrlS();
+        wordInsertUrl(new HashMap<String, Object>() {{
+            put("examineUrl", new FilePictureRenderData(100,50,imgUrl + "/" + signatureUrl));
+        }}, (urlS == null ? url : urlS).replace("/word", wordUrl));
+        // 淇敼涓存椂pdf
+        String tempUrlPdf = wordToPdfTemp((StrUtil.isBlank(urlS) ? url : urlS).replace("/word", wordUrl));
+        insReport.setTempUrlPdf("/word/" + tempUrlPdf);
+        return insReportMapper.updateById(insReport);
+    }
+
+    //鎵瑰噯
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int ratifyReport(Integer id, Integer isRatify, String ratifyTell) {
+        int userId = Integer.parseInt(SecurityUtils.getUserId() + "");
+        InsReport insReport = insReportMapper.selectById(id);
+        insReport.setIsRatify(isRatify);
+        if (ObjectUtils.isNotEmpty(ratifyTell)) {
+            insReport.setRatifyTell(ratifyTell);
+        }
+        insReport.setRatifyUserId(userId);//鎵瑰噯浜�
+        insReport.setRatifyTime(LocalDateTime.now());//鎵瑰噯鏃堕棿
+        if (isRatify == 0) {
+            //濡傛灉鎵瑰噯涓嶉�氳繃
+            insReport.setState(0);//鎻愪氦鐘舵�佹敼涓哄緟鎻愪氦
+            return insReportMapper.updateById(insReport);
+        }
+        //鑾峰彇鎵瑰噯浜虹殑绛惧悕鍦板潃
+        String signatureUrl;
+        try {
+            signatureUrl = userMapper.selectById(insReport.getRatifyUserId()).getSignatureUrl();
+        } catch (Exception e) {
+            throw new ErrorException("鎵句笉鍒版壒鍑嗕汉鐨勭鍚�");
+        }
+        //鑾峰彇鍦烘墍鐨勬姤鍛婁笓鐢ㄧ珷
+        String sealUrl;
+        try {
+            String laboratory = insOrderMapper.selectById(insReport.getInsOrderId()).getLaboratory();
+            sealUrl = insReportMapper.getLaboratoryByName(laboratory);
+        } catch (Exception e) {
+            throw new ErrorException("鎵句笉鍒版姤鍛婁笓鐢ㄧ珷");
+        }
+        if (sealUrl == null) throw new ErrorException("鎵句笉鍒版姤鍛婁笓鐢ㄧ珷");
+        //绯荤粺鐢熸垚鎶ュ憡鍦板潃
+        String url = insReport.getUrl();
+        //鎵嬪姩涓婁紶鎶ュ憡鍦板潃
+        String urlS = insReport.getUrlS();
+        String finalUrl = (urlS == null ? url : urlS).replace("/word", wordUrl);
+        wordInsertUrl(new HashMap<String, Object>() {{
+            put("ratifyUrl", new FilePictureRenderData(100,50,imgUrl + "/" + signatureUrl));
+            put("seal1", new FilePictureRenderData(600,600,imgUrl + "/" + sealUrl));
+            put("seal2", new FilePictureRenderData(600,600,imgUrl + "/" + sealUrl));
+        }}, finalUrl);
+        wordToPdf(finalUrl, sealUrl);
+
+        InsOrder insOrder = new InsOrder();
+        insOrder.setId(insReportMapper.selectById(id).getInsOrderId());
+        insOrder.setState(4);
+        insOrderMapper.updateById(insOrder);
+        // 淇敼涓存椂pdf
+        String tempUrlPdf = wordToPdfTemp((StrUtil.isBlank(urlS) ? url : urlS).replace("/word", wordUrl));
+        insReport.setTempUrlPdf("/word/" + tempUrlPdf);
+        /*鏂板cnas7.8鎶ュ憡缁撴灉*/
+        ProcessReport processReport = new ProcessReport();
+        processReport.setInsReportCode(insReport.getCode());
+        processReportMapper.insert(processReport);
+        return insReportMapper.updateById(insReport);
+    }
+
+    @Override
+    public int wordInsertUrl(Map<String, Object> map, String url) {
+        XWPFTemplate template = XWPFTemplate.compile(url).render(map);
+        try {
+            template.writeAndClose(Files.newOutputStream(Paths.get(url)));
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        return 1;
+    }
+
+    //鎶ュ憡鎵归噺涓嬭浇
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public String downAll(String ids) {
+        List<Long> list = Arrays.stream(ids.split(",")).map(Long::parseLong).collect(Collectors.toList());
+        List<InsReport> insReports = insReportMapper.selectBatchIds(list);
+        String zipFilePath = null;
+        // 涓存椂鏂囦欢澶硅矾寰�
+        try {
+            String tempFolderPath = wordUrl + "/tempFolder";
+            File tempFolder = new File(tempFolderPath);
+            if (tempFolder.exists()) {
+                deleteDirectory(tempFolder); // 鍒犻櫎鏃х殑涓存椂鏂囦欢澶�
+            }
+            tempFolder.mkdirs(); // 鍒涘缓鏂扮殑涓存椂鏂囦欢澶�
+            for (InsReport insReport : insReports) {
+                File sourceFile = new File((ObjectUtils.isNotEmpty(insReport.getUrlS()) ? insReport.getUrlS() : insReport.getUrl()).replace("/word", wordUrl));
+                // 涓嬭浇鏂囦欢鍚嶇О鍘婚櫎鏃堕棿
+                String destinationFileName = sourceFile.getName();
+                if(destinationFileName.indexOf("_") != -1) {
+                    destinationFileName = destinationFileName.split("_")[1];
+                }
+                File destinationFile = new File(tempFolder, destinationFileName);
+                Files.copy(sourceFile.toPath(), destinationFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
+            }
+            // 鍘嬬缉涓存椂鏂囦欢澶�
+            zipFilePath = wordUrl + "/zip/output.zip";
+            zipDirectory(tempFolderPath, zipFilePath);
+
+            // 娓呯悊涓存椂鏂囦欢澶�
+            deleteDirectory(tempFolder);
+
+            System.out.println("ZIP鏂囦欢鍒涘缓瀹屾垚锛�");
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return "/word/zip/output.zip";
+    }
+
+    //鎵归噺涓婁紶
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int upAll(MultipartFile file) {
+        if (file != null) {
+            // 鏍规嵁鏂囦欢鍚嶆煡璇d
+            String fileName = file.getOriginalFilename();
+            String code = fileName.replace(".docx", "").replace("JCZX", "JCZX/");
+            if(fileName.lastIndexOf("_") != -1) {
+                code = code.substring(file.getOriginalFilename().lastIndexOf("_") + 1);
+            }
+            //鏌ヨ鏈鏍哥殑鎶ュ憡鏁版嵁
+            InsReport insReport = insReportMapper.selectOne(Wrappers.<InsReport>lambdaQuery().eq(InsReport::getCode, code).eq(InsReport::getIsExamine,-9));
+            if (ObjectUtils.isEmpty(insReport)) {
+                throw new ErrorException("娌℃湁缂栧彿涓�" + code + "鐨勬姤鍛婃垨璇ユ姤鍛婂凡瀹℃牳閫氳繃");
+            }
+            // 濡傛灉UrlS鏈夊�� 鍏堝皢璇ユ枃浠跺垹闄�
+            if(Strings.isNotEmpty(insReport.getUrlS())) {
+                String url = wordUrl + File.separator + insReport.getUrlS().replace("/word/", "");
+                File file1 = new File(url);
+                if(file1.exists()) {
+                    file1.delete();
+                }
+            }
+            String urlString;
+            String pathName;
+            String path = wordUrl;
+            File realpath = new File(path);
+            if (!realpath.exists()) {
+                realpath.mkdirs();
+            }
+            pathName = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyMMddHHmmss")) + "_" + insReport.getCode().replace("/", "") + ".docx";
+            urlString = realpath + "/" + pathName;
+            // 澶嶅埗鏂囦欢鍒版寚瀹氳矾寰�
+            try {
+                Files.copy(file.getInputStream(), new File(urlString).toPath(), StandardCopyOption.REPLACE_EXISTING);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+            inReport("/word/" + pathName, insReport.getId());
+        }
+        return 0;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void withdraw(Map<String,Object> map) {
+        Integer id = Integer.parseInt(map.get("id").toString());
+        List<String> list = JSONArray.parseArray(map.get("laboratory").toString(), String.class);
+        Integer insOrderId = insReportMapper.selectById(id).getInsOrderId();
+        List<InsOrderState> insOrderStateS = insOrderStateMapper.selectList(new LambdaQueryWrapper<InsOrderState>()
+                .eq(InsOrderState::getInsOrderId, insOrderId)
+                .in(CollectionUtils.isNotEmpty(list),InsOrderState::getLaboratory, list));
+        if(CollectionUtils.isNotEmpty(insOrderStateS)) {
+            List<Integer> collect = insOrderStateS.stream().map(InsOrderState::getId).collect(Collectors.toList());
+            // 淇敼璇ュ崟瀛愯瘯楠屽鐨勭姸鎬佷负寰呭鏍革紝鍒犻櫎鎶ュ憡淇℃伅
+            insOrderStateMapper.update(null,new LambdaUpdateWrapper<InsOrderState>()
+                    .set(InsOrderState::getInsState,3) // 寰呭鏍�
+                    .in(InsOrderState::getId,collect));
+            insReportMapper.delete(new LambdaQueryWrapper<InsReport>().eq(InsReport::getId,id));
+        }
+    }
+
+    @Override
+    public List<Map<String, Object>> getLaboratoryByReportId(Integer id) {
+        List<Map<String, Object>> list = new ArrayList<>();
+        Integer insOrderId = insReportMapper.selectById(id).getInsOrderId();
+        insOrderStateMapper.selectList(new LambdaQueryWrapper<InsOrderState>()
+                        .eq(InsOrderState::getInsOrderId,insOrderId))
+                .forEach(insOrderState -> {
+                    Map<String, Object> map = new HashMap<>();
+                    map.put("label",insOrderState.getLaboratory());
+                    map.put("value",insOrderState.getLaboratory());
+                    list.add(map);
+                });
+        return list;
+    }
+
+    @Override
+    public Map<String, Object> getReportCountInfo(ReportPageDto reportPageDto) {
+        int userId = Integer.parseInt(SecurityUtils.getUserId() + "");
+        HashMap<String, Object> map = new HashMap<>();
+        User user = userMapper.selectById(userId);//褰撳墠鐧诲綍鐨勪汉
+        //鑾峰彇褰撳墠浜烘墍灞炲疄楠屽id
+        String departLimsId = user.getDepartLimsId();
+        String laboratory = null;
+        if (ObjectUtils.isNotEmpty(departLimsId) && !departLimsId.isEmpty()) {
+            String[] split = departLimsId.split(",");
+            //鏌ヨ瀵瑰簲鏋舵瀯鍚嶇О(閫氫俊瀹為獙瀹�,鐢靛姏瀹為獙瀹�,妫�娴嬪姙)
+            String departLims = insOrderMapper.seldepLimsId(Integer.parseInt(split[split.length - 1]));
+            if (departLims.contains("瀹為獙瀹�")) {
+                laboratory = departLims;
+            }
+        }
+        QueryWrapper<ReportPageDto> wrapper = QueryWrappers.queryWrappers(reportPageDto);
+        if(Objects.nonNull(reportPageDto) && Objects.nonNull(reportPageDto.getCreateTimeRange())){
+            wrapper.gt(reportPageDto.getCreateTimeRange().size()>1,"create_time",reportPageDto.getCreateTimeRange().get(0))
+                    .lt(reportPageDto.getCreateTimeRange().size()>1,"create_time",reportPageDto.getCreateTimeRange().get(1));
+
+        }
+        map.put("unSubmitCount",insReportMapper.findReportCountInfo(wrapper,laboratory,"ir.write_user_id").size());
+        map.put("unExamineCount",insReportMapper.findReportCountInfo(wrapper,laboratory,"ir.is_examine").size());
+        map.put("unRatifyCount",insReportMapper.findReportCountInfo(wrapper,laboratory,"ir.is_ratify").size());
+        return map;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void batchApprovalReport(List<Integer> ids) {
+        redisTemplate.setKeySerializer(new StringRedisSerializer());
+        Integer userId = Integer.parseInt(SecurityUtils.getUserId() + "");
+        String key = SYNC_REPORT_KEY_PREFIX+userId;
+        //鎵ц鍓嶅垹闄や箣鍓嶇殑keys
+        deleteRedisKeys(key);
+        synchronized (key) {
+            redisTemplate.opsForValue().set(key,1);
+            RequestContextHolder.setRequestAttributes(RequestContextHolder.getRequestAttributes(),true);
+            //寮傛鎵ц瀹℃壒鎿嶄綔
+            CompletableFuture.runAsync(() -> {
+                try {
+                    runBatchApproval(ids,key);
+                }catch (Exception e){
+                    //鍒犻櫎key
+                    deleteRedisKeys(key);
+                    redisTemplate.opsForValue().set(key+"_exception",e.getMessage());
+                }
+            },threadPoolTaskExecutor);
+        }
+    }
+
+    /**
+     * 鍒犻櫎redis key
+     * @param key
+     */
+    private void deleteRedisKeys(String key){
+        redisTemplate.delete(key);
+        redisTemplate.delete(key+"_num");
+        redisTemplate.delete(key+"_count");
+        redisTemplate.delete(key+"_surplus");
+        redisTemplate.delete(key+"_exception");
+    }
+
+    /**
+     * 鎵ц瀹℃壒鎿嶄綔
+     * @param ids 鎶ュ憡id鍒楄〃
+     */
+    private void runBatchApproval(List<Integer> ids,String keyPrefix) {
+        if(ids.isEmpty()){
+            return;
+        }
+        long start = System.currentTimeMillis();
+        String surplusKey = keyPrefix + "_surplus";//鍓╀綑鏉℃暟
+        String numKey = keyPrefix + "_num";//鎬昏繘搴�
+        String countKey = keyPrefix + "_count";//鎬绘潯鏁�
+        redisTemplate.opsForValue().set(countKey, ids.size());
+        redisTemplate.opsForValue().set(surplusKey, ids.size());
+        Object countObj = redisTemplate.opsForValue().get(countKey);
+        long parsed2 = Long.parseLong(String.valueOf(countObj));
+        AtomicLong count = new AtomicLong(parsed2);
+        for (Integer id : ids) {
+            //涓氬姟浠g爜
+            InsReport insReport = insReportMapper.selectById(id);
+            String laboratory = insOrderMapper.selectById(insReport.getInsOrderId()).getLaboratory();
+            //鑾峰彇绛惧悕鍜屽嵃绔�
+            String sealUrl;
+            String writeUrl;
+            String examineUrl;
+            String ratifyUrl;
+            int writeId;
+            int examineId;
+            int ratifyId;
+            try {
+                sealUrl = insReportMapper.getLaboratoryByName(laboratory);//鍗扮珷
+                Map<String,Object> urlMap = insReportApproveConfigMapper.selectApprovalConfigByLaboratory(laboratory);//绛惧悕
+                writeUrl = imgUrl + "/" + (Objects.isNull(urlMap.get("writeUrl"))?"":urlMap.get("writeUrl").toString());//缂栧埗浜虹鍚島rl
+                examineUrl = imgUrl + "/" +  (Objects.isNull(urlMap.get("examineUrl"))?"":urlMap.get("examineUrl").toString());//瀹℃牳浜虹鍚島rl
+                ratifyUrl = imgUrl + "/" +  (Objects.isNull(urlMap.get("ratifyUrl"))?"":urlMap.get("ratifyUrl").toString());//鎵瑰噯浜虹鍚島rl
+                writeId = Integer.parseInt(urlMap.get("writeId").toString());//缂栧埗浜�
+                examineId = Integer.parseInt(urlMap.get("examineId").toString());//瀹℃牳浜虹
+                ratifyId =Integer.parseInt(urlMap.get("ratifyId").toString());//鎵瑰噯浜�
+            } catch (Exception e) {
+                throw new ErrorException("鎵句笉鍒扮鍚嶅拰鍗扮珷");
+            }
+            //璁剧疆鎶ュ憡淇℃伅
+            insReport.setIsExamine(1);
+            insReport.setIsRatify(1);
+            insReport.setState(1);
+            insReport.setWriteUserId(writeId);
+            insReport.setExamineUserId(examineId);
+            insReport.setRatifyUserId(ratifyId);
+            if(Objects.isNull(insReport.getWriteTime())){
+                insReport.setWriteTime(LocalDateTime.now());
+            }
+            if(Objects.isNull(insReport.getExamineTime())){
+                insReport.setExamineTime(LocalDateTime.now());
+            }
+            if(Objects.isNull(insReport.getRatifyTime())){
+                insReport.setRatifyTime(LocalDateTime.now());
+            }
+            //鏇存柊璁㈠崟鐘舵��
+            InsOrder insOrder = new InsOrder();
+            insOrder.setId(insReport.getInsOrderId());
+            insOrder.setState(4);
+            insOrderMapper.updateById(insOrder);
+            //绯荤粺鐢熸垚鎶ュ憡鍦板潃
+            String url = insReport.getUrl();
+            //鎵嬪姩涓婁紶鎶ュ憡鍦板潃
+            String urlS = insReport.getUrlS();
+            String finalUrl = (StringUtils.isBlank(urlS) ? url : urlS).replace("/word", wordUrl);
+            wordInsertUrl(new HashMap<String, Object>() {{
+                put("writeUrl", new FilePictureRenderData(100,50,writeUrl));
+                put("examineUrl", new FilePictureRenderData(100,50,examineUrl));
+                put("ratifyUrl", new FilePictureRenderData(100,50,ratifyUrl));
+                put("seal1", new FilePictureRenderData(600,600,imgUrl + "/" +sealUrl));
+                put("seal2", new FilePictureRenderData(600,600,imgUrl + "/" +sealUrl));
+            }}, finalUrl);
+            wordToPdf(finalUrl, sealUrl);
+            // 淇敼涓存椂pdf
+            String tempUrlPdf = wordToPdfTemp((StrUtil.isBlank(urlS) ? url : urlS).replace("/word", wordUrl));
+            insReport.setTempUrlPdf("/word/" + tempUrlPdf);
+            //鏇存柊鎶ュ憡鐘舵��
+            insReportMapper.updateById(insReport);
+            //鏇存柊redis鐨刱ey
+            Object o = redisTemplate.opsForValue().get(numKey);
+            if (Objects.isNull(o)) {
+                redisTemplate.opsForValue().set(numKey, 1);
+            } else {
+                long parsed = Long.parseLong(String.valueOf(o));
+                redisTemplate.opsForValue().set(numKey, parsed + 1);
+            }
+            redisTemplate.opsForValue().set(surplusKey, count.decrementAndGet());
+        }
+        long end = System.currentTimeMillis();
+        long useTime = (end-start)/1000;
+        log.info("绾跨▼{}鎶ュ憡瀹℃壒缁撴潫锛岃�楁椂:{}s",keyPrefix,useTime);
+    }
+
+    @Override
+    public Map<String, Object> getBatchApprovalProgress() {
+        Integer userId =  Integer.parseInt(SecurityUtils.getUserId() + "");
+        String key = SYNC_REPORT_KEY_PREFIX + userId;
+        Map<String, Object> map = new HashMap<>();
+        map.put("hasProgress",false);
+        map.put("hasNum",0);
+        map.put("hasCount",0);
+        map.put("surplus",0);
+        Object o = redisTemplate.opsForValue().get(key);
+        if(Objects.nonNull(o)){
+            map.put("hasProgress",true);
+        }
+        Object o1 = redisTemplate.opsForValue().get(key+"_num");
+        Object o2 = redisTemplate.opsForValue().get(key+"_count");
+        Object surplus = redisTemplate.opsForValue().get(key+"_surplus");
+        Object exception = redisTemplate.opsForValue().get(key+"_exception");
+        if(Objects.nonNull(surplus)){
+            map.put("surplus",surplus);
+        }
+        if (Objects.nonNull(o1)&&Objects.nonNull(o2)){
+            //寰楀埌杩涘害
+            BigDecimal multiply = new BigDecimal(String.valueOf(o1)).divide(new BigDecimal(String.valueOf(o2)), 2,BigDecimal.ROUND_DOWN).multiply(BigDecimal.valueOf(100));
+            map.put("hasNum",multiply);
+            map.put("hasCount",Long.parseLong(String.valueOf(o2)));
+        }
+        map.put("hasException",exception);
+        return map;
+    }
+
+    //瑙e帇鏂囦欢澶�
+    private void unzip(File zipFile, File destDir) throws IOException {
+        try (ZipFile zip = new ZipFile(zipFile)) {
+            Enumeration<? extends ZipEntry> entries = zip.entries();
+            while (entries.hasMoreElements()) {
+                ZipEntry entry = entries.nextElement();
+                File file = new File(destDir, entry.getName());
+                if (entry.isDirectory()) {
+                    file.mkdirs();
+                } else {
+                    file.getParentFile().mkdirs();
+                    try (InputStream in = zip.getInputStream(entry);
+                         OutputStream out = new FileOutputStream(file)) {
+                        byte[] buffer = new byte[1024];
+                        int len;
+                        while ((len = in.read(buffer)) > 0) {
+                            out.write(buffer, 0, len);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // 鍘嬬缉鏂囦欢澶�
+    public static void zipDirectory(String sourceDirPath, String zipFilePath) throws IOException {
+        try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFilePath))) {
+            Path sourceDir = Paths.get(sourceDirPath);
+            Files.walk(sourceDir)
+                    .filter(path -> !Files.isDirectory(path))
+                    .forEach(path -> {
+                        ZipEntry zipEntry = new ZipEntry(sourceDir.relativize(path).toString());
+                        try {
+                            zipOut.putNextEntry(zipEntry);
+                            Files.copy(path, zipOut);
+                            zipOut.closeEntry();
+                        } catch (IOException e) {
+                            e.printStackTrace();
+                        }
+                    });
+        }
+    }
+
+    // 鍒犻櫎鏂囦欢澶瑰強鍏跺唴瀹�
+    public static void deleteDirectory(File directory) throws IOException {
+        if (directory.isDirectory()) {
+            File[] files = directory.listFiles();
+            if (files != null) {
+                for (File file : files) {
+                    deleteDirectory(file);
+                }
+            }
+        }
+        Files.delete(directory.toPath());
+    }
+
+    /**
+     * word杞崲pdf
+     * @param path
+     * @return
+     */
+    public String wordToPdfTemp(String path) {
+        try {
+            return wordToPdf(path, path.replace(".docx", ""));
+        } catch (Exception e) {
+            throw new ErrorException("杞崲澶辫触");
+        }
+    }
+
+    public String wordToPdf(String wordPath, String pdfPath) {
+        FileOutputStream os = null;
+        try {
+            //鍑瘉 涓嶇劧鍒囨崲鍚庢湁姘村嵃
+            InputStream is = Files.newInputStream(new File(licenseUrl).toPath());
+            License license = new License();
+            license.setLicense(is);
+            if (!license.getIsLicensed()) {
+                System.out.println("License楠岃瘉涓嶉�氳繃...");
+                return null;
+            }
+            //鐢熸垚涓�涓┖鐨凱DF鏂囦欢
+            File file;
+            //鍒ゆ柇鏄惁鏄繘鍘傛姤鍛�
+            file = File.createTempFile(pdfPath, ".pdf");
+            file.deleteOnExit();
+            os = new FileOutputStream(file);
+            //瑕佽浆鎹㈢殑word鏂囦欢
+            com.aspose.words.Document doc = new com.aspose.words.Document(wordPath);
+            doc.save(os, SaveFormat.PDF);
+            String name = file.getName();
+            return file.getAbsolutePath();
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (os != null) {
+                try {
+                    os.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 鍒囧壊鍥剧墖
+     *
+     * @param Path 鍥剧墖璺緞
+     * @param n    鍒囧壊浠芥暟
+     */
+    public static com.itextpdf.text.Image[] slicingImages(String Path, int n) throws IOException, BadElementException {
+        com.itextpdf.text.Image[] nImage = new com.itextpdf.text.Image[n];
+        BufferedImage img = ImageIO.read(new File(Path));
+
+        int h = img.getHeight();
+        int w = img.getWidth();
+
+        int sw = w / n;
+        for (int i = 0; i < n; i++) {
+            BufferedImage subImg;
+            if (i == n - 1) {//鏈�鍚庡墿浣欓儴鍒�
+                subImg = img.getSubimage(i * sw, 0, w - i * sw, h);
+            } else {//鍓峮-1鍧楀潎鍖�鍒�
+                subImg = img.getSubimage(i * sw, 0, sw, h);
+            }
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            ImageIO.write(subImg, Path.substring(Path.lastIndexOf('.') + 1), out);
+            nImage[i] = com.itextpdf.text.Image.getInstance(out.toByteArray());
+
+        }
+        return nImage;
+    }
+
+    /**
+     * 鐩栭獞缂濈珷
+     *
+     * @param infilePath  鍘烶DF璺緞
+     * @param outFilePath 杈撳嚭PDF璺緞
+     */
+    public static void stamperCheckMarkPDF(String infilePath, String outFilePath, String picPath) throws IOException, DocumentException {
+        PdfReader reader = new PdfReader(infilePath);//閫夋嫨闇�瑕佸嵃绔犵殑pdf
+        PdfStamper stamp = new PdfStamper(reader, new FileOutputStream(outFilePath));//鍔犲畬鍗扮珷鍚庣殑pdf
+
+
+        com.itextpdf.text.Rectangle pageSize = reader.getPageSize(1);//鑾峰緱绗竴椤�
+        float height = pageSize.getHeight();
+        float width = pageSize.getWidth();
+
+        int nums = reader.getNumberOfPages();
+        com.itextpdf.text.Image[] nImage = slicingImages(picPath, nums);//鐢熸垚楠戠紳绔犲垏鍓插浘鐗�
+
+        for (int n = 1; n <= nums; n++) {
+            PdfContentByte over = stamp.getOverContent(n);//璁剧疆鍦ㄧ鍑犻〉鎵撳嵃鍗扮珷
+            com.itextpdf.text.Image img = nImage[n - 1];//閫夋嫨鍥剧墖
+            float newHeight = 100f;
+            float newWidth = img.getWidth() / (img.getHeight() / 100);
+            img.scaleAbsolute(newWidth, newHeight);//鎺у埗鍥剧墖澶у皬
+            img.setAbsolutePosition(width - newWidth, height / 2 - newHeight / 2);//鎺у埗鍥剧墖浣嶇疆
+            over.addImage(img);
+        }
+        stamp.close();
+    }
+}
diff --git a/performance-server/src/main/resources/mapper/PerformanceShiftMapper.xml b/performance-server/src/main/resources/mapper/PerformanceShiftMapper.xml
index c8ff49e..55779b3 100644
--- a/performance-server/src/main/resources/mapper/PerformanceShiftMapper.xml
+++ b/performance-server/src/main/resources/mapper/PerformanceShiftMapper.xml
@@ -110,8 +110,9 @@
 
     <select id="performanceShiftList" resultMap="performanceShiftPageMap">
         SELECT
-        if(u.department is not null and u.department != '', CONCAT(u.name, '锛�', u.department, '锛�'), u.name) name,
-        GROUP_CONCAT(s.work_time, '锛�', s.shift, '锛�', s.id order by s.work_time SEPARATOR ';') AS shift_time, u.id user_id, u.department
+        <!--if(u.department is not null and u.department != '', CONCAT(u.name, '锛�', u.department, '锛�'), u.name) name,-->
+            u.name name,
+        GROUP_CONCAT(s.work_time, '锛�', s.shift, '锛�', s.id order by s.work_time SEPARATOR ';') AS shift_time, u.id user_id, u.dept_id
         FROM performance_shift s
         LEFT JOIN user u on u.id = s.user_id
         <where>
@@ -124,8 +125,8 @@
             <if test="laboratory != null and laboratory != ''">
             </if>
         </where>
-        order by s.create_time
         GROUP BY u.id
+        order by s.create_time
     </select>
 
     <select id="seldepLimsId" resultType="java.lang.String">
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/config/MinioConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/MinioConfig.java
index 28f489f..a573ff6 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/config/MinioConfig.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/MinioConfig.java
@@ -17,6 +17,7 @@
     private String accessKey;
     private String secretKey;
     private Boolean secure;
+    private String bucketName;
 
     @Bean
     public MinioClient getMinioClient() {
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/controller/AttachmentTypeController.java b/ruoyi-common/src/main/java/com/ruoyi/common/controller/AttachmentTypeController.java
new file mode 100644
index 0000000..b321181
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/controller/AttachmentTypeController.java
@@ -0,0 +1,74 @@
+package com.ruoyi.common.controller;
+
+import com.ruoyi.common.core.domain.Result;
+import com.ruoyi.common.service.AttachmentTableService;
+import lombok.AllArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+
+@RestController
+@RequestMapping("/file/attachmentType")
+@AllArgsConstructor
+public class AttachmentTypeController {
+
+    private AttachmentTableService attachmentTableService;
+
+    /**
+     * 涓婁紶鏂囦欢
+     * @param file 鏂囦欢
+     * @param type 鏋氫妇绫诲瀷
+     * @param id 涓氬姟id
+     * @return
+     */
+    @PostMapping("/upload")
+    public Result upload(@RequestParam("file")MultipartFile file,@RequestParam("type")Integer type,@RequestParam("id")Integer id) {
+        attachmentTableService.upload(file,type,id);
+        return Result.success();
+    }
+
+    /**
+     * 涓嬭浇鏂囦欢
+     * @param id 涓氬姟id
+     * @param type 鏋氫妇绫诲瀷
+     * @param code 鏂囦欢鍚嶇О
+     * @param suffix 鏂囦欢鍚庣紑 鍙兘鏄痺ord 鎴栬�� pdf
+     * @return
+     */
+    @GetMapping("/downLoad")
+    public void downLoad(Integer id, Integer type , String code,String suffix, HttpServletResponse response)   {
+        attachmentTableService.downLoad(id, type,code, suffix,response);
+    }
+
+    /**
+     * 鑾峰彇鏂囦欢鐨凪IME
+     * @param id
+     * @param type
+     * @return
+     */
+    @GetMapping("/getMIME")
+    public Result getMIME(Integer id, Integer type,String suffix) {
+        return Result.success(attachmentTableService.getAttachmentList(id, type,suffix));
+    }
+
+
+    /**
+     * 鑾峰彇鏂囦欢URL
+     * @param id
+     * @param type
+     * @param suffix 鏂囦欢鍚庣紑  鍙兘鏄痺ord 鍜� pdf
+     */
+    @GetMapping("/getURL")
+    public Result getURL(Integer id, Integer type  , String suffix) {
+        return Result.success(attachmentTableService.getURL(id, type , suffix));
+    }
+
+
+
+
+
+
+
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/AttachmentType.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/AttachmentType.java
new file mode 100644
index 0000000..0620f96
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/AttachmentType.java
@@ -0,0 +1,53 @@
+package com.ruoyi.common.enums;
+
+
+public enum AttachmentType {
+    /*
+    * 鎶ュ憡缂栧埗
+     */
+    INS_REPORT(1, "ins_report"),
+    USER(2, "user"),
+
+
+    ;
+
+
+    private Integer type;
+
+    private String value;
+
+
+    private AttachmentType(Integer type, String value) {
+        this.type = type;
+        this.value = value;
+    }
+
+    public Integer getType() {
+        return type;
+    }
+
+    public void setType(Integer type) {
+        this.type = type;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+
+    public static String getAttachmentValue(Integer type) {
+        for (AttachmentType attachmentType : AttachmentType.values()) {
+            if (attachmentType.getType().equals(type)) {
+                return attachmentType.getValue();
+            }
+        }
+        return null;
+    }
+
+
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/mapper/AttachmentTableMapper.java b/ruoyi-common/src/main/java/com/ruoyi/common/mapper/AttachmentTableMapper.java
new file mode 100644
index 0000000..b325705
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/mapper/AttachmentTableMapper.java
@@ -0,0 +1,10 @@
+package com.ruoyi.common.mapper;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.common.pojo.AttachmentTable;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface AttachmentTableMapper  extends BaseMapper<AttachmentTable> {
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/pojo/AttachmentTable.java b/ruoyi-common/src/main/java/com/ruoyi/common/pojo/AttachmentTable.java
new file mode 100644
index 0000000..577c6cb
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/pojo/AttachmentTable.java
@@ -0,0 +1,36 @@
+package com.ruoyi.common.pojo;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@TableName("attachment_table")
+public class AttachmentTable {
+
+    @TableId(type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty("鍏朵粬琛ㄧ粦瀹歩d")
+    private Integer subclassId;
+
+    @ApiModelProperty("鏂囦欢鍚嶇О")
+    private String fileName;
+
+    @ApiModelProperty("鏂囦欢绫诲瀷")
+    private String fileType;
+
+    @ApiModelProperty("鏂囦欢鍘熷悕绉�")
+    private String originalFileName;
+
+    @ApiModelProperty("妗跺悕")
+    private String bucketName;
+
+    @ApiModelProperty("鎵�鍦ㄦā鍧楀悕绉�")
+    private String moduleName;
+
+    @ApiModelProperty("鍏朵粬琛ㄥ悕")
+    private String otherTableName;
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/service/AttachmentTableService.java b/ruoyi-common/src/main/java/com/ruoyi/common/service/AttachmentTableService.java
new file mode 100644
index 0000000..85e0097
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/service/AttachmentTableService.java
@@ -0,0 +1,23 @@
+package com.ruoyi.common.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.common.pojo.AttachmentTable;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.InputStream;
+import java.util.Map;
+
+public interface AttachmentTableService extends IService<AttachmentTable> {
+
+    void upload(MultipartFile file, Integer type, Integer id);
+
+   void downLoad(Integer id, Integer type,String code,String suffix,HttpServletResponse response)  ;
+
+   Map<String, Object> getAttachmentList(Integer id, Integer type,String suffix);
+
+   String getURL(Integer id, Integer type  , String suffix);
+
+    InputStream getInputStream(Integer id, Integer type  , String suffix);
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/service/impl/AttachmentTableServiceImpl.java b/ruoyi-common/src/main/java/com/ruoyi/common/service/impl/AttachmentTableServiceImpl.java
new file mode 100644
index 0000000..281cffc
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/service/impl/AttachmentTableServiceImpl.java
@@ -0,0 +1,218 @@
+package com.ruoyi.common.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.config.MinioConfig;
+import com.ruoyi.common.enums.AttachmentType;
+import com.ruoyi.common.mapper.AttachmentTableMapper;
+import com.ruoyi.common.pojo.AttachmentTable;
+import com.ruoyi.common.service.AttachmentTableService;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.uuid.UUID;
+import io.minio.*;
+import io.minio.http.Method;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+@Service
+@AllArgsConstructor
+public class AttachmentTableServiceImpl  extends ServiceImpl<AttachmentTableMapper, AttachmentTable> implements AttachmentTableService {
+
+    private MinioConfig minioConfig;
+
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void upload(MultipartFile file, Integer type, Integer id) {
+        MinioClient build = MinioClient.builder()
+                .endpoint(minioConfig.getEndpoint(), minioConfig.getPort(), minioConfig.getSecure())
+                .credentials(minioConfig.getAccessKey(), minioConfig.getSecretKey())
+                .build();
+        String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename();
+        try(InputStream inputStream = file.getInputStream()) {
+            build.putObject(
+                    PutObjectArgs.builder()
+                            .bucket(minioConfig.getBucketName())
+                            .object(fileName)
+                            .stream(inputStream, file.getSize(), -1)
+                            .contentType("application/octet-stream")
+                            .userMetadata(Collections.singletonMap("Content-Disposition", "attachment; filename=\"" + fileName + "\""))
+                            .build()
+            );
+            // 淇濆瓨鍒版暟鎹簱
+            AttachmentTable attachmentTable = new AttachmentTable();
+            attachmentTable.setSubclassId(id);
+            attachmentTable.setFileName(fileName);
+            attachmentTable.setOriginalFileName(file.getOriginalFilename());
+            attachmentTable.setFileType(file.getContentType());
+            attachmentTable.setBucketName(minioConfig.getBucketName());
+            attachmentTable.setOtherTableName(AttachmentType.getAttachmentValue(type));
+            baseMapper.insert(attachmentTable);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void downLoad(Integer id, Integer type,String code,String suffix, HttpServletResponse response)   {
+        // 鏌ヨ鏁版嵁搴�
+        List<AttachmentTable> list = baseMapper.selectList(new LambdaQueryWrapper<AttachmentTable>()
+                .eq(AttachmentTable::getSubclassId, id)
+                .eq(AttachmentTable::getOtherTableName, AttachmentType.getAttachmentValue(type))
+                .like(AttachmentTable::getFileName, suffix)
+                .orderByDesc(AttachmentTable::getId));
+        if(CollectionUtils.isNotEmpty(list)) {
+            AttachmentTable attachmentTable = list.get(0);
+            String fileName = attachmentTable.getFileName(); // 鏂囦欢鍚�
+            MinioClient build = MinioClient.builder()
+                    .endpoint(minioConfig.getEndpoint(), minioConfig.getPort(), minioConfig.getSecure())
+                    .credentials(minioConfig.getAccessKey(), minioConfig.getSecretKey())
+                    .build();
+            try( InputStream inputStream = build.getObject(GetObjectArgs.builder().bucket(minioConfig.getBucketName()).object(fileName).build());
+                 ServletOutputStream stream = response.getOutputStream()) {
+                String finalName = "";
+                String fileNameMinIo = attachmentTable.getFileName();
+                String suffix1 = fileNameMinIo.substring(fileNameMinIo.lastIndexOf(".")+1);
+                String contentType = getContentType(suffix1);
+                if(StringUtils.isNotEmpty(code)) {
+                    finalName = code + "." + suffix1;
+                }else {
+                    finalName = fileNameMinIo;
+                }
+                // 璁剧疆鍝嶅簲澶�
+                response.setContentType(contentType);
+                response.setHeader("Content-disposition", "attachment;filename=" + finalName);
+                byte[] bytes = new byte[1024];
+                int len;
+                while ((len = inputStream.read(bytes)) != -1) {
+                    stream.write(bytes, 0, len);
+                    stream.flush();
+                }
+            }catch (Exception e) {
+                e.printStackTrace();
+            }
+
+
+        }
+    }
+
+    @Override
+    public Map<String, Object> getAttachmentList(Integer id, Integer type,String suffix) {
+        HashMap<String, Object> map = new HashMap<>();
+        // 鏌ヨ鏁版嵁搴�
+        List<AttachmentTable> list = baseMapper.selectList(new LambdaQueryWrapper<AttachmentTable>()
+                .eq(AttachmentTable::getSubclassId, id)
+                .eq(AttachmentTable::getOtherTableName, AttachmentType.getAttachmentValue(type))
+                .like(StringUtils.isNotEmpty(suffix),AttachmentTable::getFileName, suffix)
+                .orderByDesc(AttachmentTable::getId));
+        if(CollectionUtils.isNotEmpty(list)) {
+            String contentType = getContentType(suffix.replace(".",""));
+            map.put("contentType", contentType);
+            map.put("suffix", suffix);
+        }
+        return map;
+    }
+
+    @Override
+    public String getURL(Integer id, Integer type , String suffix) {
+        String url = "";
+        // 鏌ヨ鏁版嵁搴� 鑾峰彇鏈�鏂版枃浠跺悕
+        List<AttachmentTable> attachmentTables = baseMapper.selectList(new LambdaQueryWrapper<AttachmentTable>()
+                .eq(AttachmentTable::getSubclassId, id)
+                .eq(AttachmentTable::getOtherTableName, AttachmentType.getAttachmentValue(type))
+                .like(AttachmentTable::getFileName, suffix)
+                .orderByDesc(AttachmentTable::getId));
+        if(CollectionUtils.isNotEmpty(attachmentTables)) {
+            AttachmentTable attachmentTable = attachmentTables.get(0);
+            MinioClient build = MinioClient.builder()
+                    .endpoint(minioConfig.getEndpoint(), minioConfig.getPort(), minioConfig.getSecure())
+                    .credentials(minioConfig.getAccessKey(), minioConfig.getSecretKey())
+                    .build();
+            try {
+                 url = build.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
+                        .method(Method.GET)
+                        .bucket(minioConfig.getBucketName())
+                        .object(attachmentTable.getFileName())
+                        .expiry(60 * 60 * 24)
+                        .build());
+
+            }  catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+
+        }
+        return url;
+    }
+
+    public InputStream  getInputStream(Integer id, Integer type , String suffix) {
+        InputStream inputStream = null;
+        // 鏌ヨ鏁版嵁搴� 鑾峰彇鏈�鏂版枃浠跺悕
+        List<AttachmentTable> attachmentTables = baseMapper.selectList(new LambdaQueryWrapper<AttachmentTable>()
+                .eq(AttachmentTable::getSubclassId, id)
+                .eq(AttachmentTable::getOtherTableName, AttachmentType.getAttachmentValue(type))
+                .like(StringUtils.isNotEmpty(suffix),AttachmentTable::getFileName, suffix)
+                .orderByDesc(AttachmentTable::getId));
+        if(CollectionUtils.isNotEmpty(attachmentTables)) {
+            AttachmentTable attachmentTable = attachmentTables.get(0);
+            MinioClient build = MinioClient.builder()
+                    .endpoint(minioConfig.getEndpoint(), minioConfig.getPort(), minioConfig.getSecure())
+                    .credentials(minioConfig.getAccessKey(), minioConfig.getSecretKey())
+                    .build();
+            try {
+                inputStream  = build.getObject(
+                        GetObjectArgs.builder()
+                                .bucket(minioConfig.getBucketName())
+                                .object(attachmentTable.getFileName())
+                                .build());
+
+            }  catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return inputStream;
+    }
+
+
+
+
+    // 鏍规嵁鏂囦欢鎵╁睍鍚嶈幏鍙� MIME 绫诲瀷
+    private String getContentType(String fileExtension) {
+        switch (fileExtension) {
+            case "jpg":
+            case "jpeg":
+                return "image/jpeg";
+            case "png":
+                return "image/png";
+            case "gif":
+                return "image/gif";
+            case "pdf":
+                return "application/pdf";
+            case "doc":
+                return "application/msword";
+            case "docx":
+                return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
+            case "xls":
+                return "application/vnd.ms-excel";
+            case "xlsx":
+                return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
+            case "ppt":
+            case "pptx":
+                return "application/vnd.ms-powerpoint";
+            default:
+                return "application/octet-stream"; // 榛樿浜岃繘鍒舵祦
+        }
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/UserMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/UserMapper.java
index 157d946..ad464ef 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/UserMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/UserMapper.java
@@ -47,5 +47,8 @@
     User getUserNow(@Param("userId") int userId);
 
     SysUserVO selectUserInfo(Long userId);
+    String seldepLimsId(int depLimsId);
+
+    List<Map<String, Object>> getPersonList(String laboratory);
 }
 
diff --git a/ruoyi-system/src/main/resources/mapper/system/UserMapper.xml b/ruoyi-system/src/main/resources/mapper/system/UserMapper.xml
index f05881a..3eb9d91 100644
--- a/ruoyi-system/src/main/resources/mapper/system/UserMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/UserMapper.xml
@@ -63,4 +63,28 @@
     <select id="selectUserInfo" resultType="com.ruoyi.common.core.vo.SysUserVO">
         select * from user
     </select>
+    <select id="seldepLimsId" resultType="java.lang.String">
+        select name
+        from department_lims
+        where id = #{depLimsId}
+    </select>
+    <select id="getPersonList" resultType="java.util.Map">
+        select
+        u.id,
+        u.name,
+        dl.name as depName
+        from
+        user u
+        left join
+        department_lims dl
+        on
+        FIND_IN_SET(dl.id,u.depart_lims_id)
+        where
+        dl.name in('閫氫俊浜у搧瀹為獙瀹�','鐢靛姏浜у搧瀹為獙瀹�','妫�娴嬪姙')
+        and u.status = 1
+        and u.is_custom = 0
+        <if test="laboratory!='' and laboratory!=null">
+            and (dl.name = #{laboratory} or dl.name='妫�娴嬪姙')
+        </if>
+    </select>
 </mapper>

--
Gitblit v1.9.3