Преглед на файлове

Merge remote-tracking branch 'origin/master' into master

yangyj преди 1 година
родител
ревизия
72d94db1d6
променени са 18 файла, в които са добавени 879 реда и са изтрити 289 реда
  1. 3 1
      blade-ops-api/blade-flow-api/src/main/java/org/springblade/flow/core/feign/NewFlowClient.java
  2. 16 0
      blade-ops-api/blade-flow-api/src/main/java/org/springblade/flow/core/vo/SendPageVO.java
  3. 5 4
      blade-ops/blade-flow/src/main/java/org/springblade/flow/business/feign/NewFlowClientImpl.java
  4. 1 1
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchivesAutoServiceImpl.java
  5. 62 62
      blade-service/blade-business/src/main/java/org/springblade/business/controller/ImageClassificationFileController.java
  6. 11 3
      blade-service/blade-business/src/main/java/org/springblade/business/controller/TaskController.java
  7. 6 2
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/ImageClassificationFileMapper.xml
  8. 1 1
      blade-service/blade-business/src/main/java/org/springblade/business/utils/FileUtils.java
  9. 3 3
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ArchiveTreeContractController.java
  10. 104 47
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java
  11. 89 16
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreeContractController.java
  12. 10 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/feign/ProjectAssignmentUserClientImpl.java
  13. 2 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreeContractMapper.xml
  14. 1 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IWbsTreeContractService.java
  15. 12 2
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ArchiveTreeContractSyncImpl.java
  16. 2 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ExcelTabServiceImpl.java
  17. 150 144
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeContractServiceImpl.java
  18. 401 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/utils/ExcelInfoUtils.java

+ 3 - 1
blade-ops-api/blade-flow-api/src/main/java/org/springblade/flow/core/feign/NewFlowClient.java

@@ -4,9 +4,11 @@ import org.springblade.core.launch.constant.AppConstant;
 import org.springblade.core.mp.support.Query;
 import org.springblade.core.tool.api.R;
 import org.springblade.flow.core.vo.FlowProcessVO;
+import org.springblade.flow.core.vo.SendPageVO;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestParam;
 
 import java.util.List;
@@ -30,7 +32,7 @@ public interface NewFlowClient {
      * 获取已发起
      */
     @PostMapping(SEND_LIST)
-    R<Object> selectSendPage(@RequestParam Integer current, @RequestParam Integer size, @RequestParam Integer ordType, @RequestParam String parallelProcessInstanceIds);
+    R<Object> selectSendPage(@RequestBody SendPageVO vo);
 
     /**
      * 获取待办

+ 16 - 0
blade-ops-api/blade-flow-api/src/main/java/org/springblade/flow/core/vo/SendPageVO.java

@@ -0,0 +1,16 @@
+package org.springblade.flow.core.vo;
+
+import lombok.Data;
+
+/**
+ * @Param
+ * @Author wangwl
+ * @Date 2023/8/30 14:44
+ **/
+@Data
+public class SendPageVO {
+    private Integer current;
+    private Integer size;
+    private Integer ordType;
+    private String parallelProcessInstanceIds;
+}

+ 5 - 4
blade-ops/blade-flow/src/main/java/org/springblade/flow/business/feign/NewFlowClientImpl.java

@@ -15,6 +15,7 @@ import org.springblade.flow.business.service.FlowBusinessService;
 import org.springblade.flow.core.entity.BladeFlow;
 import org.springblade.flow.core.feign.NewFlowClient;
 import org.springblade.flow.core.vo.FlowProcessVO;
+import org.springblade.flow.core.vo.SendPageVO;
 import org.springblade.flow.engine.entity.FlowProcess;
 import org.springblade.flow.engine.service.FlowEngineService;
 import org.springframework.web.bind.annotation.RestController;
@@ -33,11 +34,11 @@ public class NewFlowClientImpl implements NewFlowClient {
     private final TaskService taskService;
 
     @Override
-    public R<Object> selectSendPage(Integer current, Integer size, Integer ordType, String parallelProcessInstanceIds) {
+    public R<Object> selectSendPage(SendPageVO vo) {
         Query query = new Query();
-        query.setCurrent(current);
-        query.setSize(size);
-        return R.data(this.flowBusinessService.selectSendPage(Condition.getPage(query), ordType, new BladeFlow(), parallelProcessInstanceIds));
+        query.setCurrent(vo.getCurrent());
+        query.setSize(vo.getSize());
+        return R.data(this.flowBusinessService.selectSendPage(Condition.getPage(query), vo.getOrdType(), new BladeFlow(), vo.getParallelProcessInstanceIds()));
     }
 
     @Override

+ 1 - 1
blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchivesAutoServiceImpl.java

@@ -461,7 +461,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		Iterator<ArchivesAutoVO> iterator = pageVoList.iterator();
 		while (iterator.hasNext()) {
 			ArchivesAutoVO autoVO = iterator.next();
-			if (autoVO.getFileN() == 0) {
+			if (autoVO.getFileN() != null && autoVO.getFileN() == 0) {
 				iterator.remove();
 			}
 		}

+ 62 - 62
blade-service/blade-business/src/main/java/org/springblade/business/controller/ImageClassificationFileController.java

@@ -188,72 +188,72 @@ public class ImageClassificationFileController extends BladeController {
                                 try {
                                     //创建模板Workbook
                                     modInput = CommonUtil.getOSSInputStream(excelTab.getFileUrl());
-                                    workbook = WorkbookFactory.create(modInput);
-
-                                    for (int i = 0, l = urls.size(); i < l; i++) {
-                                        try {
-                                            CreationHelper helper = workbook.getCreationHelper();
-                                            Sheet sheet = workbook.getSheetAt(0);
-                                            Drawing<?> drawing = sheet.createDrawingPatriarch();
-                                            ClientAnchor anchor = helper.createClientAnchor();
-
-                                            if (i == 0) {
-                                                anchor.setRow1(0);
-                                                anchor.setCol1(0);
-                                            } else {
-                                                anchor.setRow1(28);
-                                                anchor.setCol1(1);
+                                    if (modInput != null) {
+                                        workbook = WorkbookFactory.create(modInput);
+                                        for (int i = 0, l = urls.size(); i < l; i++) {
+                                            try {
+                                                CreationHelper helper = workbook.getCreationHelper();
+                                                Sheet sheet = workbook.getSheetAt(0);
+                                                Drawing<?> drawing = sheet.createDrawingPatriarch();
+                                                ClientAnchor anchor = helper.createClientAnchor();
+
+                                                if (i == 0) {
+                                                    anchor.setRow1(0);
+                                                    anchor.setCol1(0);
+                                                } else {
+                                                    anchor.setRow1(28);
+                                                    anchor.setCol1(1);
+                                                }
+
+                                                //获取文件流
+                                                byte[] bytes = CommonUtil.InputStreamToBytes(CommonUtil.getOSSInputStream(urls.get(i)));
+
+                                                //压缩文件大小
+                                                byte[] byteNew = FileUtils.compressImage(bytes);
+
+                                                //创建图片
+                                                Picture picture = drawing.createPicture(anchor, workbook.addPicture(byteNew, Workbook.PICTURE_TYPE_PNG));
+                                                picture.resize();
+
+                                                //图片定位
+                                                FileUtils.imageOrientation(sheet, anchor, i == 1 ? new DataVO(1, 28) : new DataVO(0, 0));
+
+                                                //定位其它信息
+                                                //文字说明
+                                                sheet.getRow(i == 0 ? 1 : 29).getCell(i == 0 ? 5 : 0).setCellValue(file.getTextContent());
+                                                //照片号
+                                                sheet.getRow(i == 0 ? 11 : 39).getCell(i == 0 ? 5 : 0).setCellValue(file.getPhotoCode());
+                                                //底片号
+                                                sheet.getRow(i == 0 ? 17 : 45).getCell(i == 0 ? 5 : 0).setCellValue(file.getFilmCode());
+                                                //题名
+                                                sheet.getRow(i == 0 ? 23 : 51).getCell(i == 0 ? 0 : 3).setCellValue(file.getTitle());
+                                                //参见号
+                                                sheet.getRow(i == 0 ? 23 : 51).getCell(i == 0 ? 3 : 0).setCellValue(file.getSeeAlsoCode());
+                                                //拍摄时间
+                                                sheet.getRow(i == 0 ? 25 : 53).getCell(i == 0 ? 3 : 0).setCellValue(DateUtil.format(file.getShootingTime(), "yyyy-MM-dd"));
+                                                //拍摄者
+                                                sheet.getRow(i == 0 ? 27 : 55).getCell(i == 0 ? 3 : 0).setCellValue(file.getShootingUser());
+
+                                            } catch (Exception e) {
+                                                e.printStackTrace();
                                             }
-
-                                            //获取文件流
-                                            byte[] bytes = CommonUtil.InputStreamToBytes(CommonUtil.getOSSInputStream(urls.get(i)));
-
-                                            //压缩文件大小
-                                            byte[] byteNew = FileUtils.compressImage(bytes);
-
-                                            //创建图片
-                                            Picture picture = drawing.createPicture(anchor, workbook.addPicture(byteNew, Workbook.PICTURE_TYPE_PNG));
-                                            picture.resize();
-
-                                            //图片定位
-                                            FileUtils.imageOrientation(sheet, anchor, i == 1 ? new DataVO(1, 28) : new DataVO(0, 0));
-
-                                            //定位其它信息
-                                            //文字说明
-                                            sheet.getRow(i == 0 ? 1 : 29).getCell(i == 0 ? 5 : 0).setCellValue(file.getTextContent());
-                                            //照片号
-                                            sheet.getRow(i == 0 ? 11 : 39).getCell(i == 0 ? 5 : 0).setCellValue(file.getPhotoCode());
-                                            //底片号
-                                            sheet.getRow(i == 0 ? 17 : 45).getCell(i == 0 ? 5 : 0).setCellValue(file.getFilmCode());
-                                            //题名
-                                            sheet.getRow(i == 0 ? 23 : 51).getCell(i == 0 ? 0 : 3).setCellValue(file.getTitle());
-                                            //参见号
-                                            sheet.getRow(i == 0 ? 23 : 51).getCell(i == 0 ? 3 : 0).setCellValue(file.getSeeAlsoCode());
-                                            //拍摄时间
-                                            sheet.getRow(i == 0 ? 25 : 53).getCell(i == 0 ? 3 : 0).setCellValue(DateUtil.format(file.getShootingTime(), "yyyy-MM-dd"));
-                                            //拍摄者
-                                            sheet.getRow(i == 0 ? 27 : 55).getCell(i == 0 ? 3 : 0).setCellValue(file.getShootingUser());
-
-                                        } catch (Exception e) {
-                                            e.printStackTrace();
                                         }
-                                    }
 
-                                    String locationFile = file_path + SnowFlakeUtil.getId() + ".xlsx";
-                                    outputStream = new FileOutputStream(locationFile);
-                                    //记录文件删除
-                                    removeList.add(locationFile);
-                                    //生成一份新的excel
-                                    workbook.write(outputStream);
-                                    //将excel转PDF
-                                    File excelFile = new File(locationFile);
-                                    excelFileInput = new FileInputStream(excelFile);
-                                    MultipartFile files = new MockMultipartFile("file", excelFile.getName(), "text/plain", IOUtils.toByteArray(excelFileInput));
-                                    NewBladeFile bladeFile = this.commonFileClient.excelToPdf(files);
-                                    if (bladeFile != null) {
-                                        pdfFileList.add(bladeFile.getPdfUrl());
+                                        String locationFile = file_path + SnowFlakeUtil.getId() + ".xlsx";
+                                        outputStream = new FileOutputStream(locationFile);
+                                        //记录文件删除
+                                        removeList.add(locationFile);
+                                        //生成一份新的excel
+                                        workbook.write(outputStream);
+                                        //将excel转PDF
+                                        File excelFile = new File(locationFile);
+                                        excelFileInput = new FileInputStream(excelFile);
+                                        MultipartFile files = new MockMultipartFile("file", excelFile.getName(), "text/plain", IOUtils.toByteArray(excelFileInput));
+                                        NewBladeFile bladeFile = this.commonFileClient.excelToPdf(files);
+                                        if (bladeFile != null) {
+                                            pdfFileList.add(bladeFile.getPdfUrl());
+                                        }
                                     }
-
                                 } catch (Exception e) {
                                     e.printStackTrace();
                                 } finally {

+ 11 - 3
blade-service/blade-business/src/main/java/org/springblade/business/controller/TaskController.java

@@ -32,6 +32,7 @@ import org.springblade.core.tool.utils.Func;
 import org.springblade.core.tool.utils.ObjectUtil;
 import org.springblade.flow.core.entity.BladeFlow;
 import org.springblade.flow.core.feign.NewFlowClient;
+import org.springblade.flow.core.vo.SendPageVO;
 import org.springblade.manager.entity.ContractInfo;
 import org.springblade.manager.feign.ContractClient;
 import org.springblade.resource.feign.CommonFileClient;
@@ -220,8 +221,12 @@ public class TaskController extends BladeController {
             //设置主表map,方便获取
             Map<String, Task> masterTaskMap = new HashMap<>();
             masterTaskList.forEach(task -> masterTaskMap.put(task.getProcessInstanceId(), task));
-
-            R<Object> rObject = this.newFlowClient.selectSendPage(queryVO.getCurrent(), queryVO.getSize(), queryVO.getOrdType() == null ? 1 : queryVO.getOrdType(), String.join(",", processInstanceIds));
+            SendPageVO pageVO = new SendPageVO();
+            pageVO.setCurrent(queryVO.getCurrent());
+            pageVO.setSize(queryVO.getSize());
+            pageVO.setOrdType(queryVO.getOrdType() == null ? 1 : queryVO.getOrdType());
+            pageVO.setParallelProcessInstanceIds(String.join(",", processInstanceIds));
+            R<Object> rObject = this.newFlowClient.selectSendPage(pageVO);
             if (rObject.isSuccess()) {
                 Query query = new Query();
                 query.setCurrent(queryVO.getCurrent());
@@ -404,6 +409,9 @@ public class TaskController extends BladeController {
         List<String> parallelProcessInstanceIds = new ArrayList<>();
         //统合查询方法
         this.integrationMethod(queryVO, masterTaskMap, parallelMap, parallelProcessInstanceIds, "2,3");
+        if (masterTaskMap.size() == 0 || parallelMap.size() == 0) {
+            return R.data(null);
+        }
 
         //获取已办(基于原生已办)
         R<Object> rObject = this.newFlowClient.selectDonePage(queryVO.getCurrent(), queryVO.getSize(), queryVO.getOrdType() == null ? 1 : queryVO.getOrdType(), String.join(",", parallelProcessInstanceIds));
@@ -449,7 +457,7 @@ public class TaskController extends BladeController {
         List<String> parallelProcessInstanceIds = new ArrayList<>();
         //统合查询方法
         this.integrationMethod(queryVO, masterTaskMap, parallelMap, parallelProcessInstanceIds, "1");
-        if (masterTaskMap.size() == 0) {
+        if (masterTaskMap.size() == 0 || parallelMap.size() == 0) {
             return R.data(null);
         }
         //获取待办(基于原生待办)

+ 6 - 2
blade-service/blade-business/src/main/java/org/springblade/business/mapper/ImageClassificationFileMapper.xml

@@ -44,11 +44,15 @@
     </select>
 
     <select id="queryCurrentClassifyAllFileCount" resultType="java.lang.Integer">
-        select count(id) from u_image_classification_file where is_deleted = 0 and classify_id = #{classifyId} and
-        contract_id = #{contractId}
+        select count(id) from u_image_classification_file a
+        where is_deleted = 0
+          and status = 1
+          and classify_id = #{classifyId}
+          and contract_id = #{contractId}
         <if test="projectId != null and projectId != ''">
             and project_id = #{projectId}
         </if>
+            and a.wbs_id in (select p_key_id from m_wbs_tree_contract where is_deleted = 0 and status = 1 and contract_id = #{contractId})
     </select>
 
     <select id="selectShootingTimeByClassifyAndProjectId" resultType="java.util.Date">

+ 1 - 1
blade-service/blade-business/src/main/java/org/springblade/business/utils/FileUtils.java

@@ -209,7 +209,7 @@ public class FileUtils {
      */
     public static void imageOrientation(Sheet sheet, ClientAnchor anchor, DataVO dataVO) {
         // 设置图片距左边和上边的偏移量
-        anchor.setDx1(Units.pixelToEMU(-90));
+        anchor.setDx1(Units.pixelToEMU(5));
         anchor.setDy1(Units.pixelToEMU(5));
         // 设置图片右下角所在单元格的行列号与左上角一致
         anchor.setCol2(anchor.getCol1());

+ 3 - 3
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ArchiveTreeContractController.java

@@ -400,12 +400,12 @@ public class ArchiveTreeContractController extends BladeController {
     }
 
     @PostMapping("syncBusinessData")
-    @ApiOperation(value = "同步业务数据", notes = "传入节点id")
+    @ApiOperation(value = "同步合同段文件", notes = "传入节点id")
     public R syncBusinessData(Long projectId,Long contractId) {
         ContractInfo contract = contractInfoService.getById(contractId);
 
         Integer isArchivesAuto = contract.getIsArchivesAuto();
-        if(isArchivesAuto!=-1 && isArchivesAuto!=null && isArchivesAuto!=0){
+        if(isArchivesAuto!=null && isArchivesAuto!=0){
             return R.fail("当前合同段已经在同步中,请耐心等待");
         }
         log.info("开始自动组卷...." + contractId);
@@ -413,7 +413,7 @@ public class ArchiveTreeContractController extends BladeController {
         contractInfoService.updateIsArchivesAutoById(contractId,1);
 
         archiveTreeContractSync.syncBusinessDataThread(projectId,contractId);
-        return R.success("开始同步合同段,请耐心等待" );
+        return R.success("同步合同段文件完成" );
     }
 
     @PostMapping("test1")

+ 104 - 47
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java

@@ -48,6 +48,7 @@ import org.springblade.manager.enums.ExecuteType;
 import org.springblade.manager.mapper.ExcelTabMapper;
 import org.springblade.manager.mapper.WbsTreePrivateMapper;
 import org.springblade.manager.service.*;
+import org.springblade.manager.utils.ExcelInfoUtils;
 import org.springblade.manager.utils.FileUtils;
 import org.springblade.manager.utils.RegularExpressionUtil;
 import org.springblade.manager.utils.WbsElementUtil;
@@ -294,13 +295,18 @@ public class ExcelTabController extends BladeController {
         String filecode = SnowFlakeUtil.getId() + "";
         String thmlUrl = file_path + filecode + ".html";
         String exceUrl = file_path + filecode + "123.xlsx";
-
-
-       // FileUtils.excelInfo(file.getInputStream(),exceUrl,thmlUrl,"1");
+        //ExcelInfoUtils.excelInfo(file.getInputStream(),exceUrl,thmlUrl,"1");
         // 上传excel文件
-        BladeFile bladeFile = newIOSSClient.uploadFile(file.getOriginalFilename(),exceUrl);
+       // BladeFile bladeFile = newIOSSClient.uploadFile(file.getOriginalFilename(),exceUrl);
+        // 解析原始excel
+        Workbook wb = new Workbook();
+        wb.loadFromMHtml(file.getInputStream());
+        Worksheet sheet = wb.getWorksheets().get(0);
+        sheet.saveToHtml(thmlUrl);
+
+        BladeFile bladeFileR = newIOSSClient.uploadFileByInputStream(file);
         detail.setExtension(file.getOriginalFilename());
-        detail.setFileUrl(bladeFile.getLink());
+        detail.setFileUrl(bladeFileR.getLink());
         detail.setFileType(3); // 表示为清表信息  1 表示祖节点  2 表示为节点信息 3 表示清表
         detail.setHtmlUrl(thmlUrl);
         excelTabService.saveOrUpdate(detail);
@@ -840,7 +846,7 @@ public class ExcelTabController extends BladeController {
 
 
     // 上传解析 html
-    public void expailHtmlInfo(String thmlUrl, Long excelId) throws Exception {
+    public void expailHtmlInfo12231(String thmlUrl, Long excelId) throws Exception {
 
         // 读取
         File file1 = ResourceUtil.getFile(thmlUrl);
@@ -1149,7 +1155,7 @@ public class ExcelTabController extends BladeController {
     }
 
     // 上传解析 html
-    public void expailHtmlInfo1111111(String thmlUrl, Long excelId) throws Exception {
+    public void expailHtmlInfo(String thmlUrl, Long excelId) throws Exception {
 
         // 读取
         File file1 = ResourceUtil.getFile(thmlUrl);
@@ -1209,6 +1215,16 @@ public class ExcelTabController extends BladeController {
             for (int j = 0; j < tds.size(); j++) {
                 {
                     Element data = tds.get(j);
+                    Boolean isText = false;
+                    //判断高度
+                    String style = data.attr("style");
+                    if (StringUtils.isNotBlank(style)){
+                        String substring = style.substring(style.lastIndexOf(":") + 1);
+                        String height = substring.substring(0, substring.length() - 3);
+                        if (Integer.parseInt(height) > 90){
+                            isText = true;
+                        }
+                    }
                     String trHtml = data.html();
                     int colspan = data.attr("COLSPAN").equals("") ? 0 : Integer.parseInt(data.attr("COLSPAN"));
                     int rowspan = data.attr("ROWSPAN").equals("") ? 0 : Integer.parseInt(data.attr("ROWSPAN"));
@@ -1504,7 +1520,7 @@ public class ExcelTabController extends BladeController {
 
                         } else {
                             if (index_state) { // 区域内
-                                if (rowspan >= 1) {
+                                if (rowspan >= 1 || isText) {
                                     data.empty().append("<el-input type='textarea' @keydown.shift.up='keyupShiftUp' @keydown.shift.down='keyupShiftDown' @keydown.shift.left='keyupShiftLeft'  @keydown.shift.right='keyupShiftRight'  @contextmenu.prevent.native='contextmenuClick(" + parm + ")'  @mouseup.right='RightClick(" + parm + ")' trIndex=" + i + " tdIndex=" + j + "  x1=" + x1 + " x2=" + x2 + " y1=" + y1 + " y2=" + y2 + " style='width:100%;height:100%;'   :rows=" + rowspan * 2 + " placeholder=''> </el-input>");
                                 } else {
                                     data.empty().append("<el-input type='text' @keydown.shift.up='keyupShiftUp' @keydown.shift.down='keyupShiftDown' @keydown.shift.left='keyupShiftLeft'  @keydown.shift.right='keyupShiftRight'  @contextmenu.prevent.native='contextmenuClick(" + parm + ")'  @mouseup.right='RightClick(" + parm + ")' trIndex=" + i + " tdIndex=" + j + "  x1=" + x1 + " x2=" + x2 + " y1=" + y1 + " y2=" + y2 + " style='width:100%;height:100%;' placeholder=''> </el-input>");
@@ -1512,7 +1528,7 @@ public class ExcelTabController extends BladeController {
                             } else { // 区域外
                                 if (j == 0) {
                                     if (colspan == maxCol && i >= 1) {
-                                        if (rowspan >= 1) {
+                                        if (rowspan >= 1 || isText) {
                                             data.empty().append("<el-input @keydown.shift.up='keyupShiftUp' @keydown.shift.down='keyupShiftDown' @keydown.shift.left='keyupShiftLeft' @keydown.shift.right='keyupShiftRight' type='textarea'  @contextmenu.prevent.native='contextmenuClick(" + parm + ")'  @mouseup.right='RightClick(" + parm + ")' trIndex=" + i + " tdIndex=" + j + "  x1=" + x1 + " x2=" + x2 + " y1=" + y1 + " y2=" + y2 + " style='width:100%;height:100%;'   :rows=" + rowspan * 2 + " placeholder=''> </el-input>");
                                         } else {
                                             data.empty().append("<el-input @keydown.shift.up='keyupShiftUp' @keydown.shift.down='keyupShiftDown' @keydown.shift.left='keyupShiftLeft' @keydown.shift.right='keyupShiftRight' type='text' @contextmenu.prevent.native='contextmenuClick(" + parm + ")'  @mouseup.right='RightClick(" + parm + ")' trIndex=" + i + " tdIndex=" + j + "  x1=" + x1 + " x2=" + x2 + " y1=" + y1 + " y2=" + y2 + " style='width:100%;height:100%;' placeholder=''> </el-input>");
@@ -1521,7 +1537,7 @@ public class ExcelTabController extends BladeController {
                                 } else {
                                     Element bforData = tds.get(j - 1);
                                     if (!bforData.text().isEmpty() || bforData.html().indexOf("hc-form-checkbox-group") >= 0) {
-                                        if (rowspan >= 1) {
+                                        if (rowspan >= 1 || isText) {
                                             data.empty().append("<el-input @keydown.shift.up='keyupShiftUp' @keydown.shift.down='keyupShiftDown' @keydown.shift.left='keyupShiftLeft' @keydown.shift.right='keyupShiftRight' type='textarea' @contextmenu.prevent.native='contextmenuClick(" + parm + ")'  @mouseup.right='RightClick(" + parm + ")' trIndex=" + i + " tdIndex=" + j + "  x1=" + x1 + " x2=" + x2 + " y1=" + y1 + " y2=" + y2 + " style='width:100%;height:100%;'   :rows=" + rowspan * 2 + " placeholder=''> </el-input>");
                                         } else {
                                             data.empty().append("<el-input @keydown.shift.up='keyupShiftUp' @keydown.shift.down='keyupShiftDown' @keydown.shift.left='keyupShiftLeft'  @keydown.shift.right='keyupShiftRight' type='text' @contextmenu.prevent.native='contextmenuClick(" + parm + ")'  @mouseup.right='RightClick(" + parm + ")' trIndex=" + i + " tdIndex=" + j + "  x1=" + x1 + " x2=" + x2 + " y1=" + y1 + " y2=" + y2 + " style='width:100%;height:100%;' placeholder=''> </el-input>");
@@ -3496,6 +3512,65 @@ public class ExcelTabController extends BladeController {
         return R.data("成功!");
     }
 
+//    @PostMapping("/batchUploadExcelTab")
+//    @ApiOperationSupport(order = 39)
+//    @ApiOperation(value = "批量上传清表", notes = "传入id、fileList")
+//    public R<Object> batchUploadExcelTab(@RequestParam Long id, @RequestPart("file") MultipartFile[] file) throws IOException {
+//        if (ObjectUtil.isEmpty(id)) {
+//            throw new ServiceException("获取节点信息失败");
+//        }
+//        if (file.length <= 0) {
+//            throw new ServiceException("未获取到需要上传的文件信息");
+//        }
+//        ExcelTab excelTabParentNode = excelTabService.getBaseMapper().selectById(id);
+//        List<ExcelTab> excelTabs = excelTabService.getBaseMapper().selectList(Wrappers.<ExcelTab>lambdaQuery().select(ExcelTab::getSort).eq(ExcelTab::getParentId, excelTabParentNode.getId()));
+//        Optional<Integer> maxSort = excelTabs.stream().map(ExcelTab::getSort).max(Integer::compare);
+//        int maxValue = 1;
+//        if (maxSort.isPresent()) {
+//            maxValue = maxSort.get();
+//        }
+//        for (MultipartFile fileDTO : file) {
+//            if (ObjectUtil.isEmpty(fileDTO.getOriginalFilename())) {
+//                throw new ServiceException("文件名不能为空");
+//            }
+//            if (!this.isExcelFormat(fileDTO.getOriginalFilename())) {
+//                throw new ServiceException("文件名后缀不是.xlsx或者.xls格式,请重新填写");
+//            }
+//            if (!this.isExcelFile(fileDTO)) {
+//                throw new ServiceException("【" + fileDTO.getOriginalFilename() + "】文件不是excel格式文件,上传终止");
+//            }
+//            try {
+//                R<BladeFile> bladeFile = iossClient.addFileInfo(fileDTO);
+//                if (ObjectUtil.isNotEmpty(bladeFile.getData())) {
+//                    //创建节点,并上传excel文件到节点上
+//                    ExcelTab excelTabNode = new ExcelTab();
+//                    excelTabNode.setId(SnowFlakeUtil.getId());
+//                    excelTabNode.setParentId(excelTabParentNode.getId());
+//                    excelTabNode.setFileType(3); //不要上传按钮 默认=3
+//                    excelTabNode.setName(fileDTO.getOriginalFilename().split(".xls")[0]);
+//                    excelTabNode.setAlias(excelTabParentNode.getAlias() + "," + excelTabParentNode.getId());
+//                    excelTabNode.setFileUrl(bladeFile.getData().getLink());
+//                    excelTabNode.setExtension(fileDTO.getOriginalFilename());
+//                    excelTabNode.setCreateTime(new Date());
+//                    excelTabNode.setUpdateTime(new Date());
+//                    excelTabNode.setCreateUser(SecureUtil.getUserId());
+//                    excelTabNode.setUpdateUser(SecureUtil.getUserId());
+//                    excelTabNode.setCreateDept(SecureUtil.getUser().getDeptId().contains(",") ? Long.parseLong(SecureUtil.getUser().getDeptId().split(",")[0]) : Long.parseLong(SecureUtil.getUser().getDeptId()));
+//                    excelTabNode.setStatus(1);
+//                    excelTabNode.setIsDeleted(0);
+//                    excelTabNode.setTabType(excelTabParentNode.getTabType());
+//                    excelTabNode.setTenantId(SecureUtil.getTenantId());
+//                    excelTabNode.setSort(maxValue++);
+//                    excelTabService.save(excelTabNode);
+//                }
+//            } catch (Exception e) {
+//                throw new ServiceException("【" + fileDTO.getOriginalFilename() + "】文件上传失败,上传终止" + e.getMessage());
+//            }
+//        }
+//        return R.success("操作成功");
+//    }
+
+
     @PostMapping("/batchUploadExcelTab")
     @ApiOperationSupport(order = 39)
     @ApiOperation(value = "批量上传清表", notes = "传入id、fileList")
@@ -3513,43 +3588,25 @@ public class ExcelTabController extends BladeController {
         if (maxSort.isPresent()) {
             maxValue = maxSort.get();
         }
-        for (MultipartFile fileDTO : file) {
-            if (ObjectUtil.isEmpty(fileDTO.getOriginalFilename())) {
-                throw new ServiceException("文件名不能为空");
-            }
-            if (!this.isExcelFormat(fileDTO.getOriginalFilename())) {
-                throw new ServiceException("文件名后缀不是.xlsx或者.xls格式,请重新填写");
-            }
-            if (!this.isExcelFile(fileDTO)) {
-                throw new ServiceException("【" + fileDTO.getOriginalFilename() + "】文件不是excel格式文件,上传终止");
-            }
-            try {
-                R<BladeFile> bladeFile = iossClient.addFileInfo(fileDTO);
-                if (ObjectUtil.isNotEmpty(bladeFile.getData())) {
-                    //创建节点,并上传excel文件到节点上
-                    ExcelTab excelTabNode = new ExcelTab();
-                    excelTabNode.setId(SnowFlakeUtil.getId());
-                    excelTabNode.setParentId(excelTabParentNode.getId());
-                    excelTabNode.setFileType(3); //不要上传按钮 默认=3
-                    excelTabNode.setName(fileDTO.getOriginalFilename().split(".xls")[0]);
-                    excelTabNode.setAlias(excelTabParentNode.getAlias() + "," + excelTabParentNode.getId());
-                    excelTabNode.setFileUrl(bladeFile.getData().getLink());
-                    excelTabNode.setExtension(fileDTO.getOriginalFilename());
-                    excelTabNode.setCreateTime(new Date());
-                    excelTabNode.setUpdateTime(new Date());
-                    excelTabNode.setCreateUser(SecureUtil.getUserId());
-                    excelTabNode.setUpdateUser(SecureUtil.getUserId());
-                    excelTabNode.setCreateDept(SecureUtil.getUser().getDeptId().contains(",") ? Long.parseLong(SecureUtil.getUser().getDeptId().split(",")[0]) : Long.parseLong(SecureUtil.getUser().getDeptId()));
-                    excelTabNode.setStatus(1);
-                    excelTabNode.setIsDeleted(0);
-                    excelTabNode.setTabType(excelTabParentNode.getTabType());
-                    excelTabNode.setTenantId(SecureUtil.getTenantId());
-                    excelTabNode.setSort(maxValue++);
-                    excelTabService.save(excelTabNode);
-                }
-            } catch (Exception e) {
-                throw new ServiceException("【" + fileDTO.getOriginalFilename() + "】文件上传失败,上传终止" + e.getMessage());
-            }
+        for (MultipartFile fileDTO : file){
+            //创建节点,并上传excel文件到节点上
+            ExcelTab excelTabNode = new ExcelTab();
+            Long aLong = SnowFlakeUtil.getId();
+            excelTabNode.setId(aLong);
+            excelTabNode.setParentId(excelTabParentNode.getId());
+            excelTabNode.setFileType(3); //不要上传按钮 默认=3
+            excelTabNode.setName(fileDTO.getOriginalFilename().split(".xls")[0]);
+            excelTabNode.setAlias(excelTabParentNode.getAlias() + "," + excelTabParentNode.getId());
+            excelTabNode.setTabType(excelTabParentNode.getTabType());
+            excelTabNode.setTenantId(SecureUtil.getTenantId());
+            excelTabNode.setSort(++maxValue);
+            excelTabNode.setCreateTime(new Date());
+            excelTabNode.setUpdateTime(new Date());
+            excelTabNode.setCreateUser(SecureUtil.getUserId());
+            excelTabNode.setUpdateUser(SecureUtil.getUserId());
+            excelTabNode.setStatus(1);
+            excelTabService.save(excelTabNode);
+            this.putFileAttach(fileDTO,aLong);
         }
         return R.success("操作成功");
     }

+ 89 - 16
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreeContractController.java

@@ -49,6 +49,7 @@ import java.net.URLEncoder;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.*;
 import java.util.List;
@@ -280,6 +281,12 @@ public class WbsTreeContractController extends BladeController {
         return R.data(list);
     }
 
+    /**
+     * 客户端-下载元素表对应的excel模板
+     *
+     * @author liuyc
+     * @date 2023年8月30日15:44:55
+     */
     @SneakyThrows
     @GetMapping("/download-excel")
     @ApiOperationSupport(order = 13)
@@ -355,7 +362,7 @@ public class WbsTreeContractController extends BladeController {
                 try (ServletOutputStream outputStream = response.getOutputStream();
                      ByteArrayOutputStream byteArrayOutputStreamResult = new ByteArrayOutputStream()) {
                     //设置响应头
-                    response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(tab.getFullName(), "UTF-8") + ".xlsx");
+                    response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(ObjectUtil.isNotEmpty(tab.getFullName()) ? tab.getFullName() : tab.getNodeName(), "UTF-8") + ".xlsx");
                     response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
                     poiWorkbook.write(byteArrayOutputStreamResult);
                     byte[] excelBytesResult = byteArrayOutputStreamResult.toByteArray();
@@ -439,6 +446,12 @@ public class WbsTreeContractController extends BladeController {
         cellStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
     }
 
+    /**
+     * 客户端-导入excel数据到对应元素表中
+     *
+     * @author liuyc
+     * @date 2023年8月29日
+     */
     @PostMapping("/import-excel")
     @ApiOperationSupport(order = 14)
     @ApiOperation(value = "客户端-导入excel数据到对应元素表中", notes = "传入表的pKeyId、excel文件file")
@@ -456,6 +469,7 @@ public class WbsTreeContractController extends BladeController {
         String doubleSlashRegex_XG = ".*\\/[^\\/]*\\/.*"; //匹配包含两个斜杠且不相邻的字符串
         String dateFormatRegex_yyyyMdd = "\\d{4}/\\d{1,2}/\\d{1,2}"; //yyyy/M/dd格式
         String dateFormatRegex_yyyyMMdd = "\\d{4}/\\d{2}/\\d{2}";   //yyyy/MM/dd格式
+        String dateFormatRegex_chinese = "(\\d{4}年\\d{1,2}月\\d{1,2}日|\\d{4}年\\d{2}月\\d{2}日)"; //“2023年1月1日、2023年01月01日”这两种格式
         SimpleDateFormat inputDateFormat = new SimpleDateFormat("yyyy/M/dd");
         SimpleDateFormat outputDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
 
@@ -464,7 +478,7 @@ public class WbsTreeContractController extends BladeController {
         String importExcelFilePath = FileUtils.getSysLocalFileUrl();
         String importExcelTOHtmlPath = importExcelFilePath + "/pdf//" + id + ".html";
 
-        //解析匹配数据
+        //解析匹配数据(rul_1为临时文件地址,接口执行后删除,用流读取会导致htmlString_2乱码,只能存储本地后再解析)
         String url_1 = "";
         com.spire.xls.Workbook workbook = null;
         try {
@@ -490,12 +504,16 @@ public class WbsTreeContractController extends BladeController {
                 for (int j = 0; j < tdElements1.size(); j++) {
                     Element td1 = tdElements1.get(j);
                     Element td2 = tdElements2.get(j);
-                    //String x1 = getX1Attribute(td1);
-                    //String y1 = getY1Attribute(td1);
                     String keyName = getKeyNameFromChildElement(td1);
                     if (StringUtils.isNotEmpty(keyName)) {
                         String divValue = td2.text(); //获取文本值
                         if (StringUtils.isNotEmpty(divValue)) {
+                            if (parseDateRange(divValue).size() == 2) {
+                                //判断范围日期
+                                List<String> dateArr = parseDateRange(divValue);
+                                stringStringMap.put(keyName, dateArr);
+                                continue;
+                            }
                             //判断是否存在两个斜杠,且不在一起,那么视为日期格式
                             Pattern pattern_XG = Pattern.compile(doubleSlashRegex_XG);
                             Matcher matcher_XG = pattern_XG.matcher(divValue);
@@ -512,8 +530,16 @@ public class WbsTreeContractController extends BladeController {
                                     Date date = inputDateFormat.parse(divValue);
                                     divValue = outputDateFormat.format(date);
                                 }
+
+                            } else if (divValue.contains("年") && divValue.contains("月") && divValue.contains("日")) {
+                                //判断如:“2023年1月1日、2023年01月01日”这两种格式
+                                Pattern pattern_chinese = Pattern.compile(dateFormatRegex_chinese);
+                                Matcher matcher_chinese = pattern_chinese.matcher(divValue);
+                                if (matcher_chinese.matches()) {
+                                    Date date = outputDateFormat.parse(divValue);
+                                    divValue = outputDateFormat.format(date);
+                                }
                             }
-                            //String mapKey = keyName + "***" + x1 + "_" + y1;
                             stringStringMap.put(keyName, divValue);
                         }
                     }
@@ -552,6 +578,53 @@ public class WbsTreeContractController extends BladeController {
         return R.data(null, "没有获取到excel中的数据");
     }
 
+    /**
+     * 判断日期范围格式数据,以下12种格式
+     * 2023-01-01-2023-01-30 或 2023-01-01~2023-01-30
+     * 2023-1-1-2023-1-30 或 2023-1-1~2023-1-30
+     * 2023/01/01-2023/01/30 或 2023/01/01~2023/01/30
+     * 2023/1/1-2023/1/30 或 2023/1/1~2023/1/30
+     * 2023年01月01日-2023年01月30日 或 2023年01月01日~2023年01月30日
+     * 2023年1月1日-2023年1月30日 或 2023年1月1日~2023年01月30日
+     *
+     * @param inputDateStr
+     * @return
+     * @throws ParseException
+     */
+    public static List<String> parseDateRange(String inputDateStr) throws ParseException {
+        String[] patterns = {
+                "(\\d{4}[年\\/-]\\d{1,2}[月\\/-]\\d{1,2}[日]?)[-~](\\d{4}[年\\/-]\\d{1,2}[月\\/-]\\d{1,2}[日]?)"
+        };
+        for (String pattern : patterns) {
+            Pattern regex = Pattern.compile(pattern);
+            Matcher matcher = regex.matcher(inputDateStr);
+            if (matcher.find()) {
+                String startDateStr = matcher.group(1);
+                String endDateStr = matcher.group(2);
+                boolean var1 = startDateStr.contains("年");
+                boolean var2 = startDateStr.contains("-");
+                boolean var3 = startDateStr.contains("/");
+                SimpleDateFormat inputDateFormat = null;
+                SimpleDateFormat outputDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
+                if (var1) {
+                    inputDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
+                } else if (var2) {
+                    inputDateFormat = new SimpleDateFormat("yyyy-MM-dd");
+                } else if (var3) {
+                    inputDateFormat = new SimpleDateFormat("yyyy/MM/dd");
+                }
+                if (inputDateFormat != null) {
+                    Date startDate = inputDateFormat.parse(startDateStr);
+                    Date endDate = inputDateFormat.parse(endDateStr);
+                    String resultStartDateStr = outputDateFormat.format(startDate);
+                    String resultEndDateStr = outputDateFormat.format(endDate);
+                    return Arrays.asList(resultStartDateStr, resultEndDateStr);
+                }
+            }
+        }
+        return new ArrayList<>();
+    }
+
     private static boolean deleteFolder(Path folderPath) throws IOException {
         if (Files.exists(folderPath)) {
             Files.walk(folderPath)
@@ -574,14 +647,6 @@ public class WbsTreeContractController extends BladeController {
         return false;
     }
 
-    private static String getX1Attribute(Element element) {
-        return element.select("[x1]").attr("x1");
-    }
-
-    private static String getY1Attribute(Element element) {
-        return element.select("[y1]").attr("y1");
-    }
-
     private static String getKeyNameFromChildElement(Element element) {
         //TODO Element UI的时间标签待补全
         String[] tagNames = {"el-input", "el-date-picker", "el-time-picker", "hc-form-select-search", "hc-table-form-upload", "hc-form-checkbox-group", "el-radio-group", "el-select"};
@@ -608,11 +673,19 @@ public class WbsTreeContractController extends BladeController {
         }
     }
 
+    /**
+     * 懒加载获取合同段隐蔽工程节点树
+     *
+     * @param contractId
+     * @param parentId
+     * @author liuyc
+     * @date 2023年8月30日15:44:28
+     */
     @PostMapping("/getConcealedWorksNodeTree")
     @ApiOperationSupport(order = 15)
-    @ApiOperation(value = "获取合同段隐蔽工程节点树-懒加载", notes = "传入合同段id、父级id")
-    public R<List<WbsTreeContractVO>> getConcealedWorksNodeTree(@RequestParam String contractId, @RequestParam String parentId) {
-        List<WbsTreeContractVO> result = iWbsTreeContractService.getConcealedWorksNodeTree(contractId, parentId);
+    @ApiOperation(value = "懒加载获取合同段隐蔽工程节点树", notes = "传入合同段id、父级id")
+    public R<List<WbsTreeContractLazyVO>> getConcealedWorksNodeTree(@RequestParam String contractId, @RequestParam String parentId) {
+        List<WbsTreeContractLazyVO> result = iWbsTreeContractService.getConcealedWorksNodeTree(contractId, parentId);
         return R.data(result);
     }
 

+ 10 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/feign/ProjectAssignmentUserClientImpl.java

@@ -41,6 +41,16 @@ public class ProjectAssignmentUserClientImpl implements ProjectAssignmentUserCli
                                     Function.identity(),
                                     (dto1, dto2) -> dto1))
                             .values());
+                }else {
+                    List<SaveUserInfoByProjectDTO> list = this.saveUserInfoByProjectService.list(Wrappers.<SaveUserInfoByProjectDTO>lambdaQuery().eq(SaveUserInfoByProjectDTO::getContractId, contractId).eq(SaveUserInfoByProjectDTO::getIsDeleted, 0));
+                    //根据roleId、userId去重
+                    return new ArrayList<>(list.stream()
+                            .collect(Collectors.toMap(
+                                    dto -> dto.getRoleId() + "-" + dto.getUserId(),
+                                    Function.identity(),
+                                    (dto1, dto2) -> dto1))
+                            .values());
+
                 }
             } else if (contractInfo.getContractType() == 2 || contractInfo.getContractType() == 3) {
                 //如果本身就是监理合同段,那么不处理,返回本身合同段信息

+ 2 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreeContractMapper.xml

@@ -653,7 +653,8 @@
         SELECT b.*
         from u_operation_log a,
              blade_user b
-        where a.operation_account = b.account
+        where b.tenant_id = '000000' /*只查询后管系统的用户*/
+          and a.operation_account = b.account
           and a.operation_type = 1
           and a.business_id like concat('%', #{sonId}, '%')
         group by b.id

+ 1 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/service/IWbsTreeContractService.java

@@ -69,7 +69,7 @@ public interface IWbsTreeContractService extends BaseService<WbsTreeContract> {
 
     List<AppWbsTreeContractVO> searchNodeAllTableAndFile(String primaryKeyId, String type, String contractId, String projectId);
 
-    List<WbsTreeContractVO> getConcealedWorksNodeTree(String contractId, String parentId);
+    List<WbsTreeContractLazyVO> getConcealedWorksNodeTree(String contractId, String parentId);
 
 
 }

+ 12 - 2
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ArchiveTreeContractSyncImpl.java

@@ -254,7 +254,7 @@ public class ArchiveTreeContractSyncImpl {
      */
     public void  syncBusinessDataThread(Long projectId,Long contractId) {
 
-        executorService.execute(()->{
+        //executorService.execute(()->{
             try{
                 //将项目未锁定案卷拆卷
                 syncBusinessData(projectId,contractId);
@@ -267,7 +267,7 @@ public class ArchiveTreeContractSyncImpl {
                 //设置自动组卷结束
                 contractInfoService.updateIsArchivesAutoById(contractId, 0);
             }
-        });
+        //});
 
     }
 
@@ -279,6 +279,8 @@ public class ArchiveTreeContractSyncImpl {
      */
     public void  syncBusinessData(Long projectId,Long contractId) {
 
+        log.info("同步文件  projectId:"+projectId+"-contractId:"+contractId);
+
         //项目信息
         ProjectInfo projectInfo = projectInfoService.getOne(projectId);
 
@@ -325,6 +327,10 @@ public class ArchiveTreeContractSyncImpl {
             wbsTreeKeyToIdMap.put(wbsTreeContractVO6.getPKeyId(),wbsTreeContractVO6.getId());
         }
 
+
+        log.info("同步文件  informationQueryList size :"+informationQueryList.size()+
+                " - archiveFiles :"+archiveFiles.size() +  " - wbsTreeContractVO6s :"+wbsTreeContractVO6s.size());
+
         //同步质检关联节点
         syncNodes(contractId, informationQueryList, wbsTreeContractVO6Map, wbsTreeKeyToSortMap,
                 wbsTreeKeyToIdMap, archiveKeyIdMap, contractIndfo);
@@ -421,10 +427,14 @@ public class ArchiveTreeContractSyncImpl {
             return;
         }
 
+        log.info("同步文件  syncNodes"+associatedNodes.size());
+
         Map<Long,Long> archiveTreeContractIdMap = new LinkedHashMap<>();
 
         for (ArchiveTreeContract node : associatedNodes) {
             Integer nodeLevel = Integer.valueOf(associatedNodes.get(0).getDisplayHierarchy());
+
+            log.info("同步文件  syncNode"+ nodeLevel + " " + node.getId() + " " +  node.getNodeName());
             if (nodeLevel == 0) {
                 continue;
             }

+ 2 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ExcelTabServiceImpl.java

@@ -58,6 +58,7 @@ import org.springblade.manager.formula.NodeTable;
 import org.springblade.manager.formula.impl.TableElementConverter;
 import org.springblade.manager.mapper.ExcelTabMapper;
 import org.springblade.manager.service.*;
+import org.springblade.manager.utils.ExcelInfoUtils;
 import org.springblade.manager.utils.FileUtils;
 import org.springblade.manager.vo.*;
 import org.springblade.resource.feign.NewIOSSClient;
@@ -619,7 +620,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
                 //上传新文件到文件服务器
                 //excel修改 同步修改html 对象
                 String thmlUrl = file_path + filecode + ".html";
-              //  FileUtils.excelInfo(inputStream,dataUrl,thmlUrl,"2");
+                ExcelInfoUtils.excelInfo(inputStream,dataUrl,thmlUrl,"2");
                 BladeFile bladeFile = newIOSSClient.uploadFile(excelTab.getExtension(), dataUrl);
                 //获取文件大小
                int size = connection.getContentLength() / 1024 / 1024; //单位M

+ 150 - 144
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeContractServiceImpl.java

@@ -1,6 +1,5 @@
 package org.springblade.manager.service.impl;
 
-import cn.hutool.core.swing.ScreenUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
@@ -57,7 +56,6 @@ import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.math.BigInteger;
-import java.time.Year;
 import java.util.*;
 import java.util.function.Function;
 import java.util.regex.Matcher;
@@ -936,21 +934,13 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                                         ArrayList::new
                                 ));
 
-                        //所有节点parentId分组Map
-                        Map<Long, List<WbsTreeContractLazyVO>> parentIdToNodesMap = distinctNodesAll.stream()
-                                .collect(Collectors.groupingBy(WbsTreeContractLazyVO::getParentId));
-
-                        //所有节点id分组Map
-                        Map<Long, List<WbsTreeContractLazyVO>> idToNodesMap = distinctNodesAll.stream()
-                                .collect(Collectors.groupingBy(WbsTreeContractLazyVO::getId));
-
                         //所有最底层节点
                         List<WbsTreeContractLazyVO> distinctLowestNodesAll = distinctNodesAll.stream().filter(f -> f.getHasChildren().equals(0)).collect(Collectors.collectingAndThen(
                                 Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(WbsTreeContractLazyVO::getPKeyId))),
                                 ArrayList::new
                         ));
                         //获取当前合同段所有影像文件信息
-                        List<WbsTreeContractLazyFileVO> queryFileList = jdbcTemplate.query("select wbs_id,id from u_image_classification_file where status = 1 and contract_id = " + contractId + " and classify_id = " + classId, new BeanPropertyRowMapper<>(WbsTreeContractLazyFileVO.class));
+                        List<WbsTreeContractLazyFileVO> queryFileList = jdbcTemplate.query("select wbs_id,id from u_image_classification_file where status = 1 and is_deleted = 0 and contract_id = " + contractId + " and classify_id = " + classId, new BeanPropertyRowMapper<>(WbsTreeContractLazyFileVO.class));
                         //最底层节点与存储文件数量map
                         Map<Long, Integer> queryFileMaps = queryFileList.stream()
                                 .collect(Collectors.groupingBy(
@@ -959,27 +949,34 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                                 ));
                         List<Long> pKeyIdList = new ArrayList<>(queryFileMaps.keySet());
 
-                        //所有最底层节点,处理文件数量
-                        List<WbsTreeContractLazyVO> lowestNodesFile = distinctLowestNodesAll.stream().filter(f -> pKeyIdList.contains(f.getPKeyId())).collect(Collectors.toList());
-                        Set<Long> lowestNodeParentIds = lowestNodesFile.stream().map(WbsTreeContractLazyVO::getParentId).collect(Collectors.toSet());
-
-                        //获取所有父级节点
-                        Set<WbsTreeContractLazyVO> resultParentNodes = new HashSet<>();
-                        this.getParentNodes(resultParentNodes, lowestNodeParentIds, idToNodesMap);
+                        //填报过的所有最底层节点,处理数量
+                        List<WbsTreeContractLazyVO> lowestNodesTB = distinctLowestNodesAll.stream().filter(f -> pKeyIdList.contains(f.getPKeyId())).collect(Collectors.toList());
+                        List<WbsTreeContractLazyVO> lowestNodesTBNew = BeanUtil.copyProperties(lowestNodesTB, WbsTreeContractLazyVO.class);
+                        for (WbsTreeContractLazyVO vo : lowestNodesTB) {
+                            Integer fileCounts = queryFileMaps.get(vo.getPKeyId());
+                            if (fileCounts > 1) {
+                                /*当前节点下存在多个影像资料文件信息,那么就要添加进入集合中统一处理,
+                                在入参根据parentId分组时,就存在出现多个父级节点信息;
+                                此处要从1开始循环,因为不包含本身,如果从0,会多一条父级节点信息*/
+                                for (int i = 1; i < fileCounts; i++) {
+                                    lowestNodesTBNew.add(vo);
+                                }
+                            }
+                        }
+                        List<Long> lowestNodeParentIdsTB = lowestNodesTBNew.stream().map(WbsTreeContractLazyVO::getParentId).collect(Collectors.toList());
+                        List<WbsTreeContractLazyVO> resultParentNodesTB = new ArrayList<>();
+                        this.recursiveGetParentNodes(resultParentNodesTB, lowestNodeParentIdsTB, nodesAll);
 
                         //处理最终结果集
                         if (lazyNodes.size() > 0) {
                             Map<Long, Integer> countMap = new HashMap<>();
-                            for (WbsTreeContractLazyVO node : resultParentNodes) {
+                            for (WbsTreeContractLazyVO node : resultParentNodesTB) {
                                 Long key = node.getPKeyId();
-                                Set<WbsTreeContractLazyVO> resultNodes = new HashSet<>();
-                                //获取最底层节点的文件数量信息
-                                this.getDcNodes(resultNodes, Collections.singletonList(node), parentIdToNodesMap);
-                                int totalCount = 0;
-                                for (Long pKeyId : resultNodes.stream().map(WbsTreeContractLazyVO::getPKeyId).collect(Collectors.toSet())) {
-                                    totalCount += queryFileMaps.getOrDefault(pKeyId, 0);
+                                if (countMap.containsKey(key)) {
+                                    countMap.put(key, countMap.get(key) + 1);
+                                } else {
+                                    countMap.put(key, 1);
                                 }
-                                countMap.put(key, totalCount);
                             }
 
                             //返回最终结果集
@@ -1041,14 +1038,6 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                                                 ArrayList::new
                                         ));
 
-                                //所有节点parentId分组Map
-                                Map<Long, List<WbsTreeContractLazyVO>> parentIdToNodesMap = distinctNodesAll.stream()
-                                        .collect(Collectors.groupingBy(WbsTreeContractLazyVO::getParentId));
-
-                                //所有节点id分组Map
-                                Map<Long, List<WbsTreeContractLazyVO>> idToNodesMap = distinctNodesAll.stream()
-                                        .collect(Collectors.groupingBy(WbsTreeContractLazyVO::getId));
-
                                 //所有最底层节点
                                 List<WbsTreeContractLazyVO> distinctLowestNodesAll = distinctNodesAll.stream().filter(f -> f.getHasChildren().equals(0)).collect(Collectors.collectingAndThen(
                                         Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(WbsTreeContractLazyVO::getPKeyId))),
@@ -1066,27 +1055,31 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
 
                                 List<Long> pKeyIdList = new ArrayList<>(queryFileMaps.keySet());
 
-                                //所有最底层节点,处理文件数量
-                                List<WbsTreeContractLazyVO> lowestNodesFile = distinctLowestNodesAll.stream().filter(f -> pKeyIdList.contains(f.getPKeyId())).collect(Collectors.toList());
-                                Set<Long> lowestNodeParentIds = lowestNodesFile.stream().map(WbsTreeContractLazyVO::getParentId).collect(Collectors.toSet());
-
-                                //获取所有父级节点
-                                Set<WbsTreeContractLazyVO> resultParentNodes = new HashSet<>();
-                                this.getParentNodes(resultParentNodes, lowestNodeParentIds, idToNodesMap);
+                                //填报过的所有最底层节点,处理数量
+                                List<WbsTreeContractLazyVO> lowestNodesTB = distinctLowestNodesAll.stream().filter(f -> pKeyIdList.contains(f.getPKeyId())).collect(Collectors.toList());
+                                List<WbsTreeContractLazyVO> lowestNodesTBNew = BeanUtil.copyProperties(lowestNodesTB, WbsTreeContractLazyVO.class);
+                                for (WbsTreeContractLazyVO vo : lowestNodesTB) {
+                                    Integer fileCounts = queryFileMaps.get(vo.getPKeyId());
+                                    if (fileCounts > 1) {
+                                        for (int i = 1; i < fileCounts; i++) {
+                                            lowestNodesTBNew.add(vo);
+                                        }
+                                    }
+                                }
+                                List<Long> lowestNodeParentIdsTB = lowestNodesTBNew.stream().map(WbsTreeContractLazyVO::getParentId).collect(Collectors.toList());
+                                List<WbsTreeContractLazyVO> resultParentNodesTB = new ArrayList<>();
+                                this.recursiveGetParentNodes(resultParentNodesTB, lowestNodeParentIdsTB, nodesAll);
 
                                 //处理最终结果集
                                 if (lazyNodes.size() > 0) {
                                     Map<Long, Integer> countMap = new HashMap<>();
-                                    for (WbsTreeContractLazyVO node : resultParentNodes) {
+                                    for (WbsTreeContractLazyVO node : resultParentNodesTB) {
                                         Long key = node.getPKeyId();
-                                        Set<WbsTreeContractLazyVO> resultNodes = new HashSet<>();
-                                        //获取最底层节点的文件数量信息
-                                        this.getDcNodes(resultNodes, Collections.singletonList(node), parentIdToNodesMap);
-                                        int totalCount = 0;
-                                        for (Long pKeyId : resultNodes.stream().map(WbsTreeContractLazyVO::getPKeyId).collect(Collectors.toSet())) {
-                                            totalCount += queryFileMaps.getOrDefault(pKeyId, 0);
+                                        if (countMap.containsKey(key)) {
+                                            countMap.put(key, countMap.get(key) + 1);
+                                        } else {
+                                            countMap.put(key, 1);
                                         }
-                                        countMap.put(key, totalCount);
                                     }
 
                                     //返回最终结果集
@@ -1117,59 +1110,6 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
         return null;
     }
 
-    /**
-     * 获取所有父级节点
-     *
-     * @param resultParentNodes
-     * @param parentIds
-     * @param idToNodesMap
-     */
-    private void getParentNodes(Set<WbsTreeContractLazyVO> resultParentNodes, Set<Long> parentIds, Map<Long, List<WbsTreeContractLazyVO>> idToNodesMap) {
-        if (parentIds.size() > 0 && !parentIds.contains(0L)) {
-            Set<Long> parentIdsAll = new HashSet<>();
-            for (Long parentId : parentIds) {
-                List<WbsTreeContractLazyVO> parentNodes = idToNodesMap.get(parentId);
-                if (parentNodes.size() > 0) {
-                    resultParentNodes.addAll(parentNodes);
-                    Set<Long> parentIdsFu = parentNodes.stream().map(WbsTreeContractLazyVO::getParentId).collect(Collectors.toSet());
-                    if (parentIdsFu.size() > 0) {
-                        parentIdsAll.addAll(parentIdsFu);
-                    }
-                }
-            }
-            if (parentIdsAll.size() > 0) {
-                this.getParentNodes(resultParentNodes, parentIdsAll, idToNodesMap);
-            }
-        }
-    }
-
-    /**
-     * 递归获取所有最底层节点
-     */
-    private void getDcNodes(Set<WbsTreeContractLazyVO> resultNodes, List<WbsTreeContractLazyVO> initNode, Map<Long, List<WbsTreeContractLazyVO>> parentIdToNodeAllMap) {
-        Set<Long> childIds = initNode.stream().map(WbsTreeContractLazyVO::getId).collect(Collectors.toSet());
-        if (childIds.size() > 0) {
-            List<WbsTreeContractLazyVO> dcNodeAll = new ArrayList<>();
-            for (Long childId : childIds) {
-                //所有子级
-                List<WbsTreeContractLazyVO> childNodes = parentIdToNodeAllMap.get(childId);
-                //最底层节点,返回结果
-                List<WbsTreeContractLazyVO> dcNode = childNodes.stream().filter(f -> f.getHasChildren() == 0).collect(Collectors.toList());
-                if (dcNode.size() > 0) {
-                    resultNodes.addAll(dcNode);
-                }
-                //非最底层节点,进入下次递归循环
-                List<WbsTreeContractLazyVO> noDcNode = childNodes.stream().filter(f -> f.getHasChildren() == 1).collect(Collectors.toList());
-                if (noDcNode.size() > 0) {
-                    dcNodeAll.addAll(noDcNode);
-                }
-            }
-            if (dcNodeAll.size() > 0) {
-                this.getDcNodes(resultNodes, dcNodeAll, parentIdToNodeAllMap);
-            }
-        }
-    }
-
     @Override
     public boolean syncContractTabSort(String projectId) {
         if (ObjectUtil.isNotEmpty(projectId)) {
@@ -1214,52 +1154,59 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
     }
 
     @Override
-    public List<WbsTreeContractVO> getConcealedWorksNodeTree(String contractId, String parentId) {
-        List<WbsTreeContract> wbsTreeContracts = this.getBaseMapper().selectList(Wrappers.<WbsTreeContract>lambdaQuery()
-                .select(WbsTreeContract::getId, WbsTreeContract::getPKeyId, WbsTreeContract::getParentId, WbsTreeContract::getNodeType,
-                        WbsTreeContract::getType, WbsTreeContract::getWbsType, WbsTreeContract::getMajorDataType, WbsTreeContract::getPartitionCode,
-                        WbsTreeContract::getOldId, WbsTreeContract::getContractIdRelation, WbsTreeContract::getIsConcealedWorksNode, WbsTreeContract::getIsConcrete
-                )
-                .eq(WbsTreeContract::getContractId, contractId).eq(WbsTreeContract::getIsConcealedWorksNode, 1));
-        List<WbsTreeContract> initNode = wbsTreeContracts.stream()
-                .distinct()
-                .collect(Collectors.toList());
-        //获取所有隐蔽节点的父级、子级
-        Set<WbsTreeContract> resultAllNodes = new HashSet<>();
-        this.getConcealedWorkParentNode(resultAllNodes, initNode, contractId);
-        this.getConcealedWorkChildNode(resultAllNodes, initNode, contractId);
-        resultAllNodes.addAll(initNode);
-
-        /*List<WbsTreeContractVO> result = new ArrayList<>();
-        for (WbsTreeContract resultAllNode : resultAllNodes) {
-            WbsTreeContractVO vo = new WbsTreeContractVO();
-            BeanUtil.copyProperties(resultAllNode, vo);
-            vo.setNodeName(resultAllNode.getNodeName());
-            vo.setFullName(resultAllNode.getFullName());
-            vo.setTitle(resultAllNode.getFullName());
-            result.add(vo);
-        }*/
-        //return this.buildWbsTreeByStream(result, 0L); //全加载树
-
-        List<WbsTreeContractVO> result = BeanUtil.copyProperties(resultAllNodes, WbsTreeContractVO.class);
-        Map<Long, List<WbsTreeContractVO>> groupMaps = result.stream().collect(Collectors.groupingBy(WbsTreeContractVO::getParentId));
-
-        //半懒加载,实际上已经查出全部的数据了,过滤一下,懒得重新改接口;
-        List<WbsTreeContractVO> wbsTreeContractVOS;
-        if (StringUtils.isNotEmpty(parentId)) {
-            //返回子节点
-            wbsTreeContractVOS = groupMaps.get(Long.parseLong(parentId));
+    public List<WbsTreeContractLazyVO> getConcealedWorksNodeTree(String contractId, String parentId) {
+        //获取当前合同段隐蔽工程节点相关的缓存信息
+        List<WbsTreeContract> nodesAllByConcealedWorksNode = new ArrayList<>();
+        Object data = redisTemplate.opsForValue().get("blade-manager::contract:wbstree:ConcealedWorksNode:" + contractId);
+        if (data != null) {
+            nodesAllByConcealedWorksNode = JSON.parseArray(data.toString(), WbsTreeContract.class);
         } else {
-            //返回根节点
-            wbsTreeContractVOS = groupMaps.get(0L);
+            List<WbsTreeContract> initNode = this.getBaseMapper().selectList(Wrappers.<WbsTreeContract>lambdaQuery()
+                    .eq(WbsTreeContract::getContractId, contractId).eq(WbsTreeContract::getIsConcealedWorksNode, 1)).stream().distinct().collect(Collectors.toList());
+            Set<WbsTreeContract> resultAllNodes = new HashSet<>();
+            this.getConcealedWorkParentNode(resultAllNodes, initNode, contractId);
+            this.getConcealedWorkChildNode(resultAllNodes, initNode, contractId);
+            resultAllNodes.addAll(initNode);
+            if (resultAllNodes.size() > 0) {
+                //把隐蔽工程相关节点存入缓存
+                JSONArray array = JSONArray.parseArray(JSON.toJSONString(resultAllNodes));
+                redisTemplate.opsForValue().set("blade-manager::contract:wbstree:ConcealedWorksNode:" + contractId, JSON.toJSON(array).toString());
+                nodesAllByConcealedWorksNode.addAll(resultAllNodes);
+            }
         }
-        for (WbsTreeContractVO wbsTreeContractVO : wbsTreeContractVOS) {
-            List<WbsTreeContractVO> child = groupMaps.get(wbsTreeContractVO.getId());
-            if (child != null && child.size() > 0) {
-                wbsTreeContractVO.setHasChildren(true);
+        if (nodesAllByConcealedWorksNode != null) {
+            List<WbsTreeContractLazyVO> result = new ArrayList<>();
+            for (WbsTreeContract obj : nodesAllByConcealedWorksNode) {
+                WbsTreeContractLazyVO vo = BeanUtil.copyProperties(obj, WbsTreeContractLazyVO.class);
+                if (vo != null) {
+                    vo.setTitle(ObjectUtil.isNotEmpty(obj.getFullName()) ? obj.getFullName() : obj.getNodeName());
+                    result.add(vo);
+                }
             }
+            Map<Long, List<WbsTreeContractLazyVO>> groupMaps = result.stream().collect(Collectors.groupingBy(WbsTreeContractLazyVO::getParentId));
+            List<WbsTreeContractLazyVO> wbsTreeContractLazyVOList;
+            if (StringUtils.isNotEmpty(parentId)) {
+                //返回子节点
+                wbsTreeContractLazyVOList = groupMaps.get(Long.parseLong(parentId));
+            } else {
+                //返回根节点
+                wbsTreeContractLazyVOList = groupMaps.get(0L);
+            }
+            if (wbsTreeContractLazyVOList != null && wbsTreeContractLazyVOList.size() > 0) {
+                for (WbsTreeContractLazyVO vo : wbsTreeContractLazyVOList) {
+                    List<WbsTreeContractLazyVO> child = groupMaps.get(vo.getId());
+                    if (child != null && child.size() > 0) {
+                        vo.setHasChildren(1);
+                        vo.setNotExsitChild(false);
+                    } else {
+                        vo.setHasChildren(0);
+                        vo.setNotExsitChild(true);
+                    }
+                }
+            }
+            return wbsTreeContractLazyVOList;
         }
-        return wbsTreeContractVOS;
+        return null;
     }
 
     /**
@@ -1375,6 +1322,56 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
         }
     }
 
+    public void recursiveGetParentNodes2(List<WbsTreeContractLazyVO> result, List<Long> lowestNodeParentIds, List<WbsTreeContractLazyVO> nodesAll) {
+        if (lowestNodeParentIds.isEmpty()) {
+            return;
+        }
+
+        //父级Id与出现的次数Map
+        Map<Long, Long> parentIdGroup = lowestNodeParentIds.stream()
+                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
+
+        List<String> keysWithValueOne = new ArrayList<>();
+        Map<Long, Long> keysWithValueSome = new HashMap<>();
+
+        for (Map.Entry<Long, Long> entry : parentIdGroup.entrySet()) {
+            if (entry.getValue() == 1L) {
+                keysWithValueOne.add(entry.getKey().toString());
+            } else {
+                keysWithValueSome.put(entry.getKey(), entry.getValue());
+            }
+        }
+
+        //批量查询单次节点
+        List<WbsTreeContractLazyVO> parentNodes = new ArrayList<>();
+        if (keysWithValueOne.size() > 0) {
+            parentNodes = nodesAll.stream().filter(f -> keysWithValueOne.contains(f.getId().toString())).collect(Collectors.toList());
+        }
+
+        //批量查询多次节点
+        List<WbsTreeContractLazyVO> multipleParentNodes = new ArrayList<>();
+        for (Map.Entry<Long, Long> entry : keysWithValueSome.entrySet()) {
+            Long key = entry.getKey();
+            Long count = entry.getValue();
+
+            List<WbsTreeContractLazyVO> nodes = nodesAll.stream().filter(f -> key.equals(f.getId())).collect(Collectors.toList());
+            if (!nodes.isEmpty()) {
+                multipleParentNodes.addAll(Collections.nCopies(count.intValue(), nodes.get(0)));
+            }
+        }
+
+        //结果集
+        List<Long> collect = Stream.concat(parentNodes.stream(), multipleParentNodes.stream())
+                .map(WbsTreeContractLazyVO::getParentId)
+                .collect(Collectors.toList());
+
+        if (!collect.isEmpty()) {
+            result.addAll(parentNodes);
+            result.addAll(multipleParentNodes);
+            this.recursiveGetParentNodes(result, collect, nodesAll);
+        }
+    }
+
     /**
      * 反向递归处理父节点颜色
      */
@@ -2134,6 +2131,15 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                 updateWrapper.eq(WbsTreeContract::getPKeyId, treeContract.getPKeyId()).set(WbsTreeContract::getIsConcealedWorksNode, treeContract.getIsConcealedWorksNode());
                 baseMapper.update(null, updateWrapper);
             }
+
+            //更新缓存信息,APP懒加载隐蔽工程节点树使用
+            Set<String> contractIds = wbsTreeContractList.stream().map(WbsTreeContract::getContractId).collect(Collectors.toSet());
+            for (String contractId : contractIds) {
+                Set<String> keys = redisTemplate.keys("blade-manager::contract:wbstree:ConcealedWorksNode:" + contractId + "*");
+                if (keys != null) {
+                    redisTemplate.delete(keys);
+                }
+            }
             return true;
         }
         return false;

+ 401 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/utils/ExcelInfoUtils.java

@@ -0,0 +1,401 @@
+package org.springblade.manager.utils;
+
+import com.spire.xls.CellRange;
+import com.spire.xls.FileFormat;
+import com.spire.xls.Workbook;
+import com.spire.xls.Worksheet;
+import com.spire.xls.core.IXLSRange;
+import com.spire.xls.core.spreadsheet.HTMLOptions;
+import org.apache.commons.lang.StringUtils;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+import org.springblade.common.utils.SnowFlakeUtil;
+import org.springblade.core.tool.utils.FileUtil;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.IoUtil;
+import org.springblade.core.tool.utils.ResourceUtil;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ExcelInfoUtils {
+
+    public static void main123(String[] args) throws FileNotFoundException {
+        String excelUrl = "/Users/hongchuangyanfa/Downloads/C10.28隧道注浆施工记录表(1).xlsx";
+        String old_html = "/Users/hongchuangyanfa/Desktop/pdf/old_html.html";
+        String old_xlsx = "/Users/hongchuangyanfa/Desktop/pdf/old_html.xlsx";
+        File file = new File(excelUrl);
+        InputStream fileInputStream = new FileInputStream(file);
+        excelInfo(fileInputStream,old_xlsx,old_html,"1");
+
+
+        // 解析原始excel
+        Workbook wb = new Workbook();
+        wb.loadFromMHtml(excelUrl);
+        Worksheet sheet = wb.getWorksheets().get(0);
+
+/*        CellRange[] mergedCells = sheet.getMergedCells();
+        for(int i=0;i<mergedCells.length;i++){
+            CellRange oldcell = mergedCells[i];
+            IXLSRange ixlsRange = sheet.get(oldcell.getRow(), oldcell.getColumn(), oldcell.getLastRow(), oldcell.getLastColumn());
+            System.out.println(ixlsRange.getDataValidation().getErrorMessage());
+        }
+
+
+        ArrayList<CellRange> cellList = sheet.getCellList();
+        for(int i=0;i<cellList.size();i++){
+            CellRange oldcell = cellList.get(i);
+            System.out.println(oldcell.getRow()+"---"+oldcell.getColumn()+"---="+oldcell.getText()+"---x="+oldcell.getDataValidation().getErrorMessage());
+        }*/
+
+
+
+        String new_html = "/Users/hongchuangyanfa/Desktop/pdf/new_html.html";
+        String new_xlsx = "/Users/hongchuangyanfa/Desktop/pdf/new_html.xlsx";
+       // excelInfo(old_xlsx,new_xlsx,new_html);
+    }
+
+    public static void excelInfo(InputStream inputStream, String excelURL, String htmlUrl,String type) {
+        try {
+            String file_path = "/Users/hongchuangyanfa/Desktop//pdf/";
+            String filecode = SnowFlakeUtil.getId() + "";
+            String thmlUrl2 = file_path + filecode + "123.html";
+
+            // 解析原始excel
+            Workbook wb = new Workbook();
+            wb.loadFromMHtml(inputStream);
+            Worksheet sheet = wb.getWorksheets().get(0);
+
+            HTMLOptions options = new HTMLOptions();
+            options.setImageEmbedded(true);
+
+            //复制一份
+            wb.saveToFile(excelURL,FileFormat.Version2013);
+            // 操作
+            Workbook wb2 = new Workbook();
+            wb2.loadFromMHtml(excelURL);
+            Worksheet sheet2 = wb2.getWorksheets().get(0);
+
+            // 坐标map
+            Map<String, Map<String, Integer>> xyList = new HashMap<>();
+            int j = 0;
+            int maxVal = 0;
+            if(type.equals("2")){
+                CellRange[] sheet2Cells = sheet2.getCells();
+                for (int i = 0; i < sheet2Cells.length; i++) {
+                    CellRange oldcell = sheet2Cells[i];
+                    String data = oldcell.getDataValidation().getErrorMessage();
+                    int k = 0;
+                    if(Func.isNumeric(data)){
+                        k = Func.toInt(data);
+                    }
+                    if (maxVal < k) {
+                        maxVal = k;
+                    }
+                }
+            }else if(type.equals("1")){
+                CellRange[] sheet2Cells = sheet.getCells();
+                for (int i = 0; i < sheet2Cells.length; i++) {
+                    CellRange oldcell = sheet2Cells[i];
+                    sheet.getCellRange(oldcell.getRow(),oldcell.getColumn()).getDataValidation().setErrorMessage("");
+                }
+            }
+
+            //合并单元格操作
+            CellRange[] mergedCells = sheet.getMergedCells();
+            for (int i = 0; i < mergedCells.length; i++) {
+                Map<String, Integer> dataMap = new HashMap<>();
+                CellRange oldcell = mergedCells[i];
+                CellRange mergedCell = sheet.getCellRange(oldcell.getRow(), oldcell.getColumn());
+                if(type.equals("2")){
+                    String data = mergedCell.getDataValidation().getErrorMessage();
+                    if (StringUtils.isEmpty(data)) {
+                        if(maxVal<=0){
+                            j = j + 1;
+                        }else{
+                            maxVal = maxVal+1;
+                            j=maxVal;
+                        }
+                    } else {
+                        j = Func.toInt(data);
+                    }
+                }else{
+                    j = j + 1;
+                }
+
+                // 目标表添加备注信息
+             //   mergedCell.getDataValidation().setErrorMessage(j+"");
+               // oldcell.getDataValidation().setErrorMessage(j+"");
+               // sheet2.getMergedCells()[i].setText(j+"");
+                dataMap.put("y1", oldcell.getRow());
+                dataMap.put("y2", oldcell.getLastRow());
+                dataMap.put("x1", oldcell.getColumn());
+                dataMap.put("x2", oldcell.getLastColumn());
+                xyList.put(j + "", dataMap);
+            }
+
+            //变更最大值
+            if(maxVal<=0){
+                maxVal = j;
+            }
+
+            // 单个
+            CellRange[] onCell = sheet.getCells();
+            // 单个cell
+            for (int i = 0; i < onCell.length; i++) {
+                CellRange oldcell = onCell[i];
+                String data = oldcell.getDataValidation().getErrorMessage();
+                System.out.println(oldcell.getRow()+"---"+oldcell.getColumn()+"---="+oldcell.getText()+"---x="+data);
+                if (StringUtils.isEmpty(data)) {
+                    if(maxVal<=0){
+                        j = j + 1;
+                    }else{
+                        maxVal = maxVal+1;
+                        j=maxVal;
+                    }
+                } else {
+                    j = Func.toInt(data);
+                }
+                if(StringUtils.isEmpty(data)){
+                    oldcell.getDataValidation().setErrorMessage(j+"");
+                    sheet2.getCells()[i].setText(j+"");
+                }
+                if(!xyList.containsKey(j+"")){
+                    Map<String, Integer> dataMap = new HashMap<>();
+                    dataMap.put("y1", oldcell.getRow());
+                    dataMap.put("y2", oldcell.getLastRow());
+                    dataMap.put("x1", oldcell.getColumn());
+                    dataMap.put("x2", oldcell.getLastColumn());
+                    xyList.put(j + "", dataMap);
+                }
+            }
+
+            // 保存上传的excel
+            wb.saveToFile(excelURL,FileFormat.Version2013);
+            sheet.saveToHtml(htmlUrl, options);
+            sheet2.saveToHtml(thmlUrl2);
+
+            // html 转换值
+
+            // 组装坐标
+            File html1 = new File(htmlUrl);  // 原始html
+            File html2 = new File(thmlUrl2); // 坐标html
+            InputStream inputStream1 = new FileInputStream(html1);
+            InputStream inputStream2 = new FileInputStream(html2);
+            String htmlString1 = IoUtil.readToString(inputStream1);
+            String htmlString2 = IoUtil.readToString(inputStream2);
+
+            Document doc1 = Jsoup.parse(htmlString1);
+            Element table1 = doc1.select("table").first();
+            Elements trs1 = table1.select("tr");
+            Document doc2 = Jsoup.parse(htmlString2);
+            Element table2 = doc2.select("table").first();
+            Elements trs2 = table2.select("tr");
+
+            for (int i = 0; i < trs1.size(); i++) {
+                Elements td1 = trs1.get(i).select("td");
+                Elements td2 = trs2.get(i).select("td");
+                for (int x = 0; x < td1.size(); x++) {
+                    Element cell1 = td1.get(x);
+                    Element cell2 = td2.get(x);
+                    String html = cell2.text();
+                    Map<String, Integer> xyMap = xyList.get(html);
+                    if (xyMap != null) {
+                        cell1.attr("x1", xyMap.get("x1") + "");
+                        cell1.attr("x2", xyMap.get("x2") + "");
+                        cell1.attr("y1", xyMap.get("y1") + "");
+                        cell1.attr("y2", xyMap.get("y2") + "");
+                        cell1.attr("exceVal",html);
+                    }
+                }
+            }
+
+            File writeFile = new File(htmlUrl);
+            FileUtil.writeToFile(writeFile, doc1.html(), Boolean.parseBoolean("UTF-8"));
+            if (html2.exists()) {
+               // html2.delete();
+            }
+            wb2.dispose();
+            wb.dispose();
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+    /**
+     * 在线编辑excel 操作
+     *
+     * @param inExcelUrl
+     * @param excelURL
+     * @param htmlUrl
+     * @throws Exception
+     */
+    public static void excelInfo222(String inExcelUrl, String excelURL, String htmlUrl) {
+        try {
+            String file_path = FileUtils.getSysLocalFileUrl() + "/pdf/";
+            String filecode = SnowFlakeUtil.getId() + "";
+            String thmlUrl2 = file_path + filecode + "123.html";
+
+            // 解析原始excel
+            com.spire.xls.Workbook wb = new com.spire.xls.Workbook();
+            wb.loadFromMHtml(inExcelUrl);
+
+            // 操作
+            com.spire.xls.Workbook wb2 = new com.spire.xls.Workbook();
+            wb2.loadFromMHtml(inExcelUrl);
+
+            //获取工作表
+            Worksheet sheet = wb.getWorksheets().get(0);
+            Worksheet sheet2 = wb2.getWorksheets().get(0);
+
+            HTMLOptions options = new HTMLOptions();
+            options.setImageEmbedded(true);
+
+            sheet.saveToHtml(htmlUrl, options);
+          //  wb.saveToFile(excelURL, FileFormat.Version2013);
+
+            CellRange[] mergedCells = sheet.getMergedCells();
+            Map<String, Map<String, Integer>> xyList = new HashMap<>();
+
+            CellRange[] cellRanges = sheet.getCells();
+
+            int j = 0;
+            int maxVal = 0;
+
+           /* for (int i = 0; i < cellRanges.length; i++) {
+                CellRange oldcell = cellRanges[i];
+                CellRange mergedCell = sheet.getCellRange(oldcell.getRow(), oldcell.getColumn());
+                String data = mergedCell.getDataValidation().getErrorMessage();
+                int k = 0;
+                if(Func.isNumeric(data)){
+                    k = Func.toInt(data);
+                }
+                if (maxVal < k) {
+                    maxVal = k;
+                }
+            }*/
+
+            for (int i = 0; i < mergedCells.length; i++) {
+                Map<String, Integer> dataMap = new HashMap<>();
+                CellRange oldcell = mergedCells[i];
+                CellRange mergedCell = sheet.getCellRange(oldcell.getRow(), oldcell.getColumn());
+                String data = mergedCell.getDataValidation().getErrorMessage();
+                if (StringUtils.isEmpty(data)) {
+                    if(maxVal<=0){
+                        j = j + 1;
+                    }else{
+                        maxVal = maxVal+1;
+                        j=maxVal;
+                    }
+                } else {
+                    if(Func.isNumeric(data)){
+                        j = Func.toInt(data);
+                    }else {
+                        j = Func.toInt((data.trim().replaceAll("\r|\n", "")).split(":")[1] + "");
+                    }
+                }
+                // 目标表添加备注信息
+                sheet2.getCellRange(oldcell.getRow(), oldcell.getColumn()).getDataValidation().setErrorMessage(j+"");
+                mergedCell.getDataValidation().setErrorMessage(j+"");
+                oldcell.getDataValidation().setErrorMessage(j+"");
+                mergedCell.setText(j + "");
+                dataMap.put("y1", oldcell.getRow());
+                dataMap.put("y2", oldcell.getLastRow());
+                dataMap.put("x1", oldcell.getColumn());
+                dataMap.put("x2", oldcell.getLastColumn());
+                xyList.put(j + "", dataMap);
+            }
+
+
+            CellRange[] onCell = sheet.getCells();
+            // 单个cell
+           /* for (int i = 0; i < onCell.length; i++) {
+                CellRange oldcell = onCell[i];
+                CellRange mergedCell = sheet.getCellRange(oldcell.getRow(), oldcell.getColumn());
+                String data = mergedCell.getDataValidation().getErrorMessage();
+                Map<String, Integer> dataMap = new HashMap<>();
+                if (StringUtils.isEmpty(data)) {
+                    if(maxVal<=0){
+                        j = j + 1;
+                    }else{
+                        maxVal = maxVal+1;
+                        j=maxVal;
+                    }
+                    // null 需要添加坐标
+                    dataMap.put("y1", oldcell.getRow());
+                    dataMap.put("y2", oldcell.getLastRow());
+                    dataMap.put("x1", oldcell.getColumn());
+                    dataMap.put("x2", oldcell.getLastColumn());
+                    xyList.put(j + "", dataMap);
+                } else {
+                    if(Func.isNumeric(data)){
+                        j = Func.toInt(data);
+                    }else {
+                        j = Func.toInt((data.trim().replaceAll("\r|\n", "")).split(":")[1] + "");
+                    }
+                }
+                sheet2.getCellRange(oldcell.getRow(), oldcell.getColumn()).getDataValidation().setErrorMessage(j+"");
+                mergedCell.setText(j + "");
+            }*/
+            sheet.saveToHtml(thmlUrl2, options);
+
+            // 上传excel文件
+            wb2.saveToFile(excelURL, FileFormat.Version2013);
+
+            // 组装坐标
+            File html1 = new File(htmlUrl);  // 原始html
+            File html2 = new File(thmlUrl2); // 坐标html
+            InputStream inputStream1 = new FileInputStream(html1);
+            InputStream inputStream2 = new FileInputStream(html2);
+            String htmlString1 = IoUtil.readToString(inputStream1);
+            String htmlString2 = IoUtil.readToString(inputStream2);
+
+            org.jsoup.nodes.Document doc1 = Jsoup.parse(htmlString1);
+            Element table1 = doc1.select("table").first();
+            Elements trs1 = table1.select("tr");
+            org.jsoup.nodes.Document doc2 = Jsoup.parse(htmlString2);
+            Element table2 = doc2.select("table").first();
+            Elements trs2 = table2.select("tr");
+
+            for (int i = 0; i < trs1.size(); i++) {
+                Elements td1 = trs1.get(i).select("td");
+                Elements td2 = trs2.get(i).select("td");
+                for (int x = 0; x < td1.size(); x++) {
+                    Element cell1 = td1.get(x);
+                    /*if (cell1.children().size() >= 1) {
+                        String data = cell1.text();
+                        cell1.empty();
+                        cell1.text(data);
+                    }*/
+                    Element cell2 = td2.get(x);
+                    String html = cell2.text();
+                    Map<String, Integer> xyMap = xyList.get(html);
+                    if (xyMap != null) {
+                        cell1.attr("x1", xyMap.get("x1") + "");
+                        cell1.attr("x2", xyMap.get("x2") + "");
+                        cell1.attr("y1", xyMap.get("y1") + "");
+                        cell1.attr("y2", xyMap.get("y2") + "");
+                        cell1.attr("exceVal",html);
+                    }
+                }
+            }
+
+            File writeFile = new File(htmlUrl);
+            FileUtil.writeToFile(writeFile, doc1.html(), Boolean.parseBoolean("UTF-8"));
+            if (html2.exists()) {
+                //   html2.delete();
+            }
+            wb2.dispose();
+            wb.dispose();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+}