瀏覽代碼

质检wbs树统计

lvy 1 周之前
父節點
當前提交
f1f0d4cc3f
共有 16 個文件被更改,包括 1371 次插入202 次删除
  1. 29 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/WbsTreeContractStatisticsDTO.java
  2. 211 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/WbsTreeContractStatistics.java
  3. 48 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/feign/WbsTreeContractStatisticsClient.java
  4. 16 2
      blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java
  5. 4 0
      blade-service/blade-business/src/main/java/org/springblade/business/controller/RecycleBinController.java
  6. 156 0
      blade-service/blade-business/src/main/java/org/springblade/business/feignClient/WbsTreeContractStatisticsClientImpl.java
  7. 19 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/WbsTreeContractStatisticsMapper.java
  8. 31 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/WbsTreeContractStatisticsMapper.xml
  9. 16 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/IWbsTreeContractStatisticsService.java
  10. 3 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TaskServiceImpl.java
  11. 590 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/WbsTreeContractStatisticsServiceImpl.java
  12. 1 0
      blade-service/blade-e-visa/src/main/java/org/springblade/evisa/service/impl/EVDataServiceImpl.java
  13. 10 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java
  14. 3 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeContractServiceImpl.java
  15. 20 20
      blade-service/blade-user/src/main/java/org/springblade/system/user/controller/WbsTreeController.java
  16. 214 180
      blade-service/blade-user/src/main/java/org/springblade/system/user/service/impl/UserServiceImpl.java

+ 29 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/WbsTreeContractStatisticsDTO.java

@@ -0,0 +1,29 @@
+package org.springblade.business.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springblade.business.entity.InformationQuery;
+
+import java.io.Serializable;
+
+@Data
+@AllArgsConstructor
+public class WbsTreeContractStatisticsDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+    private Long contractId;
+    private Long pKeyId;
+    private Integer classify;
+
+
+    public WbsTreeContractStatisticsDTO() {
+    }
+
+    public WbsTreeContractStatisticsDTO(InformationQuery  query) {
+        if (query != null) {
+            this.contractId = query.getContractId();
+            this.pKeyId = query.getWbsId();
+            this.classify = query.getClassify();
+        }
+    }
+}

+ 211 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/WbsTreeContractStatistics.java

@@ -0,0 +1,211 @@
+package org.springblade.business.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@TableName("m_wbs_tree_contract_statistics")
+@AllArgsConstructor
+public class WbsTreeContractStatistics implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键id")
+    @TableId(
+            value = "id",
+            type = IdType.ASSIGN_ID
+    )
+    private Long id;
+
+    /**
+     * 项目Id
+     */
+    @JsonProperty(value = "projectId")
+    @ApiModelProperty(name = "projectId", value = "项目Id", required = true)
+    private String projectId;
+
+    /**
+     * 合同Id
+     */
+    @JsonProperty(value = "contractId")
+    @ApiModelProperty(name = "contractId", value = "合同Id", required = true)
+    private String contractId;
+
+    /**
+     * 父主键
+     */
+    @ApiModelProperty(value = "父主键id")
+    private Long parentId;
+
+    /**
+     * 祖级列表
+     */
+    @ApiModelProperty(value = "祖级id列表")
+    private String ancestors;
+
+    /**
+     * 是否是叶子节点, 1 是 0 不是
+     */
+    @ApiModelProperty(value = "是否是叶子节点, 1 是 0 不是")
+    private Integer isLeaf;
+
+    /**
+     * 叶子节点数量
+     */
+    @ApiModelProperty(value = "叶子节点数量")
+    private Integer leafNum = 0;
+
+    /**
+     * 已填报数量
+     */
+    @ApiModelProperty(value = "已填报数量")
+    private Integer fillNum = 0;
+    /**
+     * 待审批数量
+     */
+    @ApiModelProperty(value = "待审批数量")
+    private Integer approveNum = 0;
+    /**
+     * 已审批数量
+     */
+    @ApiModelProperty(value = "已审批数量")
+    private Integer completeNum = 0;
+    /**
+     * 已填报数量(监理)
+     */
+    @ApiModelProperty(value = "已填报数量(监理)")
+    private Integer jlFillNum = 0;
+    /**
+     * 待审批数量(监理)
+     */
+    @ApiModelProperty(value = "待审批数量(监理)")
+    private Integer jlApproveNum = 0;
+    /**
+     * 已审批数量(监理)
+     */
+    @ApiModelProperty(value = "已审批数量(监理)")
+    private Integer jlCompleteNum = 0;
+
+    @DateTimeFormat(
+            pattern = "yyyy-MM-dd HH:mm:ss"
+    )
+    @JsonFormat(
+            pattern = "yyyy-MM-dd HH:mm:ss"
+    )
+    @ApiModelProperty("创建时间")
+    private Date createTime;
+
+    @DateTimeFormat(
+            pattern = "yyyy-MM-dd HH:mm:ss"
+    )
+    @JsonFormat(
+            pattern = "yyyy-MM-dd HH:mm:ss"
+    )
+    @ApiModelProperty("更新时间")
+    private Date updateTime = new Date();
+
+    @ApiModelProperty("业务状态")
+    private Integer status = 1;
+    @TableLogic
+    @ApiModelProperty("是否已删除")
+    private Integer isDeleted = 0;
+
+
+    public WbsTreeContractStatistics() {
+
+    }
+    public WbsTreeContractStatistics(Long pKeyId, String projectId, String contractId, Long pId, String ancestors) {
+        if (pKeyId != null) {
+            this.id =pKeyId;
+            this.projectId = projectId;
+            this.contractId = contractId;
+            this.parentId = pId == null ? 0L : pId;
+            this.ancestors = ancestors == null ? "" : ancestors;
+            this.status = 1;
+            this.isLeaf = 1;
+        }
+    }
+
+    public WbsTreeContractStatistics(Long pKeyId, String projectId, String contractId, Long pId, String ancestors, Integer isLeaf) {
+        this(pKeyId, projectId, contractId, pId, ancestors);
+        this.isLeaf = isLeaf;
+    }
+
+    public Integer calculateSgSubmitNums() {
+        this.fillNum = this.fillNum == null ? 0 : this.fillNum;
+        this.approveNum = this.approveNum == null ? 0 : this.approveNum;
+        this.completeNum = this.completeNum == null ? 0 : this.completeNum;
+        return this.approveNum + this.completeNum + this.fillNum;
+    }
+
+    public Integer calculateSgColorStatus() {
+        this.fillNum = this.fillNum == null ? 0 : this.fillNum;
+        this.approveNum = this.approveNum == null ? 0 : this.approveNum;
+        this.completeNum = this.completeNum == null ? 0 : this.completeNum;
+        return calculateStatus(this.fillNum, this.approveNum, this.completeNum, this.leafNum);
+    }
+
+    public Integer calculateJlSubmitNums() {
+        this.jlApproveNum = this.jlApproveNum == null ? 0 : this.jlApproveNum;
+        this.jlCompleteNum = this.jlCompleteNum == null ? 0 : this.jlCompleteNum;
+        this.jlFillNum = this.jlFillNum == null ? 0 : this.jlFillNum;
+        return this.jlApproveNum + this.jlCompleteNum + this.jlFillNum;
+    }
+
+    public Integer calculateJlColorStatus() {
+        this.jlApproveNum = this.jlApproveNum == null ? 0 : this.jlApproveNum;
+        this.jlCompleteNum = this.jlCompleteNum == null ? 0 : this.jlCompleteNum;
+        this.jlFillNum = this.jlFillNum == null ? 0 : this.jlFillNum;
+        return calculateStatus(this.jlFillNum, this.jlApproveNum, this.jlCompleteNum, this.leafNum);
+    }
+
+    // 1 未填报 2已填报 3待审批 4 已审批
+    public int calculateStatus(int fillNum, int approveNum, int completeNum, int leafNum) {
+        // 叶子节点只有一种情况的
+        if (fillNum == 0 && approveNum == 0 && completeNum == 0) {
+            return 1;
+        }
+        if ((leafNum == 0 || leafNum == completeNum) && completeNum > 0 && approveNum == 0 && fillNum == 0) {
+            return 4;
+        }
+        if ((leafNum == 0 || leafNum == approveNum) && completeNum == 0 && approveNum > 0 && fillNum == 0) {
+            return 3;
+        }
+        if ((leafNum == 0 || leafNum == fillNum) && completeNum == 0 && approveNum == 0 && fillNum > 0) {
+            return 2;
+        }
+        int unApproveNum = Math.max(leafNum - approveNum - completeNum - fillNum, 0);
+        if (unApproveNum == 0 && fillNum == 0 && approveNum > 0 && completeNum > 0) {
+            return 3;
+        }
+        return 2;
+    }
+
+    public Integer calculateSubmitNums(String tableOwner) {
+        if ("1".equals(tableOwner)) {
+            return calculateSgSubmitNums();
+        } else if ("2".equals(tableOwner)) {
+            return calculateJlSubmitNums();
+        }
+        return null;
+    }
+
+    public Integer calculateColorStatus(String tableOwner) {
+        if ("1".equals(tableOwner)) {
+            return calculateSgColorStatus();
+        } else if ("2".equals(tableOwner)) {
+            return calculateJlColorStatus();
+        }
+        return null;
+    }
+}

+ 48 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/feign/WbsTreeContractStatisticsClient.java

@@ -0,0 +1,48 @@
+package org.springblade.business.feign;
+
+
+import org.springblade.business.dto.WbsTreeContractStatisticsDTO;
+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;
+
+import static org.springblade.core.launch.constant.AppConstant.APPLICATION_NAME_PREFIX;
+
+@FeignClient(value = APPLICATION_NAME_PREFIX + "manager")
+public interface WbsTreeContractStatisticsClient {
+
+    /**
+     * 接口前缀
+     */
+    String API_PREFIX = "/api/manager/WbsTreeContractStatistics";
+
+    /**
+     * 更新统计表节点信息
+     * WbsTreeContractStatisticsDTO
+     */
+    @PostMapping(API_PREFIX + "/updateInformationQuery")
+    void updateInformationQueryStatus(@RequestBody List<WbsTreeContractStatisticsDTO> wbsTreeContractStatisticsDTOs);
+
+    @GetMapping(API_PREFIX + "/updateInformationQueryStatusByTaskId")
+    void updateInformationQueryStatusByTaskId(@RequestParam String taskIds);
+
+    /**
+     * 更新统计表节点
+     */
+    @GetMapping(API_PREFIX + "/updateWbsTreeContractNodes")
+    void updateWbsTreeContractNodes(@RequestParam String nodeIds);
+
+    @GetMapping(API_PREFIX + "/delWbsTreeContractNodes")
+    void delWbsTreeContractNodes(@RequestParam String nodeIds);
+
+    @GetMapping(API_PREFIX + "/recycleWbsTreeContractNodes")
+    void recycleWbsTreeContractNodes(@RequestParam String nodeIds);
+
+    @GetMapping(API_PREFIX + "/statisticsContract")
+    void statisticsContract(@RequestParam Long contractId);
+
+}

+ 16 - 2
blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java

@@ -27,11 +27,13 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springblade.business.dto.CustomAddContractNodeDTO;
 import org.springblade.business.dto.ImportTreeDto;
+import org.springblade.business.dto.WbsTreeContractStatisticsDTO;
 import org.springblade.business.entity.*;
 import org.springblade.business.feign.MessageWarningClient;
 import org.springblade.business.feign.OperationLogClient;
 import org.springblade.business.feign.RecycleBinClient;
 import org.springblade.business.feign.TaskClient;
+import org.springblade.business.feignClient.WbsTreeContractStatisticsClientImpl;
 import org.springblade.business.mapper.InformationQueryMapper;
 import org.springblade.business.service.*;
 import org.springblade.business.utils.FileUtils;
@@ -154,6 +156,7 @@ public class InformationWriteQueryController extends BladeController {
     private final ExcelTabClient excelTabClient;
 
     private final IRecycleBinService recycleBinService;
+    private final WbsTreeContractStatisticsClientImpl wbsTreeContractStatisticsClient;
 
 
     @Autowired
@@ -1455,6 +1458,10 @@ public R<String> batchDownloadFileToZip(String ids, HttpServletResponse response
                         for (Long contractId1 : contractIds) {
                             informationQueryService.delAsyncWbsTree(contractId1 + "");
                         }
+                        if (!queries.isEmpty()) {
+                            List<WbsTreeContractStatisticsDTO> collect1 = queries.stream().filter(query -> query.getType() == 1).map(WbsTreeContractStatisticsDTO::new).collect(Collectors.toList());
+                            wbsTreeContractStatisticsClient.updateInformationQueryStatus(collect1);
+                        }
                     }
 
                     try {
@@ -1725,7 +1732,10 @@ public R<Object> batchTask(@RequestBody StartTaskVO startTaskVO) {
             }
 
             informationQueryService.delAsyncWbsTree(startTaskVO.getContractId());
-
+            if (queries != null && !queries.isEmpty()) {
+                List<WbsTreeContractStatisticsDTO> collect1 = queries.stream().filter(query -> query.getType() == 1).map(WbsTreeContractStatisticsDTO::new).collect(Collectors.toList());
+                wbsTreeContractStatisticsClient.updateInformationQueryStatus(collect1);
+            }
             return R.data(200, aopParamsSet, "操作成功");
         }
     }
@@ -2066,7 +2076,7 @@ public R<Boolean> copyContractTreeNode(@RequestBody CopyContractTreeNodeVO vo) {
 
         /*更新缓存*/
         informationQueryService.delAsyncWbsTree(needCopyNode.getContractId());
-
+        wbsTreeContractStatisticsClient.updateWbsTreeContractNodes(saveList.stream().map(item -> item.getPKeyId() + "").collect(Collectors.joining(",")));
         return booleanR;
 
     } else if (("2").equals(vo.getCopyType())) {
@@ -2286,6 +2296,7 @@ public R<Boolean> copyContractTreeNode(@RequestBody CopyContractTreeNodeVO vo) {
                 if (row) {
                     //更新redis缓存
                     informationQueryService.delAsyncWbsTree(contractId);
+                    wbsTreeContractStatisticsClient.updateWbsTreeContractNodes(nodes.stream().map(item -> item.getPKeyId() + "").collect(Collectors.joining(",")));
                 }
 
                 //拼接操作记录
@@ -3566,6 +3577,7 @@ public R removeContractTreeNodeJudge(@RequestParam String ids) {
             this.wbsTreeContractClient.removeContractTreeNode(idArray);
             //更新redis
             this.informationQueryService.delAsyncWbsTree(removeWbsTreeContracts.get(0).getContractId());
+            this.wbsTreeContractStatisticsClient.delWbsTreeContractNodes(String.join(",", idArray));
         }
         return R.data(true);
     }
@@ -4074,6 +4086,7 @@ public R<Boolean> saveContractTreeNode(@RequestBody AddContractTreeNodeVO vo) {
 
         List<WbsTreeContract> nowTabs = saveList.stream().filter(f -> new Integer(2).equals(f.getType())).collect(Collectors.toList());
         this.updateTextDictInfos(nowTabs, oldTabIds, vo.getProjectId());//获取电签信息、默认信息
+        wbsTreeContractStatisticsClient.updateWbsTreeContractNodes(saveList.stream().map(item -> item.getPKeyId() + "").collect(Collectors.joining(",")));
         iUserClient.clearContractLocalCacheAndRedisCache();
         flag=booleanR.getData();
         if(!flag){
@@ -4962,6 +4975,7 @@ public R<Object> customAddContractNode(@RequestBody CustomAddContractNodeDTO dto
         }
         if (wbsTreeContractClient.saveBatch(Collections.singletonList(obj))) {
             informationQueryService.delAsyncWbsTree(parentNode.getContractId());
+            wbsTreeContractStatisticsClient.updateWbsTreeContractNodes(obj.getPKeyId() + "");
             return R.success("操作成功");
         }
 

+ 4 - 0
blade-service/blade-business/src/main/java/org/springblade/business/controller/RecycleBinController.java

@@ -14,6 +14,7 @@ import org.apache.commons.lang.StringUtils;
 import org.springblade.business.entity.ArchiveFile;
 import org.springblade.business.entity.ImageClassificationFile;
 import org.springblade.business.feign.InformationQueryClient;
+import org.springblade.business.feignClient.WbsTreeContractStatisticsClientImpl;
 import org.springblade.business.service.IArchiveFileService;
 import org.springblade.business.service.IImageClassificationFileService;
 import org.springblade.business.vo.RecycleBinVO;
@@ -54,6 +55,8 @@ public class RecycleBinController extends BladeController {
 
     private final InformationQueryClient informationQueryClient;
 
+    private final WbsTreeContractStatisticsClientImpl wbsTreeContractStatisticsClient;
+
     /**
      * 恢复
      */
@@ -100,6 +103,7 @@ public class RecycleBinController extends BladeController {
                     e.printStackTrace();
                 }
                 informationQueryClient.delAsyncWbsTree(nodeTypeList.get(0).getContractId() + "");
+                wbsTreeContractStatisticsClient.recycleWbsTreeContractNodes(String.join(",", processNodeList));
             }
             //文件类型
             List<RecycleBin> fileTypeList = recycleBinList.stream().filter(recycleBin -> new Integer("1").equals(recycleBin.getDelType())).distinct().collect(Collectors.toList());

+ 156 - 0
blade-service/blade-business/src/main/java/org/springblade/business/feignClient/WbsTreeContractStatisticsClientImpl.java

@@ -0,0 +1,156 @@
+package org.springblade.business.feignClient;
+
+import lombok.AllArgsConstructor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springblade.business.dto.WbsTreeContractStatisticsDTO;
+import org.springblade.business.entity.InformationQuery;
+import org.springblade.business.feign.WbsTreeContractStatisticsClient;
+import org.springblade.business.mapper.InformationQueryMapper;
+import org.springblade.business.service.IWbsTreeContractStatisticsService;
+import org.springblade.business.service.impl.WbsTreeContractStatisticsServiceImpl;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+@RestController
+@AllArgsConstructor
+public class WbsTreeContractStatisticsClientImpl implements WbsTreeContractStatisticsClient {
+
+    private final IWbsTreeContractStatisticsService wbsTreeContractStatisticsService;
+    private final JdbcTemplate jdbcTemplate;
+    private final StringRedisTemplate redisTemplate;
+    private static final Logger log = LoggerFactory.getLogger(WbsTreeContractStatisticsClientImpl.class);
+
+    @Scheduled(cron = "0/10 * * * * ?")
+    public void updateInformationQueryStatus() {
+        Map<String, String> map = new HashMap<>();
+        List<String> taskIds = redisTemplate.opsForList().range("information_query_status_statistics_key", 0, 100);
+        if (taskIds != null && !taskIds.isEmpty()) {
+            List<InformationQuery> queryList = jdbcTemplate.query("select wbs_id, classify, contract_id from u_information_query where id in (select form_data_id from u_task where  id in (?) and is_deleted = 0) and is_deleted = 0 group by contract_id,wbs_id,classify",
+                    new Object[]{String.join(",", taskIds)}, new BeanPropertyRowMapper<>(InformationQuery.class));
+            if (!queryList.isEmpty()) {
+                for (InformationQuery query : queryList) {
+                    if (map.containsKey(query.getWbsId() + "," + query.getContractId() + "," + query.getClassify())) {
+                        continue;
+                    }
+                    try {
+                        wbsTreeContractStatisticsService.updateInformationNumber(query.getWbsId(), query.getClassify(), query.getContractId());
+                        map.put(query.getWbsId() + "," + query.getContractId() + "," + query.getClassify(), "");
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 定时任务 每天四点执行
+     */
+    @Scheduled(cron = "0 0 4 * * ?")
+    public void scheduledSync() {
+        log.info("WbsTreeContractStatistics.scheduledSync 定时任务开始执行, 时间:" + LocalDateTime.now());
+        try {
+            wbsTreeContractStatisticsService.sync();
+        } catch (Exception e) {
+            log.error("WbsTreeContractStatistics.scheduledSync 定时任务执行报错, 原因:"+e.getMessage());
+        }
+        log.info("WbsTreeContractStatistics.scheduledSync 定时任务结束执行, 时间:" + LocalDateTime.now());
+    }
+
+    @Override
+    @Async
+    public void updateInformationQueryStatus(List<WbsTreeContractStatisticsDTO> wbsTreeContractStatisticsDTOs) {
+        if (wbsTreeContractStatisticsDTOs == null || wbsTreeContractStatisticsDTOs.isEmpty()) {
+            return;
+        }
+        for (WbsTreeContractStatisticsDTO dto : wbsTreeContractStatisticsDTOs) {
+            try {
+                wbsTreeContractStatisticsService.updateInformationNumber(dto.getPKeyId(), dto.getClassify(), dto.getContractId());
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    @Override
+    @Async
+    public void updateInformationQueryStatusByTaskId(String taskIds) {
+        if (taskIds != null && !taskIds.isEmpty()) {
+            String[] taskIdList = taskIds.split(",");
+            List<InformationQuery> queryList = jdbcTemplate.query("select wbs_id, classify, contract_id from u_information_query where id in (select form_data_id from u_task where  id in (?) and is_deleted = 0) and is_deleted = 0 group by contract_id,wbs_id,classify",
+                    new Object[]{String.join(",", taskIdList)}, new BeanPropertyRowMapper<>(InformationQuery.class));
+            if (!queryList.isEmpty()) {
+                for (InformationQuery query : queryList) {
+                    try {
+                        wbsTreeContractStatisticsService.updateInformationNumber(query.getWbsId(), query.getClassify(), query.getContractId());
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    @Async
+    public void updateWbsTreeContractNodes(String nodeIds) {
+        if (nodeIds != null && !nodeIds.isEmpty()) {
+            String[] pKeyIds = nodeIds.split(",");
+            for (String pKeyId : pKeyIds) {
+                try {
+                    wbsTreeContractStatisticsService.insertWbsTreeContractStatistics(Long.parseLong(pKeyId), 0);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    @Override
+    @Async
+    public void delWbsTreeContractNodes(String nodeIds) {
+        if (nodeIds != null && !nodeIds.isEmpty()) {
+            String[] pKeyIds = nodeIds.split(",");
+            for (String pKeyId : pKeyIds) {
+                try {
+                    wbsTreeContractStatisticsService.insertWbsTreeContractStatistics(Long.parseLong(pKeyId), 1);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    @Async
+    @Override
+    public void recycleWbsTreeContractNodes(String nodeIds) {
+        if (nodeIds != null && !nodeIds.isEmpty()) {
+            String[] pKeyIds = nodeIds.split(",");
+            for (String pKeyId : pKeyIds) {
+                try {
+                    wbsTreeContractStatisticsService.recycleWbsTreeContractStatistics(Long.parseLong(pKeyId));
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    @Override
+    @Async
+    public void statisticsContract(Long contractId) {
+        wbsTreeContractStatisticsService.statisticsContract(contractId);
+    }
+}

+ 19 - 0
blade-service/blade-business/src/main/java/org/springblade/business/mapper/WbsTreeContractStatisticsMapper.java

@@ -0,0 +1,19 @@
+package org.springblade.business.mapper;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
+import org.springblade.business.entity.WbsTreeContractStatistics;
+
+public interface WbsTreeContractStatisticsMapper extends BaseMapper<WbsTreeContractStatistics> {
+
+    WbsTreeContractStatistics getByIdOnLock(Long id);
+
+    @Select("select id, project_id, contract_id, is_deleted, `status`, create_time,  update_time, parent_id, ancestors, leaf_num, fill_num, approve_num, complete_num, jl_fill_num, jl_approve_num, jl_complete_num, is_leaf from wbs_tree_contract_statistics where id = #{id}")
+    WbsTreeContractStatistics getByIdOnIgnoreDeleted(Long id);
+
+
+    @Update("update wbs_tree_contract_statistics set is_deleted = 0 where id = #{pKeyId}")
+    Boolean updateDeleteStatus(Long pKeyId);
+}

+ 31 - 0
blade-service/blade-business/src/main/java/org/springblade/business/mapper/WbsTreeContractStatisticsMapper.xml

@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.business.mapper.WbsTreeContractStatisticsMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="ResultMap" type="org.springblade.business.entity.WbsTreeContractStatistics">
+        <result column="id" property="id"/>
+        <result column="project_id" property="projectId"/>
+        <result column="contract_id" property="contractId"/>
+        <result column="is_deleted" property="isDeleted"/>
+        <result column="status" property="status"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_time" property="updateTime"/>
+        <result column="parent_id" property="parentId"/>
+        <result column="ancestors" property="ancestors"/>
+        <result column="leaf_num" property="leafNum"/>
+        <result column="fill_num" property="fillNum"/>
+        <result column="is_leaf" property="isLeaf"/>
+        <result column="approve_num" property="approveNum"/>
+        <result column="complete_num" property="completeNum"/>
+        <result column="jl_fill_num" property="jlFillNum"/>
+        <result column="jl_approve_num" property="jlApproveNum"/>
+        <result column="jl_complete_num" property="jlCompleteNum"/>
+    </resultMap>
+    <sql id="includeSql">
+        id, project_id, contract_id, is_deleted, `status`, create_time,  update_time, parent_id, ancestors, leaf_num, fill_num, approve_num, complete_num, jl_fill_num, jl_approve_num, jl_complete_num, is_leaf
+    </sql>
+    <select id="getByIdOnLock" resultMap="ResultMap">
+        select <include refid="includeSql"/> from m_wbs_tree_contract_statistics where id = #{id} for update
+    </select>
+</mapper>

+ 16 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/IWbsTreeContractStatisticsService.java

@@ -0,0 +1,16 @@
+package org.springblade.business.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.springblade.business.entity.WbsTreeContractStatistics;
+
+public interface IWbsTreeContractStatisticsService extends IService<WbsTreeContractStatistics> {
+
+    Boolean updateInformationNumber(Long wbsId, Integer classify, Long contractId);
+
+    Boolean insertWbsTreeContractStatistics(Long wbsTreeContractPkeyId, Integer isDelete);
+
+    Boolean recycleWbsTreeContractStatistics(Long pKeyId);
+    void statisticsContract(Long contractId);
+
+    void sync();
+}

+ 3 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TaskServiceImpl.java

@@ -16,6 +16,7 @@ import org.springblade.archive.entity.ArchiveProjectConfig;
 import org.springblade.archive.feign.ArchiveAutoClient;
 import org.springblade.business.dto.*;
 import org.springblade.business.entity.*;
+import org.springblade.business.feignClient.WbsTreeContractStatisticsClientImpl;
 import org.springblade.business.mapper.TaskMapper;
 import org.springblade.business.mapper.TrialSelfInspectionRecordMapper;
 import org.springblade.business.service.*;
@@ -132,6 +133,7 @@ public class TaskServiceImpl extends BaseServiceImpl<TaskMapper, Task> implement
     private final NewIOSSClient newIOSSClient;
     private final WbsTreePrivateClient wbsTreePrivateClient;
     private final TrialSelfInspectionRecordMapper trialSelfInspectionRecordMapper;
+    private final WbsTreeContractStatisticsClientImpl wbsTreeContractStatisticsClient;
     //超级管理员的角色id
     private final String SUPER_ADMIN_ROLE_ID ="1123598816738675201";
     //泓创智诚公司的部门id
@@ -761,6 +763,7 @@ public class TaskServiceImpl extends BaseServiceImpl<TaskMapper, Task> implement
                         }
                     }
                 }
+                wbsTreeContractStatisticsClient.updateInformationQueryStatusByTaskId(String.join(",", taskIds));
             }
         }
     }

+ 590 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/WbsTreeContractStatisticsServiceImpl.java

@@ -0,0 +1,590 @@
+package org.springblade.business.service.impl;
+
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springblade.business.entity.InformationQuery;
+import org.springblade.business.entity.WbsTreeContractStatistics;
+import org.springblade.business.mapper.WbsTreeContractStatisticsMapper;
+import org.springblade.business.service.IWbsTreeContractStatisticsService;
+import org.springblade.core.tool.utils.BeanUtil;
+import org.springblade.core.tool.utils.ObjectUtil;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.manager.entity.ContractInfo;
+import org.springblade.manager.entity.WbsTreeContract;
+import org.springblade.manager.vo.WbsTreeContractLazyQueryInfoVO;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.support.TransactionTemplate;
+
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
+
+@Service
+@AllArgsConstructor
+public class WbsTreeContractStatisticsServiceImpl extends ServiceImpl<WbsTreeContractStatisticsMapper, WbsTreeContractStatistics> implements IWbsTreeContractStatisticsService {
+
+    private final JdbcTemplate jdbcTemplate;
+    private final TransactionTemplate transactionTemplate;
+    private static final Logger log = LoggerFactory.getLogger(WbsTreeContractStatisticsServiceImpl.class);
+
+
+
+
+    @Override
+    public Boolean updateInformationNumber(Long wbsId, Integer classify, Long contractId) {
+        InformationQuery query = getInformationQueryByWbsId(wbsId, classify, contractId);
+        if (query == null || query.getStatus() == null) {
+            return false;
+        }
+        Integer status = query.getStatus();
+        WbsTreeContractStatistics contractStatistics = this.getById(wbsId);
+        if (contractStatistics == null) {
+            insertWbsTreeContractStatistics(wbsId, 0);
+        }
+        return transactionTemplate.execute(transactionStatus -> {
+            WbsTreeContractStatistics lock = this.baseMapper.getByIdOnLock(wbsId);
+            if (lock == null) {
+                return false;
+            }
+            String ancestors = lock.getAncestors();
+            if (ancestors == null || !ancestors.isEmpty()) {
+                return false;
+            }
+            String[] ids = ancestors.split(",");
+            List<Long> collect = Arrays.stream(ids).filter(item -> !item.equals("0") && StringUtil.isNumeric(item)).map(Long::parseLong).collect(Collectors.toList());
+            if (classify == 1) {
+                // 施工
+                if (status == 0 || status == 3) {
+                    //  fill_num == 0 && approve_num == 0 && complete_num == 0 更新当前节点 set fill_num = 1, approve_num = 0, complete_num = 0  并更新父级节点 set fill_num = fill_num + 1
+                    //  fill_num == 1 && approve_num == 0 && complete_num == 0 不更新
+                    //  fill_num == 0 && approve_num == 1 && complete_num == 0 更新当前节点 set fill_num = 1, approve_num = 0, complete_num = 0  并更新父级节点 set fill_num = fill_num + 1, approve_num = approve_num - 1
+                    //  fill_num == 0 && approve_num == 0 && complete_num == 1 更新当前节点 set fill_num = 1, approve_num = 0, complete_num = 0 并更新父级节点 set fill_num = fill_num + 1, complete_num = complete_num - 1
+                    this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().eq(WbsTreeContractStatistics::getId, wbsId)
+                            .set(WbsTreeContractStatistics::getFillNum, 1).set(WbsTreeContractStatistics::getApproveNum, 0).set(WbsTreeContractStatistics::getCompleteNum, 0));
+                    if (lock.getFillNum() == 0 && lock.getApproveNum() == 0 && lock.getCompleteNum() == 0) {
+                        this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().in(WbsTreeContractStatistics::getId, collect).setSql("fill_num = fill_num + 1"));
+                    } else if (lock.getFillNum() == 0 && lock.getApproveNum() == 1 && lock.getCompleteNum() == 0) {
+                        this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().in(WbsTreeContractStatistics::getId, collect).setSql("fill_num = fill_num + 1, approve_num = approve_num - 1"));
+                    } else if (lock.getFillNum() == 0 && lock.getApproveNum() == 0 && lock.getCompleteNum() == 1) {
+                        this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().in(WbsTreeContractStatistics::getId, collect).setSql("fill_num = fill_num + 1, complete_num = complete_num - 1"));
+                    }
+                } else if (status == 1) {
+                    this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().eq(WbsTreeContractStatistics::getId, wbsId)
+                            .set(WbsTreeContractStatistics::getFillNum, 0).set(WbsTreeContractStatistics::getApproveNum, 1).set(WbsTreeContractStatistics::getCompleteNum, 0));
+                    if (lock.getFillNum() == 0 && lock.getApproveNum() == 0 && lock.getCompleteNum() == 0) {
+                        this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().in(WbsTreeContractStatistics::getId, collect).setSql("approve_num = approve_num + 1"));
+                    } else if (lock.getFillNum() == 1 && lock.getApproveNum() == 0 && lock.getCompleteNum() == 0) {
+                        this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().in(WbsTreeContractStatistics::getId, collect).setSql("fill_num = fill_num - 1, approve_num = approve_num + 1"));
+                    } else if (lock.getFillNum() == 0 && lock.getApproveNum() == 0 && lock.getCompleteNum() == 1) {
+                        this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().in(WbsTreeContractStatistics::getId, collect).setSql("fill_num = fill_num + 1, complete_num = complete_num - 1"));
+                    }
+                } else if (status == 2) {
+                    this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().eq(WbsTreeContractStatistics::getId, wbsId)
+                            .set(WbsTreeContractStatistics::getFillNum, 0).set(WbsTreeContractStatistics::getApproveNum, 0).set(WbsTreeContractStatistics::getCompleteNum, 1));
+                    if (lock.getFillNum() == 0 && lock.getApproveNum() == 0 && lock.getCompleteNum() == 0) {
+                        this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().in(WbsTreeContractStatistics::getId, collect).setSql("complete_num = complete_num + 1"));
+                    } else if (lock.getFillNum() == 1 && lock.getApproveNum() == 0 && lock.getCompleteNum() == 0) {
+                        this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().in(WbsTreeContractStatistics::getId, collect).setSql("fill_num = fill_num - 1, complete_num = complete_num + 1"));
+                    } else if (lock.getFillNum() == 0 && lock.getApproveNum() == 1 && lock.getCompleteNum() == 0) {
+                        this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().in(WbsTreeContractStatistics::getId, collect).setSql("approve_num = approve_num - 1, complete_num = complete_num + 1"));
+                    }
+                }
+            } else if (classify == 2) {
+                // 监理
+                if (status == 0 || status == 3) {
+                    this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().eq(WbsTreeContractStatistics::getId, wbsId)
+                            .set(WbsTreeContractStatistics::getJlFillNum, 1).set(WbsTreeContractStatistics::getJlApproveNum, 0).set(WbsTreeContractStatistics::getJlCompleteNum, 0));
+                    if (lock.getJlFillNum() == 0 && lock.getJlApproveNum() == 0 && lock.getJlCompleteNum() == 0) {
+                        this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().in(WbsTreeContractStatistics::getId, collect).setSql("jl_fill_num = jl_fill_num + 1"));
+                    } else if (lock.getJlFillNum() == 0 && lock.getJlApproveNum() == 1 && lock.getJlCompleteNum() == 0) {
+                        this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().in(WbsTreeContractStatistics::getId, collect).setSql("jl_fill_num = jl_fill_num + 1, jl_approve_num = jl_approve_num - 1"));
+                    } else if (lock.getJlFillNum() == 0 && lock.getJlApproveNum() == 0 && lock.getJlCompleteNum() == 1) {
+                        this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().in(WbsTreeContractStatistics::getId, collect).setSql("jl_fill_num = jl_fill_num + 1, jl_complete_num = jl_complete_num - 1"));
+                    }
+                } else if (status == 1) {
+                    this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().eq(WbsTreeContractStatistics::getId, wbsId)
+                            .set(WbsTreeContractStatistics::getJlFillNum, 0).set(WbsTreeContractStatistics::getJlApproveNum, 1).set(WbsTreeContractStatistics::getJlCompleteNum, 0));
+                    if (lock.getJlFillNum() == 0 && lock.getJlApproveNum() == 0 && lock.getJlCompleteNum() == 0) {
+                        this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().in(WbsTreeContractStatistics::getId, collect).setSql("jl_approve_num = jl_approve_num + 1"));
+                    } else if (lock.getJlFillNum() == 1 && lock.getJlApproveNum() == 0 && lock.getJlCompleteNum() == 0) {
+                        this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().in(WbsTreeContractStatistics::getId, collect).setSql("jl_fill_num = jl_fill_num - 1, jl_approve_num = jl_approve_num + 1"));
+                    } else if (lock.getJlFillNum() == 0 && lock.getJlApproveNum() == 0 && lock.getJlCompleteNum() == 1) {
+                        this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().in(WbsTreeContractStatistics::getId, collect).setSql("jl_approve_num = jl_approve_num - 1, jl_complete_num = jl_complete_num + 1"));
+                    }
+                } else if (status == 2) {
+                    this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().eq(WbsTreeContractStatistics::getId, wbsId)
+                            .set(WbsTreeContractStatistics::getJlFillNum, 0).set(WbsTreeContractStatistics::getJlApproveNum, 0).set(WbsTreeContractStatistics::getJlCompleteNum, 1));
+                    if (lock.getJlFillNum() == 0 && lock.getJlApproveNum() == 0 && lock.getJlCompleteNum() == 0) {
+                        this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().in(WbsTreeContractStatistics::getId, collect).setSql("jl_complete_num = jl_complete_num + 1"));
+                    } else if (lock.getJlFillNum() == 1 && lock.getJlApproveNum() == 0 && lock.getJlCompleteNum() == 0) {
+                        this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().in(WbsTreeContractStatistics::getId, collect).setSql("jl_fill_num = jl_fill_num - 1, jl_complete_num = jl_complete_num + 1"));
+                    } else if (lock.getJlFillNum() == 0 && lock.getJlApproveNum() == 1 && lock.getJlCompleteNum() == 0) {
+                        this.update(Wrappers.<WbsTreeContractStatistics>lambdaUpdate().in(WbsTreeContractStatistics::getId, collect).setSql("jl_approve_num = jl_approve_num - 1, jl_complete_num = jl_complete_num + 1"));
+                    }
+                }
+            }
+            return true;
+        });
+    }
+    @Override
+    public Boolean insertWbsTreeContractStatistics(Long wbsTreeContractPkeyId, Integer isDelete) {
+        if (isDelete == 1) {
+            return this.removeById(wbsTreeContractPkeyId);
+        }
+        WbsTreeContract wbsTreeContract = getWbsTreeContractByPKeyId(wbsTreeContractPkeyId);
+        if (wbsTreeContract == null) {
+            return false;
+        }
+        WbsTreeContractStatistics wbsTreeContractStatistics = this.getById(wbsTreeContractPkeyId);
+        if (wbsTreeContractStatistics != null) {
+            return true;
+        }
+        wbsTreeContractStatistics = createWbsTreeContractStatistics(wbsTreeContract);
+        // 查询父级节点存不存在,不存在则创建
+        List<WbsTreeContractStatistics> parentList = new ArrayList<>();
+        createWbsTreeContractStatisticsParent(wbsTreeContract, wbsTreeContractStatistics, parentList);
+        if (!parentList.isEmpty()) {
+            for (int i = 1; i < parentList.size(); i++) {
+                WbsTreeContractStatistics statistics = parentList.get(i);
+                WbsTreeContractStatistics parent = parentList.get(i - 1);
+                if (parent != null && StringUtil.hasText(parent.getAncestors())) {
+                    statistics.setAncestors(parent.getAncestors() + "," + parent.getId());
+                    statistics.setParentId(parent.getId());
+                }
+            }
+        }
+        // 查询有没有子节点,子节点是否存在
+        createWbsTreeContractStatisticsChildren(wbsTreeContract, wbsTreeContractStatistics, parentList);
+        parentList.add(wbsTreeContractStatistics);
+        saveBatch(parentList);
+        return true;
+    }
+
+    @Override
+    public Boolean recycleWbsTreeContractStatistics(Long pKeyId) {
+        WbsTreeContractStatistics wbsTreeContractStatistics = this.baseMapper.getByIdOnIgnoreDeleted(pKeyId);
+        if (wbsTreeContractStatistics == null) {
+            insertWbsTreeContractStatistics(pKeyId, 0);
+        }
+        return this.baseMapper.updateDeleteStatus(pKeyId);
+    }
+
+    public void createWbsTreeContractStatisticsParent(WbsTreeContract wbsTreeContract, WbsTreeContractStatistics wbsTreeContractStatistics, List<WbsTreeContractStatistics> wbsTreeContractStatisticsList) {
+        if (wbsTreeContract.getParentId() == null || wbsTreeContract.getParentId() <= 0) {
+            wbsTreeContractStatistics.setParentId(0L);
+            wbsTreeContractStatistics.setAncestors("");
+            return;
+        }
+        WbsTreeContractStatistics parent = this.getById(wbsTreeContractStatistics.getParentId());
+        if (parent == null) {
+            WbsTreeContract wbsTreeContractParent = getWbsTreeContractByPKeyId(wbsTreeContractStatistics.getParentId());
+            if (wbsTreeContractParent == null) {
+                return;
+            }
+            parent = createWbsTreeContractStatistics(wbsTreeContractParent);
+            createWbsTreeContractStatisticsParent(wbsTreeContractParent, parent, wbsTreeContractStatisticsList);
+            wbsTreeContractStatisticsList.add(parent);
+        } else {
+            if (StringUtil.hasText(wbsTreeContract.getAncestors())) {
+                wbsTreeContractStatistics.setParentId(parent.getId());
+                wbsTreeContractStatistics.setAncestors(parent.getAncestors() + "," + parent.getId());
+            }
+        }
+    }
+
+    public void createWbsTreeContractStatisticsChildren(WbsTreeContract wbsTreeContract, WbsTreeContractStatistics wbsTreeContractStatistics, List<WbsTreeContractStatistics> wbsTreeContractStatisticsList) {
+        List<WbsTreeContract> wbsTreeContracts =  jdbcTemplate.query("select * from m_wbs_tree_contract where is_deleted = 0 and type = 1 and contract_id = ? and p_id = ?",
+                new Object[]{wbsTreeContract.getContractId(), wbsTreeContract.getPKeyId()}, new BeanPropertyRowMapper<>(WbsTreeContract.class));
+        if (wbsTreeContracts == null || wbsTreeContracts.isEmpty()) {
+            wbsTreeContractStatistics.setIsLeaf(1);
+            wbsTreeContractStatistics.setLeafNum(0);
+            return;
+        }
+        wbsTreeContracts.forEach(item -> {
+            WbsTreeContractStatistics statistics = createWbsTreeContractStatistics(item);
+            createWbsTreeContractStatisticsChildren(item, wbsTreeContractStatistics, wbsTreeContractStatisticsList);
+            statistics.setAncestors(wbsTreeContractStatistics.getAncestors() + "," + wbsTreeContractStatistics.getId());
+            statistics.setParentId(wbsTreeContractStatistics.getId());
+            wbsTreeContractStatisticsList.add(statistics);
+            int num = wbsTreeContractStatistics.getLeafNum() == null ? 0 : wbsTreeContractStatistics.getLeafNum();
+            int i = statistics.getLeafNum() == 0 ? 1 : statistics.getLeafNum();
+            wbsTreeContractStatistics.setLeafNum(num + i);
+        });
+    }
+
+    /**
+     * 同步
+     */
+    public void sync() {
+        List<ContractInfo> contractInfos = jdbcTemplate.query("select id from m_contract_info where is_deleted = 0 and p_id in (select id from m_project_info where is_deleted = 0)", new BeanPropertyRowMapper<>(ContractInfo.class));
+        if (contractInfos.isEmpty()) {
+            return;
+        }
+        for (ContractInfo contractInfo : contractInfos) {
+            statisticsContract(contractInfo.getId());
+        }
+    }
+
+    @Override
+    public void statisticsContract(Long contractId) {
+        try {
+            List<WbsTreeContract> wbsTreeContracts =  jdbcTemplate.query("select * from m_wbs_tree_contract where is_deleted = 0 and type = 1 and status = 1 and contract_id = ? ",
+                    new Object[]{contractId}, new BeanPropertyRowMapper<>(WbsTreeContract.class));
+
+            List<WbsTreeContractStatistics> addWbsTreeContractStatistics = new ArrayList<>(wbsTreeContracts.size());
+            {
+                List<WbsTreeContractDto> contractDtoList = chickTreeAncestors(wbsTreeContracts);
+                for (WbsTreeContractDto dto : contractDtoList) {
+                    addWbsTreeContractStatistics.add(createWbsTreeContractStatistics(dto));
+                }
+            }
+            // 统计叶子节点数量
+//            countLeafNum(addWbsTreeContractStatistics);
+            useIsLeafFieldCountLeafNum(addWbsTreeContractStatistics);
+            countInformationNumber(addWbsTreeContractStatistics, contractId);
+            List<WbsTreeContractStatistics> updateWbsTreeContractStatistics = new ArrayList<>();
+            List<WbsTreeContractStatistics> wbsTreeContractStatistics = this.list(Wrappers.<WbsTreeContractStatistics>lambdaQuery().eq(WbsTreeContractStatistics::getContractId, contractId).eq(WbsTreeContractStatistics::getIsDeleted, 0));
+            Map<Long, WbsTreeContractStatistics> map = wbsTreeContractStatistics.stream().collect(Collectors.toMap(WbsTreeContractStatistics::getId, v -> v));
+            addWbsTreeContractStatistics.removeIf(item -> {
+                WbsTreeContractStatistics statistics = map.get(item.getId());
+                if (statistics == null) {
+                    return false;
+                }
+                if (updateWbsTreeContractStatisticsFields(statistics, item)) {
+                    updateWbsTreeContractStatistics.add(item);
+                }
+                return true;
+            });
+            if (!addWbsTreeContractStatistics.isEmpty()) {
+                saveBatch(addWbsTreeContractStatistics);
+            }
+            if (!updateWbsTreeContractStatistics.isEmpty()) {
+                updateBatchById(updateWbsTreeContractStatistics);
+            }
+        } catch (Exception e) {
+            log.error("更新合同段wbs树统计信息异常", e);
+        }
+    }
+
+    private boolean updateWbsTreeContractStatisticsFields(WbsTreeContractStatistics old, WbsTreeContractStatistics newObj) {
+        boolean result = false;
+        if (ObjectUtil.nullSafeEquals(old.getParentId(), newObj.getParentId())) {
+            newObj.setParentId(null);
+        } else {
+            result = true;
+        }
+        if (ObjectUtil.nullSafeEquals(old.getAncestors(), newObj.getAncestors())) {
+            newObj.setAncestors(null);
+        } else {
+            result = true;
+        }
+        if (ObjectUtil.nullSafeEquals(old.getIsLeaf(), newObj.getIsLeaf())) {
+            newObj.setIsLeaf(null);
+        } else {
+            result = true;
+        }
+        if (ObjectUtil.nullSafeEquals(old.getLeafNum(), newObj.getLeafNum())) {
+            newObj.setLeafNum(null);
+        } else {
+            result = true;
+        }
+        if (ObjectUtil.nullSafeEquals(old.getFillNum(), newObj.getFillNum())) {
+            newObj.setFillNum(null);
+        } else {
+            result = true;
+        }
+        if (ObjectUtil.nullSafeEquals(old.getApproveNum(), newObj.getApproveNum())) {
+            newObj.setApproveNum(null);
+        } else {
+            result = true;
+        }
+        if (ObjectUtil.nullSafeEquals(old.getCompleteNum(), newObj.getCompleteNum())) {
+            newObj.setCompleteNum(null);
+        } else {
+            result = true;
+        }
+        if (ObjectUtil.nullSafeEquals(old.getJlFillNum(), newObj.getJlFillNum())) {
+            newObj.setJlFillNum(null);
+        } else {
+            result = true;
+        }
+        if (ObjectUtil.nullSafeEquals(old.getJlApproveNum(), newObj.getJlApproveNum())) {
+            newObj.setJlApproveNum(null);
+        } else {
+            result = true;
+        }
+        if (ObjectUtil.nullSafeEquals(old.getJlCompleteNum(), newObj.getJlCompleteNum())) {
+            newObj.setJlCompleteNum(null);
+        } else {
+            result = true;
+        }
+        newObj.setStatus(null);
+        newObj.setIsDeleted(null);
+        newObj.setCreateTime(null);
+        newObj.setUpdateTime(null);
+        newObj.setProjectId( null);
+        newObj.setContractId( null);
+        return result;
+    }
+    private void countInformationNumber(List<WbsTreeContractStatistics> wbsTreeContractStatistics, Long contractId) {
+        if (wbsTreeContractStatistics == null || wbsTreeContractStatistics.isEmpty()) {
+            return;
+        }
+        // 统计已填报,待审批,已审批数量
+        List<WbsTreeContractLazyQueryInfoVO> sgQueryInfoList = jdbcTemplate.query(
+                    "SELECT wbs_id, `status` FROM u_information_query WHERE id in (SELECT id from (SELECT max(id) as id FROM u_information_query WHERE is_deleted = 0 AND type = 1 AND contract_id = ? AND classify = ? GROUP BY wbs_id) as a)",
+                    new Object[]{contractId, 1},
+                    new BeanPropertyRowMapper<>(WbsTreeContractLazyQueryInfoVO.class));
+        List<WbsTreeContractLazyQueryInfoVO> jlQueryInfoList = jdbcTemplate.query(
+                "SELECT wbs_id, `status` FROM u_information_query WHERE id in (SELECT id from (SELECT max(id) as id FROM u_information_query WHERE is_deleted = 0 AND type = 1 AND contract_id = ? AND classify = ? GROUP BY wbs_id) as a)",
+                new Object[]{contractId, 2},
+                new BeanPropertyRowMapper<>(WbsTreeContractLazyQueryInfoVO.class));
+        if (sgQueryInfoList.isEmpty() && jlQueryInfoList.isEmpty()) {
+            return;
+        }
+        Map<Long, WbsTreeContractStatistics> map = wbsTreeContractStatistics.stream().collect(Collectors.toMap(WbsTreeContractStatistics::getId, item -> item, (k1, k2) -> k1));
+        Map<Long, Map<Integer, AtomicInteger>> sgStatisticsMap = countInformation(sgQueryInfoList, map);
+        Map<Long, Map<Integer, AtomicInteger>> jlStatisticsMap = countInformation(jlQueryInfoList, map);
+        wbsTreeContractStatistics.forEach(item -> {
+            Map<Integer, AtomicInteger> sgStatusMap = sgStatisticsMap.get(item.getId());
+            if (sgStatusMap != null && !sgStatusMap.isEmpty()) {
+                AtomicInteger integer = sgStatusMap.get(0);
+                if (integer != null) {
+                    item.setFillNum(integer.get());
+                }
+                integer = sgStatusMap.get(1);
+                if (integer != null) {
+                    item.setApproveNum(integer.get());
+                }
+                integer = sgStatusMap.get(2);
+                if (integer != null) {
+                    item.setCompleteNum(integer.get());
+                }
+            }
+            Map<Integer, AtomicInteger> jlStatusMap = jlStatisticsMap.get(item.getId());
+            if (jlStatusMap != null && !jlStatusMap.isEmpty()) {
+                AtomicInteger integer = jlStatusMap.get(0);
+                if (integer != null) {
+                    item.setJlFillNum(integer.get());
+                }
+                integer = jlStatusMap.get(1);
+                if (integer != null) {
+                    item.setJlApproveNum(integer.get());
+                }
+                integer = jlStatusMap.get(2);
+                if (integer != null) {
+                    item.setJlCompleteNum(integer.get());
+                }
+            }
+        });
+    }
+
+    private static Map<Long, Map<Integer, AtomicInteger>> countInformation(List<WbsTreeContractLazyQueryInfoVO> queryInfoList, Map<Long, WbsTreeContractStatistics> map) {
+        if (queryInfoList == null || queryInfoList.isEmpty()) {
+            return new HashMap<>();
+        }
+        Map<Long, Map<Integer, AtomicInteger>> statisticsMap = new HashMap<>();
+        Map<Long, Integer> sgStatusMap = queryInfoList.stream().peek(item -> {
+            if (item.getStatus() == null || item.getStatus() == 3) {
+                item.setStatus(0);
+            }
+        }).collect(Collectors.toMap(WbsTreeContractLazyQueryInfoVO::getWbsId, WbsTreeContractLazyQueryInfoVO::getStatus));
+        sgStatusMap.forEach((wbsId, status) -> {
+            put(wbsId, status, statisticsMap);
+            WbsTreeContractStatistics statistics = map.get(wbsId);
+            if (statistics == null || statistics.getAncestors() == null || statistics.getAncestors().isEmpty()) {
+                return;
+            }
+            String[] split = statistics.getAncestors().split(",");
+            for (String s : split) {
+                if (!StringUtil.isNumeric(s)) {
+                    continue;
+                }
+                Long id = Long.parseLong(s);
+                put(id, status, statisticsMap);
+            }
+        });
+        return statisticsMap;
+    }
+
+    private static void put(Long wbsId, Integer status, Map<Long, Map<Integer, AtomicInteger>> statisticsMap) {
+        Map<Integer, AtomicInteger> map = statisticsMap.get(wbsId);
+        if (map == null) {
+            map = new HashMap<>();
+        }
+        AtomicInteger count = map.get(status);
+        if (count == null) {
+            count = new AtomicInteger(0);
+        }
+        count.incrementAndGet();
+        map.put(status, count);
+        statisticsMap.put(wbsId, map);
+    }
+
+    /**
+     * 统计叶子节点数量 - 全量
+     */
+    public void countLeafNum(List<WbsTreeContractStatistics> wbsTreeContractStatistics) {
+        Map<Long, List<WbsTreeContractStatistics>> map = wbsTreeContractStatistics.stream().peek(item -> {
+            if (item.getParentId() == null) {
+                item.setParentId(0L);
+            }
+        }).collect(Collectors.groupingBy(WbsTreeContractStatistics::getParentId));
+        List<WbsTreeContractStatistics> list = map.get(0L);
+        if (list != null && !list.isEmpty()) {
+            list.forEach(item -> item.setLeafNum(countLeafNum(map.get(item.getId()), map)));
+        }
+    }
+    public Integer countLeafNum(List<WbsTreeContractStatistics> wbsTreeContracts, Map<Long, List<WbsTreeContractStatistics>> map) {
+        if (wbsTreeContracts == null || wbsTreeContracts.isEmpty()) {
+            return 0;
+        }
+        wbsTreeContracts.forEach(item -> item.setLeafNum(countLeafNum(map.get(item.getId()), map)));
+        return wbsTreeContracts.stream().mapToInt(item -> item.getLeafNum() == null || item.getLeafNum() == 0 ? 1 :item.getLeafNum()).sum();
+    }
+    /**
+     * 统计叶子节点数量 - 全量
+     */
+    public void useIsLeafFieldCountLeafNum(List<WbsTreeContractStatistics> wbsTreeContractStatistics) {
+        Map<Long, AtomicInteger> countMap = new HashMap<>();
+        Map<Long, WbsTreeContractStatistics> map = wbsTreeContractStatistics.stream().peek(item -> {
+            if (item.getIsLeaf() != null && item.getIsLeaf() == 1 && StringUtil.hasText(item.getAncestors())) {
+                String[] split = item.getAncestors().split(",");
+                for (String s : split) {
+                    if (s != null && !s.isEmpty()) {
+                        long id = Long.parseLong(s);
+                        if (id == 0) continue;
+                        AtomicInteger num = countMap.get(id);
+                        if (num == null) {
+                            num = new AtomicInteger(0);
+                        }
+                        num.incrementAndGet();
+                        countMap.put(id, num);
+                    }
+                }
+            }
+        }).collect(Collectors.toMap(WbsTreeContractStatistics::getId, item -> item, (k1, k2) -> k1));
+        countMap.forEach((k, v) -> {
+            WbsTreeContractStatistics statistics = map.get(k);
+            if (statistics != null) {
+                statistics.setLeafNum(v.get());
+            }
+        });
+    }
+
+    private  List<WbsTreeContractDto> chickTreeAncestors(List<WbsTreeContract> wbsTreeContracts) {
+        if (wbsTreeContracts == null || wbsTreeContracts.isEmpty()) {
+            return new ArrayList<>();
+        }
+        List<WbsTreeContractDto> contractNodes = wbsTreeContracts.stream().map(item -> BeanUtil.copyProperties(item, WbsTreeContractDto.class)).collect(Collectors.toList());
+        {
+            Map<Long, List<WbsTreeContractDto>> mapByParentId = contractNodes.stream().peek(item -> {
+                if (item.getParentId() == null) {
+                    item.setParentId(0L);
+                }
+                if (item.getPId() == null) {
+                    item.setPId(0L);
+                }
+            }).collect(Collectors.groupingBy(WbsTreeContractDto::getParentId));
+            List<WbsTreeContractDto> list = mapByParentId.get(0L);
+            list.forEach(item -> item.setAncestorsByParentId("0"));
+            Queue<WbsTreeContractDto> queue = new LinkedList<>(list);
+            while (!queue.isEmpty()) {
+                WbsTreeContractDto poll = queue.poll();
+                List<WbsTreeContractDto> children = mapByParentId.get(poll.getId());
+                if (children != null && !children.isEmpty()) {
+                    for (WbsTreeContractDto child : children) {
+                        child.setAncestorsByParentId(poll.getAncestorsByParentId() + "," + poll.getPKeyId());
+                        child.setTempPId(poll.getPKeyId());
+                        queue.offer(child);
+                    }
+                } else {
+                    poll.setIsLeaf(1);
+                }
+            }
+        }
+//        {
+//            Map<Long, List<WbsTreeContractDto>> mapByParentId = contractNodes.stream().collect(Collectors.groupingBy(WbsTreeContractDto::getPId));
+//            List<WbsTreeContractDto> list = mapByParentId.get(0L);
+//            list.forEach(item -> item.setAncestorsByPid("0"));
+//            Queue<WbsTreeContractDto> queue = new LinkedList<>(list);
+//            while (!queue.isEmpty()) {
+//                WbsTreeContractDto poll = queue.poll();
+//                List<WbsTreeContractDto> children = mapByParentId.get(poll.getPKeyId());
+//                if (children != null && !children.isEmpty()) {
+//                    for (WbsTreeContractDto child : children) {
+//                        child.setAncestorsByPid(poll.getAncestorsByPid() + "," + poll.getPKeyId());
+//                        queue.offer(child);
+//                    }
+//                }else {
+//                    poll.setIsLeaf(1);
+//                }
+//            }
+//        }
+//        for (WbsTreeContractDto node : contractNodes) {
+//            if (!StringUtil.equals(node.getAncestorsByParentId(), node.getAncestorsByPid())) {
+//                log.error("数据错误:" + node);
+//            } else if (!StringUtil.equals(node.getAncestorsByParentId(), node.getAncestors())){
+//                log.error("数据错误:" + node + " ancestorsPid=" + node.getAncestorsPId());
+//            }
+//        }
+        return contractNodes;
+    }
+
+    private WbsTreeContract getWbsTreeContractByPKeyId(Long pKeyId) {
+        List<WbsTreeContract> query = jdbcTemplate.query("select * from m_wbs_tree_contract where p_key_id = ?", new Object[]{pKeyId}, new BeanPropertyRowMapper<>(WbsTreeContract.class));
+        if (!query.isEmpty()) {
+            return query.get(0);
+        }
+        return null;
+    }
+
+    private WbsTreeContractStatistics createWbsTreeContractStatistics(WbsTreeContract wbsTreeContract) {
+        return new WbsTreeContractStatistics(wbsTreeContract.getPKeyId(), wbsTreeContract.getProjectId(), wbsTreeContract.getContractId(), wbsTreeContract.getParentId(), wbsTreeContract.getAncestors());
+    }
+    private WbsTreeContractStatistics createWbsTreeContractStatistics(WbsTreeContractDto wbsTreeContract) {
+        return new WbsTreeContractStatistics(wbsTreeContract.getPKeyId(), wbsTreeContract.getProjectId(), wbsTreeContract.getContractId(), wbsTreeContract.getTempPId(), wbsTreeContract.getAncestorsByParentId(), wbsTreeContract.getIsLeaf());
+    }
+
+    private InformationQuery getInformationQueryByWbsId(Long wbsId, Integer classify, Long contractId) {
+        List<InformationQuery> queryList = jdbcTemplate.query(
+                "SELECT wbs_id, classify, `status` FROM u_information_query WHERE id in (SELECT id from (SELECT max(id) as id FROM u_information_query WHERE is_deleted = 0 AND type = 1 AND contract_id = ? AND classify = ? and wbs_id = ?) as a)",
+                new Object[]{contractId, classify, wbsId},
+                new BeanPropertyRowMapper<>(InformationQuery.class));
+        if (!queryList.isEmpty()) {
+            return queryList.get(0);
+        }
+        return null;
+    }
+
+    @Data
+    private static class WbsTreeContractDto extends WbsTreeContract {
+        private List<WbsTreeContractDto> children;
+        private String ancestorsByParentId;
+        private String ancestorsByPid;
+        private Long tempPId;
+        // 1 是叶子节点, 0 不是叶子节点
+        private Integer isLeaf = 0;
+
+        @Override
+        public String toString() {
+            return "WbsTreeContractDto{" +
+                    "pKeyId=" + super.getPKeyId() +
+                    ", pId=" + super.getPId() +
+                    ", parentId=" + super.getParentId() +
+                    ", id=" + super.getId() +
+                    ", ancestorsByParentId='" + ancestorsByParentId + '\'' +
+                    ", ancestorsByPid='" + ancestorsByPid + '\'' +
+                    '}';
+        }
+    }
+
+}

+ 1 - 0
blade-service/blade-e-visa/src/main/java/org/springblade/evisa/service/impl/EVDataServiceImpl.java

@@ -376,6 +376,7 @@ public class EVDataServiceImpl implements EVDataService {
                 }
             }
             RedisTemplate.delete("sign-" + taskApp.getFormDataId());
+            RedisTemplate.opsForList().rightPush("information_query_status_statistics_key", taskApp.getTaskId());
             Thread.sleep(1000);
         } catch (Exception e) {
             RedisTemplate.delete("sign-" + taskApp.getFormDataId());

+ 10 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java

@@ -32,10 +32,12 @@ import org.jsoup.nodes.Document;
 import org.jsoup.nodes.Element;
 import org.jsoup.nodes.Node;
 import org.jsoup.select.Elements;
+import org.springblade.business.dto.WbsTreeContractStatisticsDTO;
 import org.springblade.business.entity.ContractLog;
 import org.springblade.business.entity.InformationQuery;
 import org.springblade.business.feign.ContractLogClient;
 import org.springblade.business.feign.InformationQueryClient;
+import org.springblade.business.feign.WbsTreeContractStatisticsClient;
 import org.springblade.business.vo.SaveContractLogVO;
 import org.springblade.common.constant.CommonConstant;
 import org.springblade.common.utils.*;
@@ -173,6 +175,8 @@ public class ExcelTabController extends BladeController {
     private final WbsTreeContractMapper wbsTreeContractMapper;
 
     private final WbsTreeContractOldHtmlService wbsTreeContractOldHtmlService;
+    private final WbsTreeContractStatisticsClient wbsTreeContractStatisticsClient;
+
 
     @Autowired
     StringRedisTemplate RedisTemplate;
@@ -2125,6 +2129,12 @@ public class ExcelTabController extends BladeController {
         executionTime.info("---PDF合并耗时---");
         //更新缓存
         informationQueryClient.delAsyncWbsTree(contractId);
+        try {
+            WbsTreeContractStatisticsDTO dto = new WbsTreeContractStatisticsDTO(Long.parseLong(contractId), Long.parseLong(nodeId), Integer.parseInt(classify));
+            wbsTreeContractStatisticsClient.updateInformationQueryStatus(Collections.singletonList(dto));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
         executionTime.info("缓存删除耗时");
         executionTime.brief();
         return R.data(result.getMsg());

+ 3 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeContractServiceImpl.java

@@ -35,6 +35,7 @@ import org.springblade.business.entity.ConstructionLedger;
 import org.springblade.business.entity.InformationQuery;
 import org.springblade.business.feign.ConstructionLedgerFeignClient;
 import org.springblade.business.feign.InformationQueryClient;
+import org.springblade.business.feign.WbsTreeContractStatisticsClient;
 import org.springblade.business.vo.QueryProcessDataVO;
 import org.springblade.common.constant.CommonConstant;
 import org.springblade.common.utils.Colour;
@@ -115,6 +116,7 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
     private final ITableFileService tableFileService;
     private final TableInfoMapper  tableInfoMapper;
     private final WbsFormElementMapper wbsFormElementMapper;
+    private final WbsTreeContractStatisticsClient wbsTreeContractStatisticsClient;
 
 
     @Autowired
@@ -433,6 +435,7 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
 
         //更新Redis缓存
         informationQueryClient.delAsyncWbsTree(pawDTO.getContractId());
+        wbsTreeContractStatisticsClient.statisticsContract(Long.parseLong(pawDTO.getContractId()));
         return true;
     }
 

+ 20 - 20
blade-service/blade-user/src/main/java/org/springblade/system/user/controller/WbsTreeController.java

@@ -79,18 +79,18 @@ public class WbsTreeController extends BladeController {
         } else if (("2").equals(classifyType)) {
             dataInfoId = contractIdRelation + "_" + parentId + "_" + "1" + "_" + tableOwner;
         }
-        Object data = null;
-        if (ObjectUtil.isNotEmpty(dataInfoId)) {
-            if (("2").equals(classifyType) && ObjectUtil.isNotEmpty(contractIdRelation)) {
-                data = redisTemplate.opsForValue().get("blade-manager::contract:wbstree:" + dataInfoId);
-            } else if (("1").equals(classifyType)) {
-                data = redisTemplate.opsForValue().get("blade-manager::contract:wbstree:" + dataInfoId);
-                redisTemplate.delete("blade-manager::contract:wbstree:" + dataInfoId);
-            }
-        }
-        if (data != null) {
-            vos = JSON.parseArray(data.toString(), WbsTreeContractLazyVO.class);
-        } else {
+//        Object data = null;
+//        if (ObjectUtil.isNotEmpty(dataInfoId)) {
+//            if (("2").equals(classifyType) && ObjectUtil.isNotEmpty(contractIdRelation)) {
+//                data = redisTemplate.opsForValue().get("blade-manager::contract:wbstree:" + dataInfoId);
+//            } else if (("1").equals(classifyType)) {
+//                data = redisTemplate.opsForValue().get("blade-manager::contract:wbstree:" + dataInfoId);
+//                redisTemplate.delete("blade-manager::contract:wbstree:" + dataInfoId);
+//            }
+//        }
+//        if (data != null) {
+//            vos = JSON.parseArray(data.toString(), WbsTreeContractLazyVO.class);
+//        } else {
             vos = iUserService.lazyQueryContractWbsTree(parentId, contractId, contractIdRelation, tableOwner,description);
             if (vos != null && ObjectUtil.isNotEmpty(dataInfoId)) {
 
@@ -106,14 +106,14 @@ public class WbsTreeController extends BladeController {
                 //对结果进行排序
                 vos.sort(safeComparator);
 
-                if (("2").equals(classifyType) && ObjectUtil.isNotEmpty(contractIdRelation)) {
-                    JSONArray array = JSONArray.parseArray(JSON.toJSONString(vos));
-                    redisTemplate.opsForValue().set("blade-manager::contract:wbstree:" + dataInfoId, JSON.toJSON(array).toString());
-                } else if (("1").equals(classifyType)) {
-                    JSONArray array = JSONArray.parseArray(JSON.toJSONString(vos));
-                    redisTemplate.opsForValue().set("blade-manager::contract:wbstree:" + dataInfoId, JSON.toJSON(array).toString());
-                }
-            }
+//                if (("2").equals(classifyType) && ObjectUtil.isNotEmpty(contractIdRelation)) {
+//                    JSONArray array = JSONArray.parseArray(JSON.toJSONString(vos));
+//                    redisTemplate.opsForValue().set("blade-manager::contract:wbstree:" + dataInfoId, JSON.toJSON(array).toString());
+//                } else if (("1").equals(classifyType)) {
+//                    JSONArray array = JSONArray.parseArray(JSON.toJSONString(vos));
+//                    redisTemplate.opsForValue().set("blade-manager::contract:wbstree:" + dataInfoId, JSON.toJSON(array).toString());
+//                }
+//            }
         }
         return R.data(vos);
     }

+ 214 - 180
blade-service/blade-user/src/main/java/org/springblade/system/user/service/impl/UserServiceImpl.java

@@ -13,10 +13,7 @@ import lombok.AllArgsConstructor;
 import org.apache.http.client.utils.DateUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springblade.business.entity.InformationQuery;
-import org.springblade.business.entity.Task;
-import org.springblade.business.entity.TaskParallel;
-import org.springblade.business.entity.TreeContractFirst;
+import org.springblade.business.entity.*;
 import org.springblade.business.vo.InformationQueryVO;
 import org.springblade.business.vo.QueryProcessDataVO;
 import org.springblade.common.constant.CommonConstant;
@@ -797,84 +794,73 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
                     }
                     if (lazyNodes.size() > 0) {
                         /*获取当前合同段节点本地缓存信息*/
-                        List<WbsTreeContractLazyVO> nodesAll = this.getNodeAll(contractId);
-                        List<WbsTreeContractLazyVO> distinctNodesAll = nodesAll.stream()
-                                .collect(Collectors.collectingAndThen(
-                                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(WbsTreeContractLazyVO::getPKeyId))),
-                                        ArrayList::new
-                                ));
-                        List<WbsTreeContractLazyVO> distinctLowestNodesAll = distinctNodesAll.stream().filter(f -> f.getHasChildren().equals(0))
-                                .collect(Collectors.collectingAndThen(
-                                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(WbsTreeContractLazyVO::getPKeyId))),
-                                        ArrayList::new
-                                ));
-
-                        /*获取当前合同段节点对应的资料填报QueryInfo本地缓存信息*/
-                        List<WbsTreeContractLazyQueryInfoVO> queryInfoList = this.getQueryInfoList(contractId, tableOwner);
-                        Map<Long, Integer> queryInfoMaps = queryInfoList.stream().filter(f -> Func.isNotEmpty(f.getWbsId())&&Func.isNotEmpty(f.getStatus()))
-                                .collect(Collectors.toMap(WbsTreeContractLazyQueryInfoVO::getWbsId, WbsTreeContractLazyQueryInfoVO::getStatus, (existingValue, newValue) -> existingValue));
-//                        List<Long> pKeyIdList = new ArrayList<>(queryInfoMaps.keySet());
-
-                        /* ================ 处理数量 ================ */
-                        List<WbsTreeContractLazyVO> lowestNodesTB = distinctLowestNodesAll.parallelStream().filter(f -> queryInfoMaps.containsKey(f.getPKeyId())).collect(Collectors.toList());
-                        List<Long> lowestNodeParentIdsTB = lowestNodesTB.parallelStream().map(WbsTreeContractLazyVO::getParentId).collect(Collectors.toList());
-                        List<WbsTreeContractLazyVO> resultParentNodesTB = this.getCachedParentCountNodes(contractId, lowestNodeParentIdsTB, nodesAll, tableOwner);
-                        Map<Long, WbsTreeContractLazyVO> lowestNodesMap = lowestNodesTB.stream()
-                                .peek(vo -> {
-                                    Integer colorStatus = queryInfoMaps.get(vo.getPKeyId());
-                                    if (colorStatus != null) {
-                                        vo.setColorStatus(colorStatus == 0 ? 2 : (colorStatus == 1 ? 3 : (colorStatus == 2 ? 4 : 2)));
-                                    } else {
-                                        vo.setColorStatus(1);
-                                    }
-                                }).collect(Collectors.toMap(WbsTreeContractLazyVO::getPKeyId, Function.identity()));
-
-                        /* ================ 处理颜色 ================ */
-                        long startTime = System.currentTimeMillis();
-//                        List<NodeVO> nodeVOList = distinctNodesAll.stream().map(this::convertToNodeVO).collect(Collectors.toList());
-//                        Map<Long, NodeVO> nodeVOMap = nodeVOList.stream().collect(Collectors.toMap(NodeVO::getId, vo -> vo, (existing, replacement) -> existing));
-//                        List<NodeVO> treeNodeVOList = this.buildNodeTreeByStream1(distinctNodesAll, lowestNodesMap);
-//                        NodeVO.calculateStatusToDFS(treeNodeVOList, nodeVOMap);
-                        Map<Long, Integer> nodeColorStatusMap = new HashMap<>();
-//                        NodeVO.calculateStatusToDFS1(treeNodeVOList, nodeColorStatusMap);
-//                        buildNodeTreeByStream(distinctNodesAll, lowestNodesMap, nodeColorStatusMap);
-                        buildNodeTreeAndCalculateStatus(distinctNodesAll, lowestNodesMap, nodeColorStatusMap);
-                        // 将树形结构展开成列表
-//                        List<NodeVO> nodeVOS = this.flattenTree(treeNodeVOList);
-//                        Map<Long, Integer> nodeColorStatusMap = nodeVOS.stream().collect(Collectors.toMap(NodeVO::getPKeyId, NodeVO::getStatus, (existing, replacement) -> existing));
-                        long endTime = System.currentTimeMillis();
-                        long executionTime = endTime - startTime;
-                        _logger.info("合同段 " + contractId + " 处理颜色 执行时间:" + executionTime + " ms");
+//                        List<WbsTreeContractLazyVO> nodesAll = this.getNodeAll(contractId);
+//                        List<WbsTreeContractLazyVO> distinctNodesAll = nodesAll.stream()
+//                                .collect(Collectors.collectingAndThen(
+//                                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(WbsTreeContractLazyVO::getPKeyId))),
+//                                        ArrayList::new
+//                                ));
+//                        List<WbsTreeContractLazyVO> distinctLowestNodesAll = distinctNodesAll.stream().filter(f -> f.getHasChildren().equals(0))
+//                                .collect(Collectors.collectingAndThen(
+//                                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(WbsTreeContractLazyVO::getPKeyId))),
+//                                        ArrayList::new
+//                                ));
+//
+//                        /*获取当前合同段节点对应的资料填报QueryInfo本地缓存信息*/
+//                        List<WbsTreeContractLazyQueryInfoVO> queryInfoList = this.getQueryInfoList(contractId, tableOwner);
+//                        Map<Long, Integer> queryInfoMaps = queryInfoList.stream().filter(f -> Func.isNotEmpty(f.getWbsId())&&Func.isNotEmpty(f.getStatus()))
+//                                .collect(Collectors.toMap(WbsTreeContractLazyQueryInfoVO::getWbsId, WbsTreeContractLazyQueryInfoVO::getStatus, (existingValue, newValue) -> existingValue));
+////                        List<Long> pKeyIdList = new ArrayList<>(queryInfoMaps.keySet());
+//
+//                        /* ================ 处理数量 ================ */
+//                        List<WbsTreeContractLazyVO> lowestNodesTB = distinctLowestNodesAll.parallelStream().filter(f -> queryInfoMaps.containsKey(f.getPKeyId())).collect(Collectors.toList());
+//                        List<Long> lowestNodeParentIdsTB = lowestNodesTB.parallelStream().map(WbsTreeContractLazyVO::getParentId).collect(Collectors.toList());
+//                        List<WbsTreeContractLazyVO> resultParentNodesTB = this.getCachedParentCountNodes(contractId, lowestNodeParentIdsTB, nodesAll, tableOwner);
+//                        Map<Long, WbsTreeContractLazyVO> lowestNodesMap = lowestNodesTB.stream()
+//                                .peek(vo -> {
+//                                    Integer colorStatus = queryInfoMaps.get(vo.getPKeyId());
+//                                    if (colorStatus != null) {
+//                                        vo.setColorStatus(colorStatus == 0 ? 2 : (colorStatus == 1 ? 3 : (colorStatus == 2 ? 4 : 2)));
+//                                    } else {
+//                                        vo.setColorStatus(1);
+//                                    }
+//                                }).collect(Collectors.toMap(WbsTreeContractLazyVO::getPKeyId, Function.identity()));
+//
+//                        /* ================ 处理颜色 ================ */
+//                        long startTime = System.currentTimeMillis();
+////                        List<NodeVO> nodeVOList = distinctNodesAll.stream().map(this::convertToNodeVO).collect(Collectors.toList());
+////                        Map<Long, NodeVO> nodeVOMap = nodeVOList.stream().collect(Collectors.toMap(NodeVO::getId, vo -> vo, (existing, replacement) -> existing));
+////                        List<NodeVO> treeNodeVOList = this.buildNodeTreeByStream1(distinctNodesAll, lowestNodesMap);
+////                        NodeVO.calculateStatusToDFS(treeNodeVOList, nodeVOMap);
+//                        Map<Long, Integer> nodeColorStatusMap = new HashMap<>();
+////                        NodeVO.calculateStatusToDFS1(treeNodeVOList, nodeColorStatusMap);
+////                        buildNodeTreeByStream(distinctNodesAll, lowestNodesMap, nodeColorStatusMap);
+//                        buildNodeTreeAndCalculateStatus(distinctNodesAll, lowestNodesMap, nodeColorStatusMap);
+//                        // 将树形结构展开成列表
+////                        List<NodeVO> nodeVOS = this.flattenTree(treeNodeVOList);
+////                        Map<Long, Integer> nodeColorStatusMap = nodeVOS.stream().collect(Collectors.toMap(NodeVO::getPKeyId, NodeVO::getStatus, (existing, replacement) -> existing));
+//                        long endTime = System.currentTimeMillis();
+//                        long executionTime = endTime - startTime;
+//                        _logger.info("合同段 " + contractId + " 处理颜色 执行时间:" + executionTime + " ms");
                         /* ================ 处理最终结果集 ================ */
-                        if (lazyNodes.size() > 0) {
-                            Map<Long, Integer> countMap = new HashMap<>();
-                            for (WbsTreeContractLazyVO node : resultParentNodesTB) {
-                                Long key = node.getPKeyId();
-                                if (countMap.containsKey(key)) {
-                                    countMap.put(key, countMap.get(key) + 1);
-                                } else {
-                                    countMap.put(key, 1);
-                                }
-                            }
-                            for (WbsTreeContractLazyVO lazyNodeVO : lazyNodes) {
+//                        if (lazyNodes.size() > 0) {
+//                            Map<Long, Integer> countMap = new HashMap<>();
+//                            for (WbsTreeContractLazyVO node : resultParentNodesTB) {
+//                                Long key = node.getPKeyId();
+//                                if (countMap.containsKey(key)) {
+//                                    countMap.put(key, countMap.get(key) + 1);
+//                                } else {
+//                                    countMap.put(key, 1);
+//                                }
+//                            }
+                        String pKeyIds = lazyNodes.stream().map(item -> item.getPKeyId() + "").collect(Collectors.joining(","));
+                        List<WbsTreeContractStatistics> wbsTreeContractStatisticsList = jdbcTemplate.query("select id, leaf_num, fill_num, approve_num, complete_num from m_wbs_tree_contract_statistics where id in (" + pKeyIds + ")",
+                                new BeanPropertyRowMapper<>(WbsTreeContractStatistics.class));
+                        Map<Long, WbsTreeContractStatistics> wbsTreeContractStatisticsMap = wbsTreeContractStatisticsList.stream().collect(Collectors.toMap(WbsTreeContractStatistics::getId, item -> item));
+                        setPrivateTemplate(lazyNodes);
+                        for (WbsTreeContractLazyVO lazyNodeVO : lazyNodes) {
                                 if(lazyNodeVO.getIsCustom()!=null&&lazyNodeVO.getIsCustom()==1){
                                     lazyNodeVO.setPrivateTemplate("当前节点为自定义节点,无法定位后管位置");
-                                }else {
-                                    try {
-                                        if(lazyNodeVO.getIsTypePrivatePid()!=null){
-                                            String privateSql="select p_key_id, ancestors_p_id from m_wbs_tree_private where p_key_id="+lazyNodeVO.getIsTypePrivatePid()+" and is_deleted=0";
-                                            WbsTreePrivate ancestor = jdbcTemplate.queryForObject(privateSql,new BeanPropertyRowMapper<>(WbsTreePrivate.class));
-                                            String ancestorsPId=ancestor.getAncestorsPId()+","+ancestor.getPKeyId();
-                                            String privateNodeNameSql="select node_name from m_wbs_tree_private where p_key_id in ("+ancestorsPId+")";
-                                            List<String> wbsTreePrivates = jdbcTemplate.query(privateNodeNameSql,new SingleColumnRowMapper<>(String.class));
-                                            if(wbsTreePrivates.size()>0){
-                                                String result = wbsTreePrivates.stream().collect(Collectors.joining("/"));
-                                                lazyNodeVO.setPrivateTemplate(result);
-                                            }
-                                        }
-                                    } catch (Exception e) {
-                                        lazyNodeVO.setPrivateTemplate("");
-                                    }
                                 }
                                 lazyNodeVO.setNotExsitChild(!lazyNodeVO.getHasChildren().equals(1));
                                 lazyNodeVO.setPrimaryKeyId(lazyNodeVO.getPKeyId());
@@ -883,25 +869,32 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
                                         lazyNodeVO.setTitle(contractInfo.getContractName());
                                     }
                                 }
-
-                                lazyNodeVO.setSubmitCounts(cn.hutool.core.util.ObjectUtil.isNotEmpty(countMap.get(lazyNodeVO.getPKeyId())) ? countMap.get(lazyNodeVO.getPKeyId()) : (cn.hutool.core.util.ObjectUtil.isNotEmpty(queryInfoMaps.get(lazyNodeVO.getPKeyId())) ? 1 : 0));
-
-                                if (lazyNodeVO.getSubmitCounts().equals(0)) {
-                                    lazyNodeVO.setColorStatus(1);
-                                    continue;
-                                }
-
-                                Integer parentColorStatus = nodeColorStatusMap.get(lazyNodeVO.getPKeyId());
-                                if (parentColorStatus != null) {
-                                    lazyNodeVO.setColorStatus(parentColorStatus);
+                                WbsTreeContractStatistics statistics = wbsTreeContractStatisticsMap.get(lazyNodeVO.getPKeyId());
+                                if (statistics != null) {
+                                    lazyNodeVO.setSubmitCounts(statistics.calculateSubmitNums(tableOwner));
+                                    lazyNodeVO.setColorStatus(statistics.calculateColorStatus(tableOwner));
                                 } else {
-                                    WbsTreeContractLazyVO lowestNode = lowestNodesMap.get(lazyNodeVO.getPKeyId());
-                                    if (lowestNode != null) {
-                                        lazyNodeVO.setColorStatus(lowestNode.getColorStatus());
-                                    }
+                                    lazyNodeVO.setSubmitCounts(0);
+                                    lazyNodeVO.setColorStatus(1);
                                 }
-
-                            }
+//                                lazyNodeVO.setSubmitCounts(cn.hutool.core.util.ObjectUtil.isNotEmpty(countMap.get(lazyNodeVO.getPKeyId())) ? countMap.get(lazyNodeVO.getPKeyId()) : (cn.hutool.core.util.ObjectUtil.isNotEmpty(queryInfoMaps.get(lazyNodeVO.getPKeyId())) ? 1 : 0));
+
+//                                if (lazyNodeVO.getSubmitCounts().equals(0)) {
+//                                    lazyNodeVO.setColorStatus(1);
+//                                    continue;
+//                                }
+//
+//                                Integer parentColorStatus = nodeColorStatusMap.get(lazyNodeVO.getPKeyId());
+//                                if (parentColorStatus != null) {
+//                                    lazyNodeVO.setColorStatus(parentColorStatus);
+//                                } else {
+//                                    WbsTreeContractLazyVO lowestNode = lowestNodesMap.get(lazyNodeVO.getPKeyId());
+//                                    if (lowestNode != null) {
+//                                        lazyNodeVO.setColorStatus(lowestNode.getColorStatus());
+//                                    }
+//                                }
+
+//                            }
                         }
                         return lazyNodes;
                     }
@@ -943,77 +936,65 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
 //                                    " ORDER BY a.sort,title,a.create_time";
                             List<WbsTreeContractLazyVO> lazyNodes = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(WbsTreeContractLazyVO.class));
                             if (lazyNodes.size() > 0) {
-                                List<WbsTreeContractLazyVO> nodesAll = this.getNodeAll(sgContractId);
-                                List<WbsTreeContractLazyVO> distinctNodesAll = nodesAll.stream()
-                                        .collect(Collectors.collectingAndThen(
-                                                Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(WbsTreeContractLazyVO::getPKeyId))),
-                                                ArrayList::new
-                                        ));
-                                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<WbsTreeContractLazyQueryInfoVO> queryInfoList = this.getQueryInfoList(sgContractId, tableOwner);
-
-                                Map<Long, Integer> queryInfoMaps = queryInfoList.stream().filter(f -> cn.hutool.core.util.ObjectUtil.isNotEmpty(f.getWbsId()))
-                                        .collect(Collectors.toMap(WbsTreeContractLazyQueryInfoVO::getWbsId, WbsTreeContractLazyQueryInfoVO::getStatus, (existingValue, newValue) -> existingValue));
-//                                List<Long> pKeyIdList = new ArrayList<>(queryInfoMaps.keySet());
-
-                                List<WbsTreeContractLazyVO> lowestNodesTB = distinctLowestNodesAll.parallelStream().filter(f -> queryInfoMaps.containsKey(f.getPKeyId())).collect(Collectors.toList());
-                                List<Long> lowestNodeParentIdsTB = lowestNodesTB.parallelStream().map(WbsTreeContractLazyVO::getParentId).collect(Collectors.toList());
-                                List<WbsTreeContractLazyVO> resultParentNodesTB = this.getCachedParentCountNodes(sgContractId, lowestNodeParentIdsTB, nodesAll, tableOwner);
-                                Map<Long, WbsTreeContractLazyVO> lowestNodesMap = lowestNodesTB.stream()
-                                        .peek(vo -> {
-                                            Integer colorStatus = queryInfoMaps.get(vo.getPKeyId());
-                                            if (colorStatus != null) {
-                                                vo.setColorStatus(colorStatus == 0 ? 2 : (colorStatus == 1 ? 3 : (colorStatus == 2 ? 4 : 2)));
-                                            } else {
-                                                vo.setColorStatus(1);
-                                            }
-                                        }).collect(Collectors.toMap(WbsTreeContractLazyVO::getPKeyId, Function.identity()));
-
-//                                List<NodeVO> nodeVOList = distinctNodesAll.stream().map(this::convertToNodeVO).collect(Collectors.toList());
-//                                Map<Long, NodeVO> nodeVOMap = nodeVOList.stream().collect(Collectors.toMap(NodeVO::getId, vo -> vo, (existing, replacement) -> existing));
-//                                List<NodeVO> treeNodeVOList = this.buildNodeTreeByStream1(distinctNodesAll, lowestNodesMap);
-//                                NodeVO.calculateStatusToDFS(treeNodeVOList, nodeVOMap);
-//                                List<NodeVO> nodeVOS = this.flattenTree(treeNodeVOList);
-//                                Map<Long, Integer> nodeColorStatusMap = nodeVOS.stream().collect(Collectors.toMap(NodeVO::getPKeyId, NodeVO::getStatus, (existing, replacement) -> existing));
-                                Map<Long, Integer> nodeColorStatusMap = new HashMap<>();
-//                                NodeVO.calculateStatusToDFS1(treeNodeVOList, nodeColorStatusMap);
-//                                buildNodeTreeByStream(distinctNodesAll, lowestNodesMap, nodeColorStatusMap);
-                                buildNodeTreeAndCalculateStatus(distinctNodesAll, lowestNodesMap, nodeColorStatusMap);
-                                if (lazyNodes.size() > 0) {
-                                    Map<Long, Integer> countMap = new HashMap<>();
-                                    for (WbsTreeContractLazyVO node : resultParentNodesTB) {
-                                        Long key = node.getPKeyId();
-                                        if (countMap.containsKey(key)) {
-                                            countMap.put(key, countMap.get(key) + 1);
-                                        } else {
-                                            countMap.put(key, 1);
-                                        }
-                                    }
-
+//                                List<WbsTreeContractLazyVO> nodesAll = this.getNodeAll(sgContractId);
+//                                List<WbsTreeContractLazyVO> distinctNodesAll = nodesAll.stream()
+//                                        .collect(Collectors.collectingAndThen(
+//                                                Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(WbsTreeContractLazyVO::getPKeyId))),
+//                                                ArrayList::new
+//                                        ));
+//                                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<WbsTreeContractLazyQueryInfoVO> queryInfoList = this.getQueryInfoList(sgContractId, tableOwner);
+//
+//                                Map<Long, Integer> queryInfoMaps = queryInfoList.stream().filter(f -> cn.hutool.core.util.ObjectUtil.isNotEmpty(f.getWbsId()))
+//                                        .collect(Collectors.toMap(WbsTreeContractLazyQueryInfoVO::getWbsId, WbsTreeContractLazyQueryInfoVO::getStatus, (existingValue, newValue) -> existingValue));
+////                                List<Long> pKeyIdList = new ArrayList<>(queryInfoMaps.keySet());
+//
+//                                List<WbsTreeContractLazyVO> lowestNodesTB = distinctLowestNodesAll.parallelStream().filter(f -> queryInfoMaps.containsKey(f.getPKeyId())).collect(Collectors.toList());
+//                                List<Long> lowestNodeParentIdsTB = lowestNodesTB.parallelStream().map(WbsTreeContractLazyVO::getParentId).collect(Collectors.toList());
+//                                List<WbsTreeContractLazyVO> resultParentNodesTB = this.getCachedParentCountNodes(sgContractId, lowestNodeParentIdsTB, nodesAll, tableOwner);
+//                                Map<Long, WbsTreeContractLazyVO> lowestNodesMap = lowestNodesTB.stream()
+//                                        .peek(vo -> {
+//                                            Integer colorStatus = queryInfoMaps.get(vo.getPKeyId());
+//                                            if (colorStatus != null) {
+//                                                vo.setColorStatus(colorStatus == 0 ? 2 : (colorStatus == 1 ? 3 : (colorStatus == 2 ? 4 : 2)));
+//                                            } else {
+//                                                vo.setColorStatus(1);
+//                                            }
+//                                        }).collect(Collectors.toMap(WbsTreeContractLazyVO::getPKeyId, Function.identity()));
+//
+////                                List<NodeVO> nodeVOList = distinctNodesAll.stream().map(this::convertToNodeVO).collect(Collectors.toList());
+////                                Map<Long, NodeVO> nodeVOMap = nodeVOList.stream().collect(Collectors.toMap(NodeVO::getId, vo -> vo, (existing, replacement) -> existing));
+////                                List<NodeVO> treeNodeVOList = this.buildNodeTreeByStream1(distinctNodesAll, lowestNodesMap);
+////                                NodeVO.calculateStatusToDFS(treeNodeVOList, nodeVOMap);
+////                                List<NodeVO> nodeVOS = this.flattenTree(treeNodeVOList);
+////                                Map<Long, Integer> nodeColorStatusMap = nodeVOS.stream().collect(Collectors.toMap(NodeVO::getPKeyId, NodeVO::getStatus, (existing, replacement) -> existing));
+//                                Map<Long, Integer> nodeColorStatusMap = new HashMap<>();
+////                                NodeVO.calculateStatusToDFS1(treeNodeVOList, nodeColorStatusMap);
+////                                buildNodeTreeByStream(distinctNodesAll, lowestNodesMap, nodeColorStatusMap);
+//                                buildNodeTreeAndCalculateStatus(distinctNodesAll, lowestNodesMap, nodeColorStatusMap);
+//                                if (lazyNodes.size() > 0) {
+//                                    Map<Long, Integer> countMap = new HashMap<>();
+//                                    for (WbsTreeContractLazyVO node : resultParentNodesTB) {
+//                                        Long key = node.getPKeyId();
+//                                        if (countMap.containsKey(key)) {
+//                                            countMap.put(key, countMap.get(key) + 1);
+//                                        } else {
+//                                            countMap.put(key, 1);
+//                                        }
+//                                    }
+                                String pKeyIds = lazyNodes.stream().map(item -> item.getPKeyId() + "").collect(Collectors.joining(","));
+                                List<WbsTreeContractStatistics> wbsTreeContractStatisticsList = jdbcTemplate.query("select id, leaf_num, fill_num, approve_num, complete_num from m_wbs_tree_contract_statistics where id in (" + pKeyIds + ")",
+                                        new BeanPropertyRowMapper<>(WbsTreeContractStatistics.class));
+                                Map<Long, WbsTreeContractStatistics> wbsTreeContractStatisticsMap = wbsTreeContractStatisticsList.stream().collect(Collectors.toMap(WbsTreeContractStatistics::getId, item -> item));
+                                setPrivateTemplate(lazyNodes);
                                     for (WbsTreeContractLazyVO lazyNodeVO : lazyNodes) {
                                         if(lazyNodeVO.getIsCustom()!=null&&lazyNodeVO.getIsCustom()==1){
                                             lazyNodeVO.setPrivateTemplate("当前节点为自定义节点,无法定位后管位置");
-                                        }else {
-                                            try {
-                                                if(lazyNodeVO.getIsTypePrivatePid()!=null){
-                                                    String privateSql="select p_key_id, ancestors_p_id from m_wbs_tree_private where p_key_id="+lazyNodeVO.getIsTypePrivatePid()+" and is_deleted=0";
-                                                    WbsTreePrivate ancestor = jdbcTemplate.queryForObject(privateSql,new BeanPropertyRowMapper<>(WbsTreePrivate.class));
-                                                    String ancestorsPId=ancestor.getAncestorsPId()+","+ancestor.getPKeyId();
-                                                    String privateNodeNameSql="select node_name from m_wbs_tree_private where p_key_id in ("+ancestorsPId+")";
-                                                    List<String> wbsTreePrivates = jdbcTemplate.query(privateNodeNameSql,new SingleColumnRowMapper<>(String.class));
-                                                    if(wbsTreePrivates.size()>0){
-                                                        String result = wbsTreePrivates.stream().collect(Collectors.joining("/"));
-                                                        lazyNodeVO.setPrivateTemplate(result);
-                                                    }
-                                                }
-                                            } catch (Exception e) {
-                                                lazyNodeVO.setPrivateTemplate("");
-                                            }
                                         }
                                         lazyNodeVO.setType(lazyNodeVO.getNodeType());
                                         lazyNodeVO.setNotExsitChild(!lazyNodeVO.getHasChildren().equals(1));
@@ -1024,24 +1005,31 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
                                                 lazyNodeVO.setTitle(sgContractInfo.getContractName());
                                             }
                                         }
-
-                                        lazyNodeVO.setSubmitCounts(cn.hutool.core.util.ObjectUtil.isNotEmpty(countMap.get(lazyNodeVO.getPKeyId())) ? countMap.get(lazyNodeVO.getPKeyId()) : (cn.hutool.core.util.ObjectUtil.isNotEmpty(queryInfoMaps.get(lazyNodeVO.getPKeyId())) ? 1 : 0));
-                                        if (lazyNodeVO.getSubmitCounts().equals(0)) {
-                                            lazyNodeVO.setColorStatus(1);
-                                            continue;
-                                        }
-
-                                        Integer parentColorStatus = nodeColorStatusMap.get(lazyNodeVO.getPKeyId());
-                                        if (parentColorStatus != null) {
-                                            lazyNodeVO.setColorStatus(parentColorStatus);
+                                        WbsTreeContractStatistics statistics = wbsTreeContractStatisticsMap.get(lazyNodeVO.getPKeyId());
+                                        if (statistics != null) {
+                                            lazyNodeVO.setSubmitCounts(statistics.calculateSubmitNums(tableOwner));
+                                            lazyNodeVO.setColorStatus(statistics.calculateColorStatus(tableOwner));
                                         } else {
-                                            WbsTreeContractLazyVO lowestNode = lowestNodesMap.get(lazyNodeVO.getPKeyId());
-                                            if (lowestNode != null) {
-                                                lazyNodeVO.setColorStatus(lowestNode.getColorStatus());
-                                            }
+                                            lazyNodeVO.setSubmitCounts(0);
+                                            lazyNodeVO.setColorStatus(1);
                                         }
-
-                                    }
+//                                        lazyNodeVO.setSubmitCounts(cn.hutool.core.util.ObjectUtil.isNotEmpty(countMap.get(lazyNodeVO.getPKeyId())) ? countMap.get(lazyNodeVO.getPKeyId()) : (cn.hutool.core.util.ObjectUtil.isNotEmpty(queryInfoMaps.get(lazyNodeVO.getPKeyId())) ? 1 : 0));
+//                                        if (lazyNodeVO.getSubmitCounts().equals(0)) {
+//                                            lazyNodeVO.setColorStatus(1);
+//                                            continue;
+//                                        }
+//
+//                                        Integer parentColorStatus = nodeColorStatusMap.get(lazyNodeVO.getPKeyId());
+//                                        if (parentColorStatus != null) {
+//                                            lazyNodeVO.setColorStatus(parentColorStatus);
+//                                        } else {
+//                                            WbsTreeContractLazyVO lowestNode = lowestNodesMap.get(lazyNodeVO.getPKeyId());
+//                                            if (lowestNode != null) {
+//                                                lazyNodeVO.setColorStatus(lowestNode.getColorStatus());
+//                                            }
+//                                        }
+
+//                                    }
                                 }
                                 lazyNodesAll.addAll(lazyNodes);
                             }
@@ -1053,6 +1041,52 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
         }
         return null;
     }
+    private void setPrivateTemplate(List<WbsTreeContractLazyVO> lazyNodes) {
+        if (lazyNodes != null && !lazyNodes.isEmpty()) {
+            try {
+                String privateIds = lazyNodes.stream().filter(vo -> vo.getIsTypePrivatePid() != null).map(vo -> vo.getIsTypePrivatePid() + "").distinct().collect(Collectors.joining(","));
+                List<WbsTreePrivate> query = new ArrayList<>();
+                if (!privateIds.isEmpty()) {
+                    String privateSql="select p_key_id, ancestors_p_id, node_name from m_wbs_tree_private where p_key_id in ("+privateIds+") and is_deleted=0";
+                    query = jdbcTemplate.query(privateSql, new BeanPropertyRowMapper<>(WbsTreePrivate.class));
+                    if (!query.isEmpty()) {
+                        Set<String> privateIdSet = new HashSet<>();
+                        query.forEach(wbsTreePrivate -> {
+                            String[] split = wbsTreePrivate.getAncestorsPId().split(",");
+                            for (String s : split) {
+                                if (StringUtils.isNotEmpty(s)) {
+                                    privateIdSet.add(s);
+                                }
+                            }
+                        });
+                        String privateNodeNameSql="select p_key_id, node_name from m_wbs_tree_private where p_key_id in ("+String.join(",",privateIdSet)+")";
+                        List<WbsTreePrivate> wbsTreePrivates = jdbcTemplate.query(privateNodeNameSql,new BeanPropertyRowMapper<>(WbsTreePrivate.class));
+                        query.addAll(wbsTreePrivates);
+                    }
+                }
+                Map<Long, WbsTreePrivate> map = query.stream().collect(Collectors.toMap(WbsTreePrivate::getPKeyId, v -> v, (v1, v2) -> v2));
+                lazyNodes.forEach(lazyNodeVO -> {
+                    WbsTreePrivate treePrivate = map.get(lazyNodeVO.getPKeyId());
+                    if (treePrivate == null || treePrivate.getAncestorsPId() == null) {
+                        lazyNodeVO.setPrivateTemplate("");
+                        return;
+                    }
+                    StringBuilder sb = new StringBuilder();
+                    String[] split = treePrivate.getAncestorsPId().split(",");
+                    for (String s : split) {
+                        WbsTreePrivate temp = map.get(Long.parseLong(s));
+                        if (temp == null || temp.getNodeName() == null) {
+                            continue;
+                        }
+                        sb.append(temp.getNodeName()).append("/");
+                    }
+                    lazyNodeVO.setPrivateTemplate(sb.deleteCharAt(sb.length() - 1).toString());
+                });
+            } catch (Exception e) {
+                lazyNodes.forEach(lazyNodeVO -> lazyNodeVO.setPrivateTemplate(""));
+            }
+        }
+    }
 
     /**
      * 非批量电签时,主动清理本地缓存,如资料填报保存、任务上报等