浏览代码

质检合同段wbs节点收藏

lvy 3 周之前
父节点
当前提交
1e6fb94ac4
共有 15 个文件被更改,包括 919 次插入6 次删除
  1. 1 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/WbsTreeContractStatistics.java
  2. 96 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/ContractCollectFolder.java
  3. 12 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/ContractInfo.java
  4. 22 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/ContractCollectFolderVO.java
  5. 2 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/WbsTreeContractLazyVO.java
  6. 3 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/WbsTreeContractTreeAllVO.java
  7. 53 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ContractCollectFolderController.java
  8. 87 3
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ContractInfoController.java
  9. 8 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ContractCollectFolderMapper.java
  10. 21 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ContractCollectFolderMapper.xml
  11. 20 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IContractCollectFolderService.java
  12. 4 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IContractInfoService.java
  13. 153 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ContractCollectFolderServiceImpl.java
  14. 382 3
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ContractInfoServiceImpl.java
  15. 55 0
      blade-service/blade-user/src/main/java/org/springblade/system/user/service/impl/UserServiceImpl.java

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

@@ -121,6 +121,7 @@ public class WbsTreeContractStatistics implements Serializable {
     private Integer isDeleted = 0;
 
 
+
     public WbsTreeContractStatistics() {
 
     }

+ 96 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/ContractCollectFolder.java

@@ -0,0 +1,96 @@
+package org.springblade.manager.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@TableName("m_contract_collect_folder")
+@NoArgsConstructor
+@AllArgsConstructor
+public class ContractCollectFolder implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty("主键id")
+    @TableId(
+            value = "id",
+            type = IdType.ASSIGN_ID
+    )
+    private Long id;
+
+    /**
+     * 父主键
+     */
+    @ApiModelProperty(value = "父主键id")
+    private Long parentId;
+
+    /**
+     * 收藏夹名称
+     */
+    @ApiModelProperty("收藏夹名称")
+    private String folderName;
+    /**
+     * 节点Id
+     */
+    @ApiModelProperty("节点Id")
+    private Long nodeId;
+
+    /**
+     * 节点路径pKeyIds
+     */
+    @ApiModelProperty("节点路径pKeyIds")
+    private String nodeAncestors;
+
+    /**
+     * 合同Id
+     */
+    @ApiModelProperty("合同段Id")
+    private Long contractId;
+
+    /**
+     * 类型, 0 收藏夹, 1 节点
+     */
+    @ApiModelProperty(value = "类型, 0 收藏夹, 1 节点")
+    private Integer type;
+
+    /**
+     * 排序
+     */
+    @ApiModelProperty(value = "排序")
+    private Integer sort;
+
+    @ApiModelProperty("创建人")
+    private Long createUser;
+
+    @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;
+
+    @ApiModelProperty("业务状态")
+    private Integer status;
+
+    @ApiModelProperty("是否已删除")
+    private Integer isDeleted;
+}

+ 12 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/ContractInfo.java

@@ -187,6 +187,18 @@ public class ContractInfo extends BaseEntity {
     @ApiModelProperty(value = "排序")
     private Integer sort;
 
+    @ApiModelProperty(value = "电签项目id")
+    private String sealProjectId;
+
+    @ApiModelProperty(value = "账号id")
+    private String sealAccountId;
+
+    @ApiModelProperty(value = "客户编号")
+    private String sealCustomerId;
+
+    @ApiModelProperty(value = "通信key")
+    private String sealCommKey;
+
     public BigDecimal getProjectMileage() {
         if (projectMileage == null){
             return null;

+ 22 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/ContractCollectFolderVO.java

@@ -0,0 +1,22 @@
+package org.springblade.manager.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class ContractCollectFolderVO {
+    @ApiModelProperty(value = "id, 收藏夹id")
+    private Long id;
+
+    @ApiModelProperty(value = "收藏夹名称")
+    private String name;
+
+    @ApiModelProperty(value = "节点pKeyId, 收藏和取消收藏时使用")
+    private Long nodeId;
+
+    @ApiModelProperty(value = "合同段id")
+    private Long contractId;
+
+    @ApiModelProperty(value = "1收藏,0取消收藏")
+    private Integer type;
+}

+ 2 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/WbsTreeContractLazyVO.java

@@ -142,4 +142,6 @@ public class WbsTreeContractLazyVO implements Serializable {
     @ApiModelProperty(value = "是否最近同步节点")
     private Integer isSync;
 
+    @ApiModelProperty(value = "是否收藏")
+    private Integer isCollect;
 }

+ 3 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/WbsTreeContractTreeAllVO.java

@@ -53,6 +53,9 @@ public class WbsTreeContractTreeAllVO implements INode<WbsTreeContractTreeAllVO>
     @JsonInclude(JsonInclude.Include.NON_EMPTY)
     private Boolean hasChildren;
 
+    @ApiModelProperty(value = "是否收藏")
+    private Integer isCollect;
+
     @Override
     public List<WbsTreeContractTreeAllVO> getChildren() {
         if (this.children == null) {

+ 53 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ContractCollectFolderController.java

@@ -0,0 +1,53 @@
+package org.springblade.manager.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.secure.utils.AuthUtil;
+import org.springblade.core.tool.api.R;
+import org.springblade.manager.service.IContractCollectFolderService;
+import org.springblade.manager.vo.*;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+
+@RestController
+@AllArgsConstructor
+@RequestMapping("/contractCollectFolder")
+@Api(value = "用户合同段wbs收藏", tags = "用户合同段wbs收藏接口")
+public class ContractCollectFolderController extends BladeController {
+
+    private final IContractCollectFolderService contractCollectFolderService;
+
+    @GetMapping("/folderList")
+    @ApiOperation(value = "收藏文件夹列表")
+    public R<List<ContractCollectFolderVO>> folderList(Long contractId){
+        return R.data(contractCollectFolderService.folderList(contractId));
+    }
+
+    @PostMapping("/deleteFolder")
+    @ApiOperation(value = "删除文件夹")
+    public R<Boolean> deleteFolder(Long id){
+        return R.data(contractCollectFolderService.deleteFolder(id));
+    }
+
+    @PostMapping("/saveOrUpdateFolder")
+    @ApiOperation(value = "编辑文件夹")
+    public R<Boolean> saveOrUpdateFolder(@RequestBody ContractCollectFolderVO vo){
+        return R.data(contractCollectFolderService.saveOrUpdateFolder(vo));
+    }
+
+    @PostMapping("/sortFolder")
+    @ApiOperation(value = "排序")
+    public R<Boolean> sortFolder(String ids){
+        return R.data(contractCollectFolderService.sortFolder(ids));
+    }
+
+    @PostMapping("/collect")
+    @ApiOperation(value = "收藏")
+    public R<Boolean> collect(@RequestBody ContractCollectFolderVO vo){
+        return R.data(contractCollectFolderService.collect(vo));
+    }
+
+}

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

@@ -1,6 +1,9 @@
 package org.springblade.manager.controller;
 
+import cn.hutool.core.date.DateUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import io.swagger.annotations.*;
 import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
@@ -9,6 +12,8 @@ import lombok.AllArgsConstructor;
 import javax.validation.Valid;
 
 import org.apache.commons.lang.StringUtils;
+import org.jetbrains.annotations.Nullable;
+import org.springblade.business.entity.WbsTreeContractStatistics;
 import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.mp.support.Condition;
@@ -16,14 +21,13 @@ import org.springblade.core.mp.support.Query;
 import org.springblade.core.secure.utils.AuthUtil;
 import org.springblade.core.secure.utils.SecureUtil;
 import org.springblade.core.tool.api.R;
-import org.springblade.core.tool.utils.BeanUtil;
-import org.springblade.core.tool.utils.Func;
-import org.springblade.core.tool.utils.ObjectUtil;
+import org.springblade.core.tool.utils.*;
 import org.springblade.manager.dto.FindAllUserByConditionDTO;
 import org.springblade.manager.dto.SaveUserInfoByProjectDTO;
 import org.springblade.manager.dto.WbsTreeContractDTO;
 import org.springblade.manager.entity.ContractRelationJlyz;
 import org.springblade.manager.entity.ProjectInfo;
+import org.springblade.manager.entity.WbsTreeContract;
 import org.springblade.manager.mapper.SaveUserInfoByProjectMapper;
 import org.springblade.manager.service.IWbsTreeContractService;
 import org.springblade.manager.service.SaveUserInfoByProjectService;
@@ -33,6 +37,7 @@ import org.springblade.system.user.entity.User;
 import org.springblade.system.user.feign.IUserClient;
 import org.springblade.system.user.vo.UserContractInfoVO;
 import org.springblade.system.user.vo.UserVO2;
+import org.springframework.dao.DataAccessException;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.transaction.annotation.Transactional;
@@ -884,4 +889,83 @@ public class ContractInfoController extends BladeController {
         List<ContractInfo> list = contractInfoService.getContractInfoByContractId(contractId);
         return R.data(list);
     }
+
+    @GetMapping("/saveHistory")
+    @ApiOperationSupport(order = 23)
+    @ApiOperation(value = "最近n天的保存记录", notes = "最近n天的保存记录, 传递contractId")
+    public R<Object> saveHistory(@RequestParam String queryValue, @RequestParam String contractId, @RequestParam String tableOwner, @RequestParam(defaultValue = "5", required = false) Integer  days) {
+        R<Object> result = contractInfoService.queryWbsTreeNodeBySaveOrHidden(contractId, tableOwner, days, queryValue, 1);
+        R<Object> data = doResult(contractId, result);
+        if (data != null) return data;
+        return R.fail(200, "未查询到信息");
+    }
+    @GetMapping("/getHiddenTreeNode")
+    @ApiOperationSupport(order = 26)
+    @ApiOperation(value = "获取隐藏节点树", notes = "获取隐藏节点树")
+    public R<Object> getHiddenTreeNode(@RequestParam String queryValue, @RequestParam String contractId, @RequestParam String tableOwner) {
+        R<Object> result = contractInfoService.queryWbsTreeNodeBySaveOrHidden(contractId, tableOwner,null, queryValue, 2);
+        R<Object> data = doResult(contractId, result);
+        if (data != null) return data;
+        return R.fail(200, "未查询到信息");
+    }
+
+    @GetMapping("/getCollectTreeNode")
+    @ApiOperationSupport(order = 26)
+    @ApiOperation(value = "获取收藏节点树", notes = "获取收藏节点树")
+    public R<Object> getCollectTreeNode(@RequestParam String queryValue, @RequestParam String contractId, @RequestParam String tableOwner, @RequestParam Long folderId) {
+        R<Object> result = contractInfoService.getCollectTreeNode(contractId, tableOwner,folderId, queryValue);
+        R<Object> data = doResult(contractId, result);
+        if (data != null) return data;
+        return R.fail(200, "未查询到信息");
+    }
+
+    @Nullable
+    private R<Object> doResult(String contractId, R<Object> result) {
+        if (ObjectUtil.isNotEmpty(result) && ObjectUtil.isNotEmpty(result.getData())) {
+            Object data = result.getData();
+            ContractInfo contractInfo = contractInfoService.getBaseMapper().selectById(contractId);
+            if (data instanceof List) {
+                List<?> dataList = (List<?>) data;
+                if (contractInfo.getContractType().equals(1)) {
+                    for (Object item : dataList) {
+                        if (item instanceof WbsTreeContractTreeAllVO) {
+                            WbsTreeContractTreeAllVO wbsTreeContractVO = (WbsTreeContractTreeAllVO) item;
+                            if (ObjectUtil.isNotEmpty(wbsTreeContractVO.getParentId()) && 0L == wbsTreeContractVO.getParentId()) {
+                                wbsTreeContractVO.setTitle(contractInfo.getContractName());
+                                break;
+                            }
+                        }
+                    }
+                    return R.data(data);
+                }
+            } else if (data instanceof Map) {
+                Map<?, ?> dataMap = (Map<?, ?>) data;
+                if (contractInfo.getContractType().equals(2) || contractInfo.getContractType().equals(3)) {
+                    List<WbsTreeContractTreeAllVO> jlYzList = new LinkedList<>();
+                    for (Map.Entry<?, ?> entry : dataMap.entrySet()) {
+                        Object key = entry.getKey();
+                        Object value = entry.getValue();
+                        if (key instanceof Long && value instanceof List) {
+                            Long mapKey = (Long) key;
+                            List<?> mapValue = (List<?>) value;
+                            ContractInfo contractInfoJlYz = contractInfoService.getBaseMapper().selectById(mapKey);
+                            List<? extends WbsTreeContractTreeAllVO> typedList = mapValue.stream()
+                                    .filter(item -> item instanceof WbsTreeContractTreeAllVO)
+                                    .map(item -> (WbsTreeContractTreeAllVO) item)
+                                    .collect(Collectors.toList());
+                            for (WbsTreeContractTreeAllVO wbsTreeContractVO : typedList) {
+                                if (ObjectUtil.isNotEmpty(wbsTreeContractVO.getParentId()) && 0L == wbsTreeContractVO.getParentId()) {
+                                    wbsTreeContractVO.setTitle(contractInfoJlYz.getContractName());
+                                    break;
+                                }
+                            }
+                            jlYzList.addAll(typedList);
+                        }
+                    }
+                    return R.data(jlYzList);
+                }
+            }
+        }
+        return null;
+    }
 }

+ 8 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ContractCollectFolderMapper.java

@@ -0,0 +1,8 @@
+package org.springblade.manager.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springblade.manager.entity.ContractCollectFolder;
+
+public interface ContractCollectFolderMapper extends BaseMapper<ContractCollectFolder> {
+
+}

+ 21 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ContractCollectFolderMapper.xml

@@ -0,0 +1,21 @@
+<?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.manager.mapper.ContractCollectFolderMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="wbsFormElementResultMap" type="org.springblade.manager.entity.ContractCollectFolder">
+        <result column="id" property="id"/>
+        <result column="parent_id" property="parentId"/>
+        <result column="folder_name" property="folderName"/>
+        <result column="contract_id" property="contractId"/>
+        <result column="node_id" property="nodeId"/>
+        <result column="node_ancestors" property="nodeAncestors"/>
+        <result column="type" property="type"/>
+        <result column="sort" property="sort"/>
+        <result column="create_time" property="createTime"/>
+        <result column="create_user" property="createUser"/>
+        <result column="update_time" property="updateTime"/>
+        <result column="status" property="status"/>
+        <result column="is_deleted" property="isDeleted"/>
+    </resultMap>
+</mapper>

+ 20 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/IContractCollectFolderService.java

@@ -0,0 +1,20 @@
+package org.springblade.manager.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.springblade.manager.entity.ContractCollectFolder;
+import org.springblade.manager.vo.ContractCollectFolderVO;
+
+import java.util.List;
+
+public interface IContractCollectFolderService extends IService<ContractCollectFolder> {
+
+    List<ContractCollectFolderVO> folderList(Long contractId);
+
+    Boolean deleteFolder(Long id);
+
+    Boolean saveOrUpdateFolder(ContractCollectFolderVO vo);
+
+    Boolean collect(ContractCollectFolderVO vo);
+
+    Boolean sortFolder(String ids);
+}

+ 4 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/IContractInfoService.java

@@ -86,4 +86,8 @@ public interface IContractInfoService extends BaseService<ContractInfo> {
     void updateIsArchivesAutoById(Long id, Integer isArchivesAuto);
 
     List<ContractInfo> getContractInfoByContractId(String contractId);
+
+    R<Object> queryWbsTreeNodeBySaveOrHidden(String contractId, String tableOwner, Integer days, String queryValue, Integer type);
+
+    R<Object> getCollectTreeNode(String contractId, String tableOwner, Long folderId, String queryValue);
 }

+ 153 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ContractCollectFolderServiceImpl.java

@@ -0,0 +1,153 @@
+package org.springblade.manager.service.impl;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springblade.common.utils.SnowFlakeUtil;
+import org.springblade.core.log.exception.ServiceException;
+import org.springblade.core.secure.utils.AuthUtil;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.manager.entity.ContractCollectFolder;
+import org.springblade.manager.entity.WbsTreeContract;
+import org.springblade.manager.mapper.ContractCollectFolderMapper;
+import org.springblade.manager.service.IContractCollectFolderService;
+import org.springblade.manager.service.IWbsTreeContractService;
+import org.springblade.manager.vo.ContractCollectFolderVO;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Service
+@RequiredArgsConstructor
+public class ContractCollectFolderServiceImpl extends ServiceImpl<ContractCollectFolderMapper, ContractCollectFolder> implements IContractCollectFolderService {
+    private final IWbsTreeContractService wbsTreeContractService;
+    private final StringRedisTemplate redisTemplate;
+
+    private static final Logger log = LoggerFactory.getLogger(ContractCollectFolderServiceImpl.class);
+
+    @Override
+    public List<ContractCollectFolderVO> folderList(Long contractId) {
+        List<ContractCollectFolder> list = this.list(Wrappers.<ContractCollectFolder>lambdaQuery().select(ContractCollectFolder::getId, ContractCollectFolder::getFolderName)
+                .eq(ContractCollectFolder::getType, 0).eq(ContractCollectFolder::getContractId, contractId).orderByAsc(ContractCollectFolder::getSort).orderByDesc(ContractCollectFolder::getCreateTime));
+        if (list == null || list.isEmpty()) {
+            return new ArrayList<>();
+        }
+        return list.stream().map(item -> {
+            ContractCollectFolderVO vo = new ContractCollectFolderVO();
+            vo.setId(item.getId());
+            vo.setName(item.getFolderName());
+            return vo;
+        }).collect(Collectors.toList());
+    }
+
+    @Override
+    @Transactional
+    public Boolean deleteFolder(Long id) {
+        ContractCollectFolder entity = this.getById(id);
+        if (entity != null) {
+            boolean b = this.removeById(id);
+            if (b) {
+                this.remove(Wrappers.<ContractCollectFolder>lambdaQuery().eq(ContractCollectFolder::getParentId, id).eq(ContractCollectFolder::getType, 1).eq(ContractCollectFolder::getContractId, entity.getContractId()));
+                redisTemplate.delete("blade-manager::contract:collectFolder:" + entity.getContractId());
+            }
+            return b;
+        }
+        return true;
+    }
+
+    @Override
+    public Boolean saveOrUpdateFolder(ContractCollectFolderVO vo) {
+        if (vo == null || StringUtil.isBlank(vo.getName())) {
+            return false;
+        }
+        long count = this.count(Wrappers.<ContractCollectFolder>lambdaQuery().eq(ContractCollectFolder::getType, 0).eq(ContractCollectFolder::getContractId, vo.getContractId())
+                .eq(ContractCollectFolder::getFolderName, vo.getName()).last(" limit 1"));
+        if (count > 0) {
+            throw new ServiceException("收藏夹名称重复");
+        }
+        redisTemplate.delete("blade-manager::contract:collectFolder:" + vo.getContractId());
+        if (vo.getId() == null) {
+            ContractCollectFolder entity = new ContractCollectFolder();
+            entity.setContractId(vo.getContractId());
+            entity.setCreateUser(AuthUtil.getUserId());
+            entity.setType(0);
+            entity.setId(SnowFlakeUtil.getId());
+            entity.setFolderName(vo.getName());
+            return this.save(entity);
+        }
+        return this.update(Wrappers.<ContractCollectFolder>lambdaUpdate().set(ContractCollectFolder::getFolderName, vo.getName())
+                .eq(ContractCollectFolder::getId, vo.getId()));
+    }
+
+    @Override
+    public Boolean collect(ContractCollectFolderVO vo) {
+        if (vo == null || vo.getNodeId() == null || (vo.getId() == null && vo.getType() != 0)) {
+            throw new ServiceException("参数错误");
+        }
+        WbsTreeContract wbsTreeContract = wbsTreeContractService.getOne(Wrappers.<WbsTreeContract>lambdaQuery().eq(WbsTreeContract::getPKeyId, vo.getNodeId()));
+        if (wbsTreeContract == null) {
+            throw new ServiceException("节点不存在或者已被删除");
+        }
+        ContractCollectFolder node = this.getOne(Wrappers.<ContractCollectFolder>lambdaQuery().eq(ContractCollectFolder::getNodeId, vo.getNodeId()).eq(ContractCollectFolder::getType, 1).eq(ContractCollectFolder::getContractId, vo.getContractId()));
+        if (vo.getType() == 0) {
+            // 取消
+            if (node == null) {
+                throw new ServiceException("请先取消该节点下所有的收藏节点");
+            }
+            this.removeById(node.getId());
+        } else if (vo.getType() == 1) {
+            ContractCollectFolder collectFolder = this.getById(vo.getId());
+            if (collectFolder == null) {
+                throw new ServiceException("收藏夹不存在");
+            }
+            if (node == null) {
+                node = new ContractCollectFolder();
+                node.setId(SnowFlakeUtil.getId());
+                node.setNodeId(vo.getNodeId());
+                node.setContractId(vo.getContractId());
+                node.setType(1);
+                node.setCreateUser(AuthUtil.getUserId());
+                node.setNodeAncestors(wbsTreeContract.getAncestorsPId() + "," + vo.getNodeId());
+                node.setParentId(vo.getId());
+                redisTemplate.delete("blade-manager::contract:collectFolder:" + vo.getContractId());
+                return this.save(node);
+            }
+            ContractCollectFolder folder = this.getById(node.getParentId());
+            if (folder != null) {
+                throw new ServiceException("该节点已被【 "+ folder.getFolderName() +" 】收藏");
+            }
+            redisTemplate.delete("blade-manager::contract:collectFolder:" + vo.getContractId());
+            return this.update(Wrappers.<ContractCollectFolder>lambdaUpdate().set(ContractCollectFolder::getParentId, vo.getId())
+                    .eq(ContractCollectFolder::getId, node.getId()));
+        }
+        return true;
+    }
+
+    @Override
+    @Transactional
+    public Boolean sortFolder(String ids) {
+        if (StringUtil.isBlank(ids)) {
+            return true;
+        }
+        int sort = 1;
+        String[] split = ids.split(",");
+        for (String s : split) {
+            if (StringUtil.isNumeric(s)) {
+                long id = Long.parseLong(s);
+                if (id <= 0) {
+                    continue;
+                }
+                this.update(Wrappers.<ContractCollectFolder>lambdaUpdate().set(ContractCollectFolder::getSort, sort++)
+                        .eq(ContractCollectFolder::getId, id).eq(ContractCollectFolder::getCreateUser, AuthUtil.getUserId()));
+            }
+        }
+        return true;
+    }
+}

+ 382 - 3
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ContractInfoServiceImpl.java

@@ -1,5 +1,6 @@
 package org.springblade.manager.service.impl;
 
+import cn.hutool.core.date.DateUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
@@ -10,18 +11,18 @@ import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.AllArgsConstructor;
+import org.jetbrains.annotations.NotNull;
 import org.springblade.business.entity.WbsTreeContractStatistics;
 import org.springblade.business.feign.InformationQueryClient;
 import org.springblade.common.utils.BaiduApiUtil;
 import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.mp.base.BaseServiceImpl;
+import org.springblade.core.secure.utils.AuthUtil;
 import org.springblade.core.secure.utils.SecureUtil;
 import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.node.ForestNodeMerger;
-import org.springblade.core.tool.utils.BeanUtil;
-import org.springblade.core.tool.utils.CollectionUtil;
-import org.springblade.core.tool.utils.ObjectUtil;
+import org.springblade.core.tool.utils.*;
 import org.springblade.manager.bean.NodeVO;
 import org.springblade.manager.dto.FindAllUserByConditionDTO;
 import org.springblade.manager.dto.SaveUserInfoByProjectDTO;
@@ -40,6 +41,7 @@ import org.springframework.dao.DataAccessException;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.SingleColumnRowMapper;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -47,6 +49,7 @@ import org.springframework.transaction.annotation.Transactional;
 import java.io.IOException;
 import java.math.BigDecimal;
 import java.util.*;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -392,6 +395,7 @@ public class ContractInfoServiceImpl extends BaseServiceImpl<ContractInfoMapper,
 
             if (contractInfo != null) {
                 /*质检施工合同段*/
+                Map<Long, String> collectNodesMap = getCollectNodesByContractId(contractId);
                 if (contractInfo.getContractType().equals(1)) {
                     LambdaQueryWrapper<WbsTreeContract> queryWrapper = new LambdaQueryWrapper<>();
                     queryWrapper.select(WbsTreeContract::getParentId, WbsTreeContract::getId, WbsTreeContract::getPKeyId);
@@ -402,6 +406,7 @@ public class ContractInfoServiceImpl extends BaseServiceImpl<ContractInfoMapper,
                     }
                     queryWrapper.eq(WbsTreeContract::getContractId, contractId);
                     queryWrapper.eq(WbsTreeContract::getType, 1);
+                    queryWrapper.and(wrapper -> wrapper.ne(WbsTreeContract::getIsBussShow, 2).or().isNull(WbsTreeContract::getIsBussShow));
                     List<WbsTreeContract> nodes = wbsTreeContractMapper.selectList(queryWrapper);
                     if (nodes.size() > 0) {
                         List<WbsTreeContractLazyVO> nodesAllTemp;
@@ -545,6 +550,11 @@ public class ContractInfoServiceImpl extends BaseServiceImpl<ContractInfoMapper,
                                                 //判断是否展示同步标识
                                                 vo.setIsSync(syncPKeyIds.contains(vo.getPrimaryKeyId().toString()) ? 1 : 0);
                                             }
+                                            if (collectNodesMap.containsKey(vo.getPrimaryKeyId())) {
+                                                vo.setIsCollect(1);
+                                            } else {
+                                                vo.setIsCollect(0);
+                                            }
                                         }
                                         return vo;
                                     }).collect(Collectors.toList());
@@ -570,6 +580,7 @@ public class ContractInfoServiceImpl extends BaseServiceImpl<ContractInfoMapper,
                         }
                         queryWrapper.eq(WbsTreeContract::getContractId, contractRelationJlyz.getContractIdSg());
                         queryWrapper.eq(WbsTreeContract::getType, 1);
+                        queryWrapper.and(wrapper -> wrapper.ne(WbsTreeContract::getIsBussShow, 2).or().isNull(WbsTreeContract::getIsBussShow));
                         List<WbsTreeContract> nodes = wbsTreeContractMapper.selectList(queryWrapper);
                         if (nodes.size() > 0) {
                             List<WbsTreeContractLazyVO> nodesAllTemp;
@@ -714,6 +725,11 @@ public class ContractInfoServiceImpl extends BaseServiceImpl<ContractInfoMapper,
                                                     //判断是否展示同步标识
                                                     vo.setIsSync(syncPKeyIds.contains(vo.getPrimaryKeyId().toString()) ? 1 : 0);
                                                 }
+                                                if (collectNodesMap.containsKey(vo.getPrimaryKeyId())) {
+                                                    vo.setIsCollect(1);
+                                                } else {
+                                                    vo.setIsCollect(0);
+                                                }
                                             }
                                             return vo;
                                         }).collect(Collectors.toList());
@@ -1268,4 +1284,367 @@ public class ContractInfoServiceImpl extends BaseServiceImpl<ContractInfoMapper,
         return contractInfo;
     }
 
+    @Override
+    public R<Object> queryWbsTreeNodeBySaveOrHidden(String contractId, String tableOwner, Integer  days, String queryValue, Integer type) {
+        if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isEmpty(contractId)) {
+            return R.fail(200, "合同段id错误");
+        }
+        ContractInfo contractInfo = this.selectById(contractId);
+        if (contractInfo == null) {
+            return R.fail(200, "合同段不存在");
+        }
+        String idsStr = "";
+        if (type != null && type == 1) {
+            List<Long> pKeyIds = jdbcTemplate.query("SELECT distinct p_key_id from blade_tab_sql WHERE user_id = ? and create_time > ?", new Object[]{AuthUtil.getUserId(), DateUtil.offsetDay(new Date(), -days)}, new SingleColumnRowMapper<>(Long.class));
+            if (pKeyIds.isEmpty()) {
+                return R.fail(200, "未查询到信息");
+            }
+            idsStr = pKeyIds.stream().map(id -> id + "").collect(Collectors.joining(","));
+        }
+        Set<String> syncPKeyIds = getSyncFlagIds(contractId, tableOwner);
+        Map<Long, String> collectNodesMap = getCollectNodesByContractId(contractId);
+        /*质检施工合同段*/
+        if (contractInfo.getContractType().equals(1)) {
+            LambdaQueryWrapper<WbsTreeContract> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.eq(WbsTreeContract::getContractId, contractId).eq(WbsTreeContract::getType, 1);
+            if (type != null && type == 1) {
+                queryWrapper.last(" and p_key_id in ( select p_id from m_wbs_tree_contract where p_key_id in (" + idsStr + ") ) ");
+            } else {
+                queryWrapper.eq(WbsTreeContract::getIsBussShow, 2);
+            }
+            List<WbsTreeContract> nodes = wbsTreeContractMapper.selectList(queryWrapper);
+            if (!nodes.isEmpty()) {
+                List<WbsTreeContractLazyVO> nodesAllTemp;
+                Object data = redisTemplate.opsForValue().get("blade-manager::contract:wbstree:" + contractId);
+                if (data != null) {
+                    nodesAllTemp = JSON.parseArray(data.toString(), WbsTreeContractLazyVO.class);
+                } else {
+                    nodesAllTemp = jdbcTemplate.query("select a.p_key_id,a.id,a.parent_id from m_wbs_tree_contract a where a.type = 1 and a.status = 1 and a.is_deleted = 0 and a.contract_id = " + contractId, new BeanPropertyRowMapper<>(WbsTreeContractLazyVO.class));
+                    if (!nodesAllTemp.isEmpty()) {
+                        Map<Long, List<WbsTreeContractLazyVO>> groupedByParentId = nodesAllTemp.stream().collect(Collectors.groupingBy(WbsTreeContractLazyVO::getParentId));
+                        for (WbsTreeContractLazyVO vo : nodesAllTemp) {
+                            if (vo.getParentId() == 0) {
+                                vo.setHasChildren(1);
+                            }
+                            List<WbsTreeContractLazyVO> childNodes = groupedByParentId.getOrDefault(vo.getId(), null);
+                            if (childNodes != null && !childNodes.isEmpty()) {
+                                vo.setHasChildren(1);
+                            } else {
+                                vo.setHasChildren(0);
+                            }
+                        }
+                        JSONArray array = JSONArray.parseArray(JSON.toJSONString(nodesAllTemp));
+                        redisTemplate.opsForValue().set("blade-manager::contract:wbstree:" + contractId, JSON.toJSON(array).toString());
+                    }
+                }
+                List<Long> parentIds = nodes.stream().map(WbsTreeContract::getParentId).collect(Collectors.toList());
+                List<Long> ids = nodes.stream().map(WbsTreeContract::getId).collect(Collectors.toList());
+                Set<Long> resultNodesPKeyIds = new LinkedHashSet<>();
+                this.recursiveGetParentNodes(resultNodesPKeyIds, parentIds, nodesAllTemp);
+                this.recursiveGetChildNodes(resultNodesPKeyIds, ids, nodesAllTemp);
+
+                resultNodesPKeyIds.addAll(nodes.stream().map(WbsTreeContract::getPKeyId).collect(Collectors.toList()));
+                List<WbsTreeContract> wbsTreeContractList = wbsTreeContractMapper.selectList(Wrappers.<WbsTreeContract>lambdaQuery().in(WbsTreeContract::getPKeyId, resultNodesPKeyIds));
+
+                if (!wbsTreeContractList.isEmpty()) {
+                    String pKeyIdStr = wbsTreeContractList.stream().map(item -> item.getPKeyId() + "").collect(Collectors.joining(","));
+                    List<WbsTreeContractStatistics> wbsTreeContractStatisticsList = jdbcTemplate.query("select id, leaf_num, fill_num, approve_num, complete_num,jl_fill_num, jl_approve_num, jl_complete_num from m_wbs_tree_contract_statistics where id in (" + pKeyIdStr + ")",
+                            new BeanPropertyRowMapper<>(WbsTreeContractStatistics.class));
+                    Map<Long, WbsTreeContractStatistics> wbsTreeContractStatisticsMap = wbsTreeContractStatisticsList.stream().collect(Collectors.toMap(WbsTreeContractStatistics::getId, item -> item));
+                    List<WbsTreeContractTreeAllVO> wbsTreeContractTreeAllVOS = wbsTreeContractList.stream()
+                            .map(node -> {
+                                WbsTreeContractTreeAllVO vo = BeanUtil.copyProperties(node, WbsTreeContractTreeAllVO.class);
+                                if (vo != null) {
+                                    vo.setContractIdRelation(node.getContractId());
+                                    vo.setType(ObjectUtils.isNotEmpty(node.getNodeType()) ? node.getNodeType() : 0);
+                                    vo.setTitle(ObjectUtil.isNotEmpty(node.getFullName()) ? node.getFullName() : node.getNodeName());
+                                    vo.setPrimaryKeyId(node.getPKeyId());
+                                    WbsTreeContractStatistics statistics = wbsTreeContractStatisticsMap.get(node.getPKeyId());
+                                    if (statistics != null) {
+                                        Integer nums = statistics.calculateSubmitNums(tableOwner);
+                                        vo.setSubmitCounts(nums == null ? 0 : nums.longValue());
+                                        vo.setColorStatus(statistics.calculateColorStatus(tableOwner));
+                                    } else {
+                                        vo.setSubmitCounts(0L);
+                                        vo.setColorStatus(1);
+                                    }
+                                    if(CollectionUtil.isNotEmpty(syncPKeyIds)){
+                                        //判断是否展示同步标识
+                                        vo.setIsSync(syncPKeyIds.contains(vo.getPrimaryKeyId().toString()) ? 1 : 0);
+                                    }
+                                    if (collectNodesMap.containsKey(vo.getPrimaryKeyId())) {
+                                        vo.setIsCollect(1);
+                                    } else {
+                                        vo.setIsCollect(0);
+                                    }
+                                }
+                                return vo;
+                            }).collect(Collectors.toList());
+                    List<WbsTreeContractTreeAllVO> resultList = this.buildWbsTreeByStreamByTreeAll(wbsTreeContractTreeAllVOS);
+                    if (StringUtil.hasText(queryValue)) {
+                        return R.data(queryTreeResult(resultList, queryValue));
+                    }
+                    return R.data(resultList);
+                }
+            }
+            /*监理、业主合同段*/
+        } else if (contractInfo.getContractType().equals(2) || contractInfo.getContractType().equals(3)) {
+            Map<Long, List<WbsTreeContractTreeAllVO>> resultMaps = new LinkedHashMap<>();
+            List<ContractRelationJlyz> relationJLYZList = jdbcTemplate.query("select * from m_contract_relation_jlyz where contract_id_jlyz = " + contractId, new BeanPropertyRowMapper<>(ContractRelationJlyz.class));
+            if (ObjectUtil.isEmpty(relationJLYZList) || relationJLYZList.isEmpty()) {
+                return null;
+            }
+            for (ContractRelationJlyz contractRelationJlyz : relationJLYZList) {
+                LambdaQueryWrapper<WbsTreeContract> queryWrapper = new LambdaQueryWrapper<>();
+                queryWrapper.eq(WbsTreeContract::getContractId, contractRelationJlyz.getContractIdSg()).eq(WbsTreeContract::getType, 1);
+                if (type != null && type == 1) {
+                    queryWrapper.last(" and p_key_id in ( select p_id from m_wbs_tree_contract where p_key_id in (" + idsStr + ") ) ");
+                } else {
+                    queryWrapper.eq(WbsTreeContract::getIsBussShow, 2);
+                }
+                List<WbsTreeContract> nodes = wbsTreeContractMapper.selectList(queryWrapper);
+                if (!nodes.isEmpty()) {
+                    List<WbsTreeContractLazyVO> nodesAllTemp;
+                    Object data = redisTemplate.opsForValue().get("blade-manager::contract:wbstree:" + contractId);
+                    if (data != null) {
+                        nodesAllTemp = JSON.parseArray(data.toString(), WbsTreeContractLazyVO.class);
+                    } else {
+                        nodesAllTemp = jdbcTemplate.query("select a.p_key_id,a.id,a.parent_id from m_wbs_tree_contract a where a.type = 1 and a.status = 1 and a.is_deleted = 0 and a.contract_id = " + contractId, new BeanPropertyRowMapper<>(WbsTreeContractLazyVO.class));
+                        if (!nodesAllTemp.isEmpty()) {
+                            Map<Long, List<WbsTreeContractLazyVO>> groupedByParentId = nodesAllTemp.stream().collect(Collectors.groupingBy(WbsTreeContractLazyVO::getParentId));
+                            for (WbsTreeContractLazyVO vo : nodesAllTemp) {
+                                if (vo.getParentId() == 0) {
+                                    vo.setHasChildren(1);
+                                }
+                                List<WbsTreeContractLazyVO> childNodes = groupedByParentId.getOrDefault(vo.getId(), null);
+                                if (childNodes != null && !childNodes.isEmpty()) {
+                                    vo.setHasChildren(1);
+                                } else {
+                                    vo.setHasChildren(0);
+                                }
+                            }
+                            JSONArray array = JSONArray.parseArray(JSON.toJSONString(nodesAllTemp));
+                            redisTemplate.opsForValue().set("blade-manager::contract:wbstree:" + contractId, JSON.toJSON(array).toString());
+                        }
+                    }
+                    List<Long> parentIds = nodes.stream().map(WbsTreeContract::getParentId).collect(Collectors.toList());
+                    List<Long> ids = nodes.stream().map(WbsTreeContract::getId).collect(Collectors.toList());
+                    Set<Long> resultNodesPKeyIds = new LinkedHashSet<>();
+                    this.recursiveGetParentNodes(resultNodesPKeyIds, parentIds, nodesAllTemp);
+                    this.recursiveGetChildNodes(resultNodesPKeyIds, ids, nodesAllTemp);
+
+                    resultNodesPKeyIds.addAll(nodes.stream().map(WbsTreeContract::getPKeyId).collect(Collectors.toList()));
+                    List<WbsTreeContract> wbsTreeContractList = wbsTreeContractMapper.selectList(Wrappers.<WbsTreeContract>lambdaQuery().in(WbsTreeContract::getPKeyId, resultNodesPKeyIds));
+                    if (!wbsTreeContractList.isEmpty()) {
+                        String pKeyIdStr = wbsTreeContractList.stream().map(item -> item.getPKeyId() + "").collect(Collectors.joining(","));
+                        List<WbsTreeContractStatistics> wbsTreeContractStatisticsList = jdbcTemplate.query("select id, leaf_num, fill_num, approve_num, complete_num,jl_fill_num, jl_approve_num, jl_complete_num from m_wbs_tree_contract_statistics where id in (" + pKeyIdStr + ")",
+                                new BeanPropertyRowMapper<>(WbsTreeContractStatistics.class));
+                        Map<Long, WbsTreeContractStatistics> wbsTreeContractStatisticsMap = wbsTreeContractStatisticsList.stream().collect(Collectors.toMap(WbsTreeContractStatistics::getId, item -> item));
+                        List<WbsTreeContractTreeAllVO> wbsTreeContractTreeAllVOS = wbsTreeContractList.stream()
+                                .map(node -> {
+                                    WbsTreeContractTreeAllVO vo = BeanUtil.copyProperties(node, WbsTreeContractTreeAllVO.class);
+                                    if (vo != null) {
+                                        vo.setContractIdRelation(node.getContractId());
+                                        vo.setType(ObjectUtils.isNotEmpty(node.getNodeType()) ? node.getNodeType() : 0);
+                                        vo.setTitle(ObjectUtil.isNotEmpty(node.getFullName()) ? node.getFullName() : node.getNodeName());
+                                        vo.setPrimaryKeyId(node.getPKeyId());
+                                        WbsTreeContractStatistics statistics = wbsTreeContractStatisticsMap.get(node.getPKeyId());
+                                        if (statistics != null) {
+                                            Integer nums = statistics.calculateSubmitNums(tableOwner);
+                                            vo.setSubmitCounts(nums == null ? 0 : nums.longValue());
+                                            vo.setColorStatus(statistics.calculateColorStatus(tableOwner));
+                                        } else {
+                                            vo.setSubmitCounts(0L);
+                                            vo.setColorStatus(1);
+                                        }
+                                        if(CollectionUtil.isNotEmpty(syncPKeyIds)){
+                                            //判断是否展示同步标识
+                                            vo.setIsSync(syncPKeyIds.contains(vo.getPrimaryKeyId().toString()) ? 1 : 0);
+                                        }
+                                        if (collectNodesMap.containsKey(vo.getPrimaryKeyId())) {
+                                            vo.setIsCollect(1);
+                                        } else {
+                                            vo.setIsCollect(0);
+                                        }
+                                    }
+                                    return vo;
+                                }).collect(Collectors.toList());
+                        List<WbsTreeContractTreeAllVO> list = this.buildWbsTreeByStreamByTreeAll(wbsTreeContractTreeAllVOS);
+                        if (StringUtil.hasText(queryValue)) {
+                            resultMaps.put(contractRelationJlyz.getContractIdSg(), this.queryTreeResult(list, queryValue));
+                        } else {
+                            resultMaps.put(contractRelationJlyz.getContractIdSg(), list);
+                        }
+                    }
+                }
+            }
+            return R.data(resultMaps);
+        }
+        return null;
+    }
+
+    private Map<Long, String> getCollectNodesByContractId(String contractId){
+        if (contractId ==  null || contractId.trim().isEmpty()) {
+            return new HashMap<>();
+        }
+        Map<Long, String> collectNodes = new HashMap<>();
+        try {
+            String string = redisTemplate.opsForValue().get("blade-manager::contract:collectFolder:" + contractId);
+            if (string != null) {
+                String[] split = string.split(",");
+                for (String s : split) {
+                    if (StringUtil.isNumeric(s)) {
+                        collectNodes.put(Long.parseLong(s), "");
+                    }
+                }
+            }
+        } catch (Exception e) {
+            log.error("",e);
+        }
+        try {
+            if (!collectNodes.isEmpty()) {
+                return collectNodes;
+            }
+            List<ContractCollectFolder> query = jdbcTemplate.query(String.format("select * from m_contract_collect_folder where contract_id = %s and type = 1", contractId), new BeanPropertyRowMapper<>(ContractCollectFolder.class));
+            for (ContractCollectFolder contractCollectFolder : query) {
+                Long nodeId = contractCollectFolder.getNodeId();
+                collectNodes.put(nodeId, "");
+                String nodeAncestors = contractCollectFolder.getNodeAncestors();
+                if (nodeAncestors != null) {
+                    String[] split = nodeAncestors.split(",");
+                    for (String s : split) {
+                        if (StringUtil.isNumeric(s)) {
+                            collectNodes.put(Long.parseLong(s), "");
+                        }
+                    }
+                }
+                String ids = collectNodes.keySet().stream().map(item -> item + "").collect(Collectors.joining(","));
+                redisTemplate.opsForValue().set("blade-manager::contract:collectFolder:" + contractId, ids, 60 * 60 * 40L, TimeUnit.SECONDS);
+            }
+        } catch (Exception e) {
+            log.error("合同段id:" + contractId + ", 获取收藏节点失败:" + e.getMessage(), e);
+        }
+        return collectNodes;
+    }
+
+    private List<WbsTreeContractTreeAllVO> queryTreeResult(List<WbsTreeContractTreeAllVO> resultList, String query) {
+        // 查找树结构中name包含query的节点,返回其父节点及所有子节点
+        List<WbsTreeContractTreeAllVO> result = new ArrayList<>();
+        for (WbsTreeContractTreeAllVO node : resultList) {
+            if (node.getTitle().contains(query)) {
+                result.add(node);
+                continue;
+            }
+            if (node.getChildren() != null && !node.getChildren().isEmpty()) {
+                List<WbsTreeContractTreeAllVO> list = queryTreeResult(node.getChildren(), query);
+                if (list.isEmpty()) {
+                    node.setChildren(new ArrayList<>());
+                } else {
+                    node.setChildren( list);
+                }
+            }
+            if (node.getChildren() != null && !node.getChildren().isEmpty()) {
+                result.add(node);
+            }
+        }
+        return result;
+    }
+    @NotNull
+    private Set<String> getSyncFlagIds(String contractId, String tableOwner) {
+        //查询wbs同步信息
+        String contractExtendSql = "select a.ancestors from m_wbs_tree_contract_extend a " +
+                "inner join m_wbs_tree_contract b on a.p_key_id = b.p_key_id and b.is_deleted = 0 " +
+                "where a.type = " + tableOwner + " and a.is_sync = 1 and a.is_deleted = 0 and a.contract_id = " + contractId;
+        Set<String> syncPKeyIds = new HashSet<>();
+        if(SecureUtil.isAdministrator()){
+            List<String> strings = null;
+            try {
+                strings = jdbcTemplate.queryForList(contractExtendSql, String.class);
+            } catch (DataAccessException e) {
+                //TODO 暂时忽略错误
+                e.printStackTrace();
+            }
+            if(strings != null && !strings.isEmpty()){
+                strings.stream().filter(StringUtils::isNotEmpty).forEach(f -> syncPKeyIds.addAll(Arrays.asList(f.split(","))));
+            }
+        }
+        return syncPKeyIds;
+    }
+    @Override
+    public R<Object> getCollectTreeNode(String contractId, String tableOwner, Long folderId, String queryValue) {
+        if (StringUtils.isEmpty(contractId)) {
+            return R.fail(200, "合同段id错误");
+        }
+        if (folderId == null || folderId <= 0) {
+            return R.fail(200, "收藏夹不存在");
+        }
+        ContractInfo contractInfo = this.selectById(contractId);
+        if (contractInfo == null) {
+            return R.fail(200, "合同段不存在");
+        }
+        Set<String> syncPKeyIds = getSyncFlagIds(contractId, tableOwner);
+        List<ContractCollectFolder> contractCollectNodes = jdbcTemplate.query("select * from m_contract_collect_folder where type = 1 and parent_id = " + folderId, new BeanPropertyRowMapper<>(ContractCollectFolder.class));
+        if (!contractCollectNodes.isEmpty()) {
+            Set<Long> pKeyIds = new LinkedHashSet<>();
+            for (ContractCollectFolder node : contractCollectNodes) {
+                String ancestors = node.getNodeAncestors();
+                if (ancestors != null) {
+                    String[] split = ancestors.split(",");
+                    for (String s : split) {
+                        if (StringUtil.isNumeric(s)) {
+                            pKeyIds.add(Long.parseLong(s));
+                        }
+                    }
+                }
+                pKeyIds.add(node.getNodeId());
+            }
+            List<WbsTreeContract> wbsTreeContractList = wbsTreeContractMapper.selectList(Wrappers.<WbsTreeContract>lambdaQuery().in(WbsTreeContract::getPKeyId, pKeyIds));
+            if (!wbsTreeContractList.isEmpty()) {
+                String pKeyIdStr = wbsTreeContractList.stream().map(item -> item.getPKeyId() + "").collect(Collectors.joining(","));
+                List<WbsTreeContractStatistics> wbsTreeContractStatisticsList = jdbcTemplate.query("select id, leaf_num, fill_num, approve_num, complete_num,jl_fill_num, jl_approve_num, jl_complete_num from m_wbs_tree_contract_statistics where id in (" + pKeyIdStr + ")",
+                        new BeanPropertyRowMapper<>(WbsTreeContractStatistics.class));
+                Map<Long, WbsTreeContractStatistics> wbsTreeContractStatisticsMap = wbsTreeContractStatisticsList.stream().collect(Collectors.toMap(WbsTreeContractStatistics::getId, item -> item));
+                Map<String, List<WbsTreeContract>> contractGroupMap = wbsTreeContractList.stream().collect(Collectors.groupingBy(WbsTreeContract::getContractId));
+                Map<Long, List<WbsTreeContractTreeAllVO>> resultMaps = new LinkedHashMap<>();
+                contractGroupMap.forEach((cId, list) -> {
+                    List<WbsTreeContractTreeAllVO> wbsTreeContractTreeAllVOS = list.stream()
+                            .map(node -> {
+                                WbsTreeContractTreeAllVO vo = BeanUtil.copyProperties(node, WbsTreeContractTreeAllVO.class);
+                                if (vo != null) {
+                                    vo.setContractIdRelation(node.getContractId());
+                                    vo.setType(ObjectUtils.isNotEmpty(node.getNodeType()) ? node.getNodeType() : 0);
+                                    vo.setTitle(ObjectUtil.isNotEmpty(node.getFullName()) ? node.getFullName() : node.getNodeName());
+                                    vo.setPrimaryKeyId(node.getPKeyId());
+                                    WbsTreeContractStatistics statistics = wbsTreeContractStatisticsMap.get(node.getPKeyId());
+                                    if (statistics != null) {
+                                        Integer nums = statistics.calculateSubmitNums(tableOwner);
+                                        vo.setSubmitCounts(nums == null ? 0 : nums.longValue());
+                                        vo.setColorStatus(statistics.calculateColorStatus(tableOwner));
+                                    } else {
+                                        vo.setSubmitCounts(0L);
+                                        vo.setColorStatus(1);
+                                    }
+                                    if(CollectionUtil.isNotEmpty(syncPKeyIds)){
+                                        //判断是否展示同步标识
+                                        vo.setIsSync(syncPKeyIds.contains(vo.getPrimaryKeyId().toString()) ? 1 : 0);
+                                    }
+                                    vo.setIsCollect(1);
+                                }
+                                return vo;
+                            }).collect(Collectors.toList());
+                    List<WbsTreeContractTreeAllVO> resultList = this.buildWbsTreeByStreamByTreeAll(wbsTreeContractTreeAllVOS);
+                    if (StringUtil.hasText(queryValue)) {
+                        resultMaps.put(Long.parseLong(cId), this.queryTreeResult(resultList, queryValue));
+                    } else {
+                        resultMaps.put(Long.parseLong(cId), resultList);
+                    }
+                });
+                if (contractInfo.getContractType() != null && contractInfo.getContractType() == 1) {
+                    return R.data(resultMaps.get(contractInfo.getId()));
+                }
+                return R.data(resultMaps);
+            }
+        }
+        return null;
+    }
 }

+ 55 - 0
blade-service/blade-user/src/main/java/org/springblade/system/user/service/impl/UserServiceImpl.java

@@ -82,6 +82,7 @@ import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -794,6 +795,7 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
             }
 
             if (contractInfo != null) {
+                Map<Long, String> collectNodesMap = getCollectNodesByContractId(contractId);
                 /* =========================== 施工合同段 =========================== */
                 if (new Integer(1).equals(contractInfo.getContractType())) {
                     String sql = "SELECT is_custom,p_key_id,contract_id," +
@@ -910,6 +912,11 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
                                     lazyNodeVO.setSubmitCounts(0);
                                     lazyNodeVO.setColorStatus(1);
                                 }
+                                if (collectNodesMap.containsKey(lazyNodeVO.getPrimaryKeyId())) {
+                                    lazyNodeVO.setIsCollect(1);
+                                } else {
+                                    lazyNodeVO.setIsCollect(0);
+                                }
 //                                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)) {
@@ -1049,6 +1056,11 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
                                             lazyNodeVO.setSubmitCounts(0);
                                             lazyNodeVO.setColorStatus(1);
                                         }
+                                        if (collectNodesMap.containsKey(lazyNodeVO.getPrimaryKeyId())) {
+                                            lazyNodeVO.setIsCollect(1);
+                                        } else {
+                                            lazyNodeVO.setIsCollect(0);
+                                        }
 //                                        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);
@@ -1126,6 +1138,49 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
             }
         }
     }
+    private Map<Long, String> getCollectNodesByContractId(String contractId){
+        if (contractId ==  null || contractId.trim().isEmpty()) {
+            return new HashMap<>();
+        }
+        Map<Long, String> collectNodes = new HashMap<>();
+        try {
+            String string = redisTemplate.opsForValue().get("blade-manager::contract:collectFolder:" + contractId);
+            if (string != null) {
+                String[] split = string.split(",");
+                for (String s : split) {
+                    if (StringUtil.isNumeric(s)) {
+                        collectNodes.put(Long.parseLong(s), "");
+                    }
+                }
+            }
+        } catch (Exception e) {
+            log.error("",e);
+        }
+        try {
+            if (!collectNodes.isEmpty()) {
+                return collectNodes;
+            }
+            List<ContractCollectFolder> query = jdbcTemplate.query(String.format("select * from m_contract_collect_folder where contract_id = %s and type = 1", contractId), new BeanPropertyRowMapper<>(ContractCollectFolder.class));
+            for (ContractCollectFolder contractCollectFolder : query) {
+                Long nodeId = contractCollectFolder.getNodeId();
+                collectNodes.put(nodeId, "");
+                String nodeAncestors = contractCollectFolder.getNodeAncestors();
+                if (nodeAncestors != null) {
+                    String[] split = nodeAncestors.split(",");
+                    for (String s : split) {
+                        if (StringUtil.isNumeric(s)) {
+                            collectNodes.put(Long.parseLong(s), "");
+                        }
+                    }
+                }
+                String ids = collectNodes.keySet().stream().map(item -> item + "").collect(Collectors.joining(","));
+                redisTemplate.opsForValue().set("blade-manager::contract:collectFolder:" + contractId, ids, 60 * 60 * 40L, TimeUnit.SECONDS);
+            }
+        } catch (Exception e) {
+            log.error("合同段id:" + contractId + ", 获取收藏节点失败:" + e.getMessage(), e);
+        }
+        return collectNodes;
+    }
 
     /**
      * 非批量电签时,主动清理本地缓存,如资料填报保存、任务上报等