Browse Source

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

yangyj 2 years ago
parent
commit
dc09090342
49 changed files with 1788 additions and 723 deletions
  1. 1 0
      blade-common/src/main/java/org/springblade/common/constant/LauncherConstant.java
  2. 23 0
      blade-common/src/main/java/org/springblade/common/constant/OssConstant.java
  3. 16 0
      blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/feign/NewIOSSClient.java
  4. 101 0
      blade-ops/blade-resource/src/main/java/org/springblade/resource/builder/ossre/AliossTemplateRe.java
  5. 6 0
      blade-ops/blade-resource/src/main/java/org/springblade/resource/builder/ossre/OssTemplateRe.java
  6. 124 45
      blade-ops/blade-resource/src/main/java/org/springblade/resource/endpoint/LargeFileEndpoint.java
  7. 12 0
      blade-ops/blade-resource/src/main/java/org/springblade/resource/feign/NewIOSSClientImpl.java
  8. 3 1
      blade-service-api/blade-archive-api/src/main/java/org/springblade/archive/vo/ArchiveExaminingSocketVo.java
  9. 9 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/ArchiveFile.java
  10. 7 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/feign/ArchiveFileClient.java
  11. 2 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/feign/OperationLogClient.java
  12. 3 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/feign/RecycleBinClient.java
  13. 7 2
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/feign/WbsTreeContractClient.java
  14. 14 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/ArchiveTreeContractVO3.java
  15. 7 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchiveExaminingReportController.java
  16. 67 1
      blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchivesAutoController.java
  17. 11 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/ArchivesAutoMapper.java
  18. 69 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/ArchivesAutoMapper.xml
  19. 4 1
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/IArchiveAutoPdfService.java
  20. 2 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/IArchiveExaminingReportService.java
  21. 8 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/IArchivesAutoService.java
  22. 57 17
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveAutoPdfServiceImpl.java
  23. 49 19
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveExaminingReportImpl.java
  24. 128 32
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchivesAutoServiceImpl.java
  25. 23 2
      blade-service/blade-archive/src/main/java/org/springblade/archive/utils/FileUtils.java
  26. 3 3
      blade-service/blade-business/src/main/java/org/springblade/business/controller/EVisaTaskCheckController.java
  27. 183 79
      blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java
  28. 7 1
      blade-service/blade-business/src/main/java/org/springblade/business/controller/MetadataController.java
  29. 15 0
      blade-service/blade-business/src/main/java/org/springblade/business/feignClient/ArchiveFileClientImpl.java
  30. 2 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/ArchiveFileMapper.java
  31. 9 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/ArchiveFileMapper.xml
  32. 4 12
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/InformationQueryMapper.xml
  33. 2 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/MetadataClassificationMapper.java
  34. 5 1
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/MetadataClassificationMapper.xml
  35. 2 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/MetadataClassificationServiceImpl.java
  36. 16 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ArchiveTreeContractController.java
  37. 3 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ArchiveTreeController.java
  38. 47 22
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java
  39. 6 6
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreePrivateController.java
  40. 5 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/feign/WbsTreeContractClientImpl.java
  41. 5 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ArchiveTreeContractMapper.java
  42. 13 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ArchiveTreeContractMapper.xml
  43. 5 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IArchiveTreeContractService.java
  44. 7 7
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IWbsTreePrivateService.java
  45. 19 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ArchiveTreeContractServiceImpl.java
  46. 2 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ContractInfoServiceImpl.java
  47. 7 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ExcelTabServiceImpl.java
  48. 526 396
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreePrivateServiceImpl.java
  49. 142 75
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeServiceImpl.java

+ 1 - 0
blade-common/src/main/java/org/springblade/common/constant/LauncherConstant.java

@@ -29,6 +29,7 @@ public interface LauncherConstant {
 
 
 	String APPLICATION_MANAGER_NAME = APPLICATION_NAME_PREFIX +  "manager";
+
 	String APPLICATION_ARCHIVE_NAME = APPLICATION_NAME_PREFIX +  "archive";
 
 

+ 23 - 0
blade-common/src/main/java/org/springblade/common/constant/OssConstant.java

@@ -0,0 +1,23 @@
+package org.springblade.common.constant;
+
+public interface OssConstant {
+
+    /**
+     * 临时目录路径
+     */
+    String TEMP_DIRECTORY = "showtmp";
+    /**
+     * 归档目录路径
+     */
+    String ARCHIVE_DIRECTORY = "archive";
+
+    /**
+     * 归档目录路径
+     */
+    String NORMAL_DIRECTORY = "upload";
+
+    /**
+     * 分隔符
+     */
+    String SEPARATOR = "__";
+}

+ 16 - 0
blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/feign/NewIOSSClient.java

@@ -19,6 +19,7 @@ public interface NewIOSSClient {
     String UPLOAD_FILE_INFO_BYTE = API_PREFIX + "/uploadFileInfoByte";
     String UPLOAD_FILE_INFO_INPUT_STREAM = API_PREFIX + "/uploadFileInfoInputStream";
     String REMOVE_PDF_FILE = API_PREFIX + "/remove-file";
+    String UPLOAD_FILE_INFO_WITH_PATH = API_PREFIX + "/uploadFileInfoWithPath";
 
     @PostMapping(value = UPLOAD_FILE_INFO_INPUT_STREAM, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
     BladeFile uploadFileByInputStream(MultipartFile file);
@@ -26,6 +27,21 @@ public interface NewIOSSClient {
     @PostMapping(UPLOAD_FILE_INFO)
     BladeFile uploadFile(@RequestParam String fileName, @RequestParam String localFileUrl);
 
+    /**
+     *  规则  projectId/filePath/fileName,
+     *  如果projectId为空则为filePath/fileName
+     *  如果filePath为空,则为 upload/20230202/fileName
+     *  如果filePath为OssConstant.TEMP_DIRECTORY,一律放进临时目录 OssConstant.TEMP_DIRECTORY/fileName
+     * @param fileName
+     * @param localFileUrl
+     * @param filePath
+     * @param projectId
+     * @return
+     */
+    @PostMapping(UPLOAD_FILE_INFO_WITH_PATH)
+    BladeFile uploadFile(@RequestParam String fileName, @RequestParam  String localFileUrl,
+                         @RequestParam(required=false)  String filePath,@RequestParam(required=false) Long projectId);
+
     @PostMapping(UPLOAD_FILE_INFO_BYTE)
     BladeFile updateFile(@RequestBody byte[] fileByte, @RequestParam String fileName);
 

+ 101 - 0
blade-ops/blade-resource/src/main/java/org/springblade/resource/builder/ossre/AliossTemplateRe.java

@@ -4,18 +4,22 @@ import com.aliyun.oss.OSSClient;
 import com.aliyun.oss.common.utils.BinaryUtil;
 import com.aliyun.oss.model.*;
 
+import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
+import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
 import lombok.SneakyThrows;
+import org.springblade.common.constant.OssConstant;
 import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.oss.model.OssFile;
 import org.springblade.core.oss.props.OssProperties;
 import org.springblade.core.oss.rule.OssRule;
+import org.springblade.core.secure.utils.AuthUtil;
 import org.springblade.core.tool.jackson.JsonUtil;
 import org.springframework.util.StringUtils;
 import org.springframework.web.multipart.MultipartFile;
@@ -305,4 +309,101 @@ public class AliossTemplateRe implements OssTemplateRe {
         InitiateMultipartUploadResult initResult = this.ossClient.initiateMultipartUpload(request);
         return initResult;
     }
+
+    public BladeFile putFileWithPath(String fileName, String filePath,Long projectId, InputStream stream) {
+        try {
+
+            String suffix = "";
+            int indexOfDot = fileName.lastIndexOf('.');
+            if (indexOfDot > 0) {
+                suffix = fileName.substring(indexOfDot + 1);
+            }
+
+            String ossUrl = "";
+            // 判断容器是否存在,不存在就创建
+            String bucket=getBucketName();
+            if (!ossClient.doesBucketExist(bucket)) {
+                ossClient.createBucket(bucket);
+                CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucket);
+                createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
+                ossClient.createBucket(createBucketRequest);
+            }
+            // 设置文件路径和名称
+            //判断是否为存储成   upload/20230322/xxxx.pdf 还是指定目录 aaaa/bbbb.pdf
+            if (StringUtils.isEmpty(filePath)) {
+                Date now = new Date();
+                SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+                String formattedDate = sdf.format(now);
+                filePath = OssConstant.NORMAL_DIRECTORY + "/" + formattedDate;
+            }
+
+            //如果有项目ID,则存为 项目id/....  ,否则直接在最外层, 临时目录除外
+            if (!filePath.equals(OssConstant.TEMP_DIRECTORY)) {
+                if (projectId != null  ) {
+                    filePath = projectId + "/" + filePath;
+                }
+            }
+
+            String fileUrl = filePath + "/" + fileName;
+            ObjectMetadata objectMetadata = new ObjectMetadata();
+            objectMetadata.setContentType(getcontentType(suffix));
+            ossUrl = getOssHost() + fileUrl;
+
+            // 上传文件
+            PutObjectResult result = ossClient.putObject(new PutObjectRequest(bucket, fileUrl, stream,objectMetadata));
+
+            BladeFile file = new BladeFile();
+            file.setOriginalName(fileName);
+            file.setName(fileName);
+            file.setDomain(this.getOssHost(bucket));
+            file.setLink(ossUrl);
+            return file;
+        } catch (Throwable var9) {
+            throw var9;
+        }
+    }
+
+
+    //判断文件的格式
+    public  String getcontentType(String filenameExtension) {
+        if (".bmp".equalsIgnoreCase(filenameExtension)) {
+            return "image/bmp";
+        }
+        if (".gif".equalsIgnoreCase(filenameExtension)) {
+            return "image/gif";
+        }
+        if (".jpeg".equalsIgnoreCase(filenameExtension) || ".jpg".equalsIgnoreCase(filenameExtension)
+                || ".png".equalsIgnoreCase(filenameExtension)) {
+            return "image/jpg";
+        }
+        if(".mp4".equalsIgnoreCase(filenameExtension)){
+            return "video/mpeg4";
+        }
+        if (".html".equalsIgnoreCase(filenameExtension)) {
+            return "text/html";
+        }
+        if (".txt".equalsIgnoreCase(filenameExtension)) {
+            return "text/plain";
+        }
+        if (".vsd".equalsIgnoreCase(filenameExtension)) {
+            return "application/vnd.visio";
+        }
+        if (".pptx".equalsIgnoreCase(filenameExtension) || ".ppt".equalsIgnoreCase(filenameExtension)) {
+            return "application/vnd.ms-powerpoint";
+        }
+        if (".docx".equalsIgnoreCase(filenameExtension) || ".doc".equalsIgnoreCase(filenameExtension)) {
+            return "application/msword";
+        }
+        if (".xml".equalsIgnoreCase(filenameExtension)) {
+            return "text/xml";
+        }
+        if (".pdf".equalsIgnoreCase(filenameExtension)) {
+            return "application/pdf";
+        }
+        if (".xls".equalsIgnoreCase(filenameExtension) || ".xlsx".equalsIgnoreCase(filenameExtension)
+                || ".xlt".equalsIgnoreCase(filenameExtension)) {
+            return "application/x-xls";
+        }
+        return "application/pdf";
+    }
 }

+ 6 - 0
blade-ops/blade-resource/src/main/java/org/springblade/resource/builder/ossre/OssTemplateRe.java

@@ -2,6 +2,9 @@ package org.springblade.resource.builder.ossre;
 
 import com.aliyun.oss.model.*;
 import org.springblade.core.oss.OssTemplate;
+import org.springblade.core.oss.model.BladeFile;
+
+import java.io.InputStream;
 
 
 public interface OssTemplateRe extends OssTemplate {
@@ -14,4 +17,7 @@ public interface OssTemplateRe extends OssTemplate {
 
     // OSS 分片上传 初始化
     InitiateMultipartUploadResult initiateMultipartUpload(InitiateMultipartUploadRequest request);
+
+    //指定路径上传
+    BladeFile putFileWithPath(String fileName, String filePath,Long projectId, InputStream stream);
 }

+ 124 - 45
blade-ops/blade-resource/src/main/java/org/springblade/resource/endpoint/LargeFileEndpoint.java

@@ -16,56 +16,46 @@
  */
 package org.springblade.resource.endpoint;
 
-import cn.hutool.core.util.StrUtil;
+import com.aliyun.oss.model.*;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import io.swagger.annotations.Api;
 import lombok.AllArgsConstructor;
 import lombok.SneakyThrows;
 import org.apache.commons.fileupload.disk.DiskFileItem;
 import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.StringUtils;
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.springblade.common.constant.CommonConstant;
-import org.springblade.common.utils.SnowFlakeUtil;
+import org.springblade.core.cache.utils.CacheUtil;
 import org.springblade.core.oss.model.BladeFile;
-import org.springblade.core.oss.model.OssFile;
 import org.springblade.core.secure.annotation.PreAuth;
 import org.springblade.core.tenant.annotation.NonDS;
 import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.constant.RoleConstant;
-import org.springblade.core.tool.utils.FileUtil;
-import org.springblade.core.tool.utils.Func;
 import org.springblade.core.tool.utils.ObjectUtil;
 import org.springblade.resource.builder.oss.OssBuilder;
-import org.springblade.resource.entity.Attach;
 import org.springblade.resource.entity.LargeFile;
 import org.springblade.resource.feign.CommonFileClient;
-import org.springblade.resource.service.IAttachService;
 import org.springblade.resource.service.ILargeFileService;
-import org.springblade.resource.service.IOssService;
 import org.springblade.resource.vo.MultipartFileParam;
 import org.springblade.resource.vo.NewBladeFile;
 import org.springblade.system.cache.ParamCache;
 import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.http.MediaType;
 import org.springframework.util.DigestUtils;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 import org.springframework.web.multipart.commons.CommonsMultipartFile;
 
-import javax.imageio.ImageIO;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.awt.*;
-import java.awt.image.BufferedImage;
 import java.io.*;
 import java.lang.reflect.Method;
 import java.nio.MappedByteBuffer;
-import java.nio.channels.FileChannel;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import java.util.ArrayList;
+import java.util.*;
 import java.util.List;
-import java.util.Objects;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
@@ -89,13 +79,16 @@ public class LargeFileEndpoint {
 	private final ILargeFileService iLargeFileService;
 
 	private final Lock lock = new ReentrantLock();
-	/**
-	 * 附件表服务
-	 */
-	private final IAttachService attachService;
 
 	private final CommonFileClient commonFileClient;
 
+	@Autowired
+	StringRedisTemplate RedisTemplate;
+
+	private final String bucketName ="bladex-chongqing-info";
+
+	private final String endpoint ="http://oss-cn-hangzhou.aliyuncs.com";
+
 	/**
 	 * 创建存储桶
 	 *
@@ -123,6 +116,115 @@ public class LargeFileEndpoint {
 		ossBuilder.template().removeBucket(bucketName);
 		return R.success("删除成功");
 	}
+
+
+	/**
+	 * @return
+	 * @throws Exception
+	 * **/
+	@SneakyThrows
+	@PostMapping("/upload-file1234")
+	public  R uploadByfile123(@RequestParam(value = "file",required=false) MultipartFile file,
+						   @RequestParam(value = "identifier",required=false) String identifier,
+						   @RequestParam(value = "chunkNumber",required=false) Integer chunkNumber,
+						   @RequestParam(value = "chunkSize",required=false) Integer chunkSize,
+						   @RequestParam(value = "currentChunkSize",required=false) String currentChunkSize,
+						   @RequestParam(value = "filename",required=false) String filename,
+						   @RequestParam(value = "relativePath",required=false) String relativePath,
+						   @RequestParam(value = "totalChunks",required=false) Integer totalChunks,
+						   @RequestParam(value = "totalSize",required=false) String totalSize,
+						   @RequestParam(value = "objectType",required=false) String objectType){
+
+		// 文件上传
+		String taskKey ="upload/20221220/"+ filename;
+		UmsAdminLoginLogDO param =new UmsAdminLoginLogDO();
+		if (file == null && totalChunks >=0 && StringUtils.isNotEmpty(identifier)) {
+			// 请求阿里云oss获取分片唯一ID
+			String ossSlicesId = this.getUploadId(taskKey);
+			RedisTemplate.opsForValue().set(identifier,ossSlicesId);
+			return R.fail("没有文件");
+		}
+
+		String uploadId = RedisTemplate.opsForValue().get(identifier);
+
+		UmsAdminLoginLogDO redisParam = (UmsAdminLoginLogDO) CacheUtil.get("oss","PartETag",uploadId);
+		if (redisParam !=null) {
+			param.setPartETags(redisParam.getPartETags());
+		}
+
+		Map<Integer, PartETag> partETags = param.getPartETags();
+
+		UploadPartRequest request = new UploadPartRequest();
+		request.setInputStream(file.getInputStream());
+		request.setBucketName(bucketName);
+		request.setPartNumber(chunkNumber);
+		request.setPartSize(Long.parseLong(currentChunkSize));
+		request.setKey(filename);
+		request.setMd5Digest(identifier);
+		request.setUploadId(uploadId);
+
+		try {
+			UploadPartResult uploadPartResult = ossBuilder.template().uploadPart(request);
+			PartETag partETag = uploadPartResult.getPartETag();
+			partETags.put(chunkNumber, partETag);
+			//分片编号等于总片数的时候合并文件,如果符合条件则合并文件,否则继续等待
+			if (chunkNumber == totalChunks) {
+				//合并文件,注意:partETags必须是所有分片的所以必须存入redis,然后取出放入集合
+				String url = this.completePartUploadFile(filename, uploadId,
+						new ArrayList<>(partETags.values()));
+				//oss地址返回后存入并清除redis
+				RedisTemplate.delete(uploadId);
+				return R.data(url);
+			}else {
+				RedisTemplate.opsForHash().putAll(uploadId, partETags);
+				CacheUtil.put("oss","PartETag",uploadId, param);
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+
+		return R.data("");
+	}
+
+	/**
+	 * 分块上传完成获取结果
+	 */
+	public String completePartUploadFile(String fileKey, String uploadId, List<PartETag> partETags) {
+		CompleteMultipartUploadRequest request = new CompleteMultipartUploadRequest(bucketName, fileKey, uploadId,
+				partETags);
+		ossBuilder.template().completeMultipartUpload(request);
+		String downLoadUrl = getDownloadUrl(fileKey, bucketName);
+		return downLoadUrl;
+	}
+
+	/**
+	 * 获取bucket文件的下载链接
+	 *
+	 * @param pathFile   首字母不带/的路径和文件
+	 * @param bucketName
+	 * @return 上报返回null, 成功返回地址
+	 */
+	public String getDownloadUrl(String pathFile, String bucketName) {
+		if (bucketName == null || "".equals(bucketName)) {
+			bucketName = bucketName;
+		}
+		StringBuffer url = new StringBuffer();
+		url.append("http://").append(bucketName).append(endpoint).append("/");
+		if (pathFile != null && !"".equals(pathFile)) {
+			url.append(pathFile);
+		}
+		return url.toString();
+	}
+
+	public String getUploadId(String fileKey) {
+		InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, fileKey);
+		// 初始化分片
+		InitiateMultipartUploadResult unrest = ossBuilder.template().initiateMultipartUpload(request);
+		// 返回uploadId,它是分片上传事件的唯一标识,您可以根据这个ID来发起相关的操作,如取消分片上传、查询分片上传等。
+		String uploadId = unrest.getUploadId();
+		return uploadId;
+	}
+
 	/**
 	 * @return
 	 * @throws Exception
@@ -206,13 +308,8 @@ public class LargeFileEndpoint {
 		String tempFileName = param.getIdentifier() + fileName.substring(fileName.lastIndexOf(".")) + "."+param.getChunkNumber();
 		// 获取文件路径
 		/**Windows文件路径要加在哪个盘**/
-//		String filePath = "D:/www/wwwroot/Users/hongchuangyanfa/Desktop/Desktop/ceshi";
 		String filePath =ParamCache.getValue(CommonConstant.SYS_LOCAL_URL)+"largeFile/";
-		// 创建文件夹
-//		getAbsoluteFile(filePath, fileName);
-//		new File(filePath, fileName);
-		// 创建临时文件
-//		File tempFile = new File(filePath, tempFileName);
+
 		File tempFile = buildUploadFile(tempFileName);
 		param.getFile().transferTo(tempFile);
 
@@ -220,25 +317,8 @@ public class LargeFileEndpoint {
 		 * 以上意思是把每个分片都保存成本地一个文件,如 测试.mp4.1 最后合并
 		 * ===================================================
 		 * 以下注释是把分片存到一个文件,持续写入,感觉不太保险**/
-//		//第一步 获取RandomAccessFile,随机访问文件类的对象
-//		RandomAccessFile raf = new RandomAccessFile(tempFile,"rw");
-//		//第二步 调用RandomAccessFile的getChannel()方法,打开文件通道 FileChannel
-//		FileChannel fileChannel = raf.getChannel();
-//		//第三步 获取当前是第几个分块,计算文件的最后偏移量
-//		long offset = (param.getChunkNumber() - 1) * param.getChunkSize();
-//		//第四步 获取当前文件分块的字节数组,用于获取文件字节长度
-//		byte[] fileData = param.getFile().getBytes();
-//		//第五步 使用文件通道FileChannel类的 map()方法创建直接字节缓冲器  MappedByteBuffer
-//		MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, offset, fileData.length);
-//		//第六步 将分块的字节数组放入到当前位置的缓冲区内  mappedByteBuffer.put(byte[] b)
-//		mappedByteBuffer.put(fileData);
-//		//第七步 释放缓冲区
-//		freeMappedByteBuffer(mappedByteBuffer);
-//		fileChannel.close();
-//		raf.close();
-		//第八步,保存分片信息
-		LargeFile largeFile = new LargeFile();
 
+		LargeFile largeFile = new LargeFile();
 		largeFile.setFileKey(param.getIdentifier());
 		largeFile.setName(tempFileName);
 		largeFile.setPath(filePath+fileName);
@@ -301,7 +381,6 @@ public class LargeFileEndpoint {
 				result.setSuccess(true);
 				result.setMsg("上传成功!");
 				result.setData(newBladeFile);
-//				result.setData(new BladeFile());
 				result.setCode(200);
 				return result;
 			}

+ 12 - 0
blade-ops/blade-resource/src/main/java/org/springblade/resource/feign/NewIOSSClientImpl.java

@@ -66,4 +66,16 @@ public class NewIOSSClientImpl implements NewIOSSClient {
         }
         return null;
     }
+
+    @Override
+    public BladeFile uploadFile(String fileName, String localFileUrl,String filePath, Long projectId) {
+        try {
+            //获取文件流
+            InputStream inputStream = new FileInputStream(new File(localFileUrl));
+            return this.ossBuilder.template().putFileWithPath(fileName,filePath, projectId,inputStream);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
 }

+ 3 - 1
blade-service-api/blade-archive-api/src/main/java/org/springblade/archive/vo/ArchiveExaminingSocketVo.java

@@ -14,12 +14,14 @@ import java.util.List;
 public class ArchiveExaminingSocketVo {
     private Integer status;
     private List<ArchiveExaminingReportDetail> detailList;
+    private String pdfUrl;
 
     public ArchiveExaminingSocketVo() {
     }
 
-    public ArchiveExaminingSocketVo(Integer status, List<ArchiveExaminingReportDetail> detailList) {
+    public ArchiveExaminingSocketVo(Integer status,String pdfUrl,List<ArchiveExaminingReportDetail> detailList) {
         this.status = status;
+        this.pdfUrl = pdfUrl;
         this.detailList = detailList;
     }
 }

+ 9 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/ArchiveFile.java

@@ -261,4 +261,13 @@ public class ArchiveFile extends BaseEntity {
 	 */
 	@ApiModelProperty("数据源类型,1原生,2数字化")
 	private Integer sourceType;
+
+	@ApiModelProperty("打了页码的pdf文件")
+	private String pdfPageUrl;
+
+	/**
+	 * 是否案卷四要素
+	 */
+	@ApiModelProperty("是否案卷四要素,0否,1是")
+	private Integer isElement;
 }

+ 7 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/feign/ArchiveFileClient.java

@@ -74,6 +74,13 @@ public interface ArchiveFileClient {
     @PostMapping(API_PREFIX + "/getAllArchiveFileSize")
     Long getAllArchiveFileSize(@RequestBody Long projectId);
 
+    @PostMapping(API_PREFIX + "/getAllArchiveFileByArchiveIds")
+    List<ArchiveFile> getAllArchiveFileByArchiveIds(@RequestBody List<String> ids);
+
+    //批量删除档案文件
+    @PostMapping(API_PREFIX + "/batchDeleteArchiveFile")
+    void batchDeleteArchiveFile(@RequestBody List<Long> ids);
+
     @PostMapping(API_PREFIX + "/getListByNodeID")
     List<ArchiveFile> getListByNodeID(@RequestParam String nodeId,@RequestParam Integer isArchive);
 }

+ 2 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/feign/OperationLogClient.java

@@ -3,6 +3,7 @@ package org.springblade.business.feign;
 import com.alibaba.fastjson.JSONObject;
 import org.springblade.common.constant.BusinessConstant;
 import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestParam;
@@ -22,6 +23,7 @@ public interface OperationLogClient {
      * @param json 操作的业务数据
      */
     @PostMapping(API_PREFIX + "/saveUserOperationLog")
+    @Async
     void saveUserOperationLog(@RequestParam Integer type, @RequestParam String operationModule, @RequestParam String operationView, @RequestBody JSONObject json);
 
 }

+ 3 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/feign/RecycleBinClient.java

@@ -1,7 +1,9 @@
 package org.springblade.business.feign;
 
+import org.checkerframework.checker.units.qual.A;
 import org.springblade.common.constant.BusinessConstant;
 import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestParam;
@@ -26,6 +28,7 @@ public interface RecycleBinClient {
      * @param contractId 合同段ID
      */
     @PostMapping(API_PREFIX + "/saveDelBusinessData")
+    @Async
     void saveDelBusinessData(@RequestBody List<String> businessIds, @RequestParam String title, @RequestParam Integer deletedType, @RequestParam String position, @RequestParam String projectId, @RequestParam String contractId);
 
 }

+ 7 - 2
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/feign/WbsTreeContractClient.java

@@ -132,7 +132,9 @@ public interface WbsTreeContractClient {
      * @return 结果
      */
     @PostMapping(API_PREFIX + "/queryCurrentNodeAllChild")
-    List<WbsTreeContract> queryCurrentNodeAllChild(@RequestParam Long contractId, @RequestParam Long parentId);/**
+    List<WbsTreeContract> queryCurrentNodeAllChild(@RequestParam Long contractId, @RequestParam Long parentId);
+
+    /**
      * 获取所有子节点
      *
      * @param contractId 合同段ID
@@ -164,9 +166,12 @@ public interface WbsTreeContractClient {
     WbsTreeContract queryWbsTreeContractById(@RequestParam String contractId, @RequestParam Long parseLong);
 
     @GetMapping(API_PREFIX + "/queryWbsTreeContractTreeLazy")
-    List<WbsTreeContractTreeVOS> queryWbsTreeContractTreeLazy(@RequestParam String contractId,@RequestParam Long parseLong);
+    List<WbsTreeContractTreeVOS> queryWbsTreeContractTreeLazy(@RequestParam String contractId, @RequestParam Long parseLong);
 
     @GetMapping(API_PREFIX + "/getAllTableFileSize")
     Long getAllTableFileSize(@RequestParam Long projectId);
 
+    @PostMapping(API_PREFIX + "/updateTabFileTypeByPkeyIds")
+    void updateTabFileTypeByPkeyIds(@RequestParam List<Long> updatePKeyIds);
+
 }

+ 14 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/ArchiveTreeContractVO3.java

@@ -0,0 +1,14 @@
+package org.springblade.manager.vo;
+
+import lombok.Data;
+import org.springblade.manager.entity.ArchiveTreeContract;
+
+/**
+ * @Param
+ * @Author wangwl
+ * @Date 2023/4/25 15:14
+ **/
+@Data
+public class ArchiveTreeContractVO3 extends ArchiveTreeContract {
+    private boolean notExsitChild;
+}

+ 7 - 0
blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchiveExaminingReportController.java

@@ -5,6 +5,7 @@ import com.itextpdf.text.DocumentException;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
+import lombok.extern.java.Log;
 import org.springblade.archive.entity.ArchiveExaminingReport;
 import org.springblade.archive.service.IArchiveExaminingReportService;
 import org.springblade.archive.vo.ArchiveExaminingVo;
@@ -102,4 +103,10 @@ public class ArchiveExaminingReportController {
 
     }
 
+    @GetMapping("/getCurrentExaminingInfo")
+    @ApiOperation(value = "获取当前正在检测的报告信息")
+    public R getCurrentExaminingInfo(Long reportId){
+        return R.data(archiveExaminingReportService.getCurrentExaminingInfo(reportId));
+    }
+
 }

+ 67 - 1
blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchivesAutoController.java

@@ -16,11 +16,13 @@
  */
 package org.springblade.archive.controller;
 
+import cn.hutool.core.text.split.SplitIter;
 import io.swagger.annotations.*;
 import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
 import lombok.AllArgsConstructor;
 import javax.validation.Valid;
 
+import org.apache.commons.lang.StringUtils;
 import org.springblade.archive.service.IArchiveAutoPdfService;
 import org.springblade.common.utils.CommonUtil;
 import org.springblade.core.mp.support.Condition;
@@ -36,6 +38,7 @@ import org.springblade.archive.wrapper.ArchivesAutoWrapper;
 import org.springblade.archive.service.IArchivesAutoService;
 import org.springblade.core.boot.ctrl.BladeController;
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
@@ -103,7 +106,8 @@ public class ArchivesAutoController extends BladeController {
 			@ApiImplicitParam(name = "secretLevel", value = "保密级别"),
 			@ApiImplicitParam(name = "carrierType", value = "类别"),
 			@ApiImplicitParam(name = "queryValue", value = "输入框模糊搜索"),
-			@ApiImplicitParam(name = "searchType", value = "搜索类型1案卷2文件")
+			@ApiImplicitParam(name = "searchType", value = "搜索类型1案卷2文件"),
+			@ApiImplicitParam(name = "nodeIds", value = "搜索树的节点id集合")
 	})
 	public R<IPage<ArchivesAutoVO>> pageByArchivesAuto(ArchivesAutoVO archivesAuto) {
 		IPage<ArchivesAutoVO> pages = archivesAutoService.pageByArchivesAuto(archivesAuto);
@@ -173,6 +177,56 @@ public class ArchivesAutoController extends BladeController {
 		return R.status(archivesAutoService.saveOrUpdate(archivesAuto));
 	}
 
+	/**
+	 * 分页-档案鉴定
+	 */
+	@GetMapping("/pageByAuthenticate")
+	@ApiOperationSupport(order = 3)
+	@ApiOperation(value = "分页-档案鉴定", notes = "传入archivesAuto")
+	@ApiImplicitParams({
+			@ApiImplicitParam(name = "nodeId", value = "节点id", required = true),
+			@ApiImplicitParam(name = "projectId", value = "项目id", required = true),
+			@ApiImplicitParam(name = "storageTime", value = "保管期限", required = false),
+			@ApiImplicitParam(name = "filingUnit", value = "立卷单位", required = false),
+			@ApiImplicitParam(name = "isDeleted", value = "是否删除", required = false)
+	})
+	public R<IPage<ArchivesAutoVO>> pageByAuthenticate(ArchivesAutoVO archivesAuto) {
+		IPage<ArchivesAutoVO> pages = archivesAutoService.pageByAuthenticate(archivesAuto);
+		return R.data(pages);
+	}
+
+	/**
+	 * 批量销毁档案-档案鉴定
+	 */
+	@GetMapping("/batchDestroyArchive")
+	@ApiOperationSupport(order = 3)
+	@ApiOperation(value = "批量销毁档案-档案鉴定", notes = "传入节点id")
+	@ApiImplicitParams({
+			@ApiImplicitParam(name = "nodeId", value = "节点id", required = true),
+	})
+	public R batchDestroyArchive(String ids ){
+		if (StringUtils.isBlank(ids)){
+			return R.fail("参数错误");
+		}
+		archivesAutoService.batchDestroyArchive(ids);
+		return R.success("销毁成功");
+	}
+
+	/**
+	 * 获取立卷单位列表-档案鉴定
+	 */
+	@GetMapping("/getFilingUnitList")
+	@ApiOperationSupport(order = 3)
+	@ApiOperation(value = "获取立卷单位列表-档案鉴定", notes = "传入节点id")
+	@ApiImplicitParams({
+			@ApiImplicitParam(name = "nodeId", value = "节点id", required = true),
+	})
+	public R getFilingUnitList(Long projectId){
+		return R.data(archivesAutoService.getFilingUnitList(projectId));
+	}
+
+
+
 	
 	/**
 	 * 删除 
@@ -252,6 +306,18 @@ public class ArchivesAutoController extends BladeController {
 		return R.data("");
 	}
 
+	/**
+	 * 预览案卷文件
+	 */
+	@GetMapping("/printArchive")
+	@ApiOperationSupport(order = 3)
+	@ApiOperation(value = "预览案卷文件")
+	public R printArchive(Long id) {
+		//统计案卷文件大小
+		String url = archivesAutoService.getMergeArchivesFile(id);
+		return R.data(url);
+	}
+
 
 
 }

+ 11 - 0
blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/ArchivesAutoMapper.java

@@ -64,6 +64,16 @@ public interface ArchivesAutoMapper extends BaseMapper<ArchivesAuto> {
 	 */
     List<ArchivesAutoVO> pageByArchivesAuto(IPage page, @Param("vo") ArchivesAutoVO vo);
 
+	/**
+	 *  档案利用-档案查询,带范围
+	 */
+	List<ArchivesAutoVO> pageByArchivesAuto2(IPage page, @Param("vo") ArchivesAutoVO vo);
+
+	/**
+	 *  档案鉴定-档案查询
+	 */
+	List<ArchivesAutoVO> pageByAuthenticate(IPage page, @Param("vo") ArchivesAutoVO vo);
+
 	/**
 	 * 获取当前项目所有案卷,并设置合同类型
 	 */
@@ -75,4 +85,5 @@ public interface ArchivesAutoMapper extends BaseMapper<ArchivesAuto> {
 	@MapKey("storage_time")
 	List<Map<String,String>> getAllArchiveAgeByContractType(@Param("projectId") Long projectId);
 
+	List<String> getFilingUnitList(@Param("projectId") Long projectId);
 }

+ 69 - 0
blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/ArchivesAutoMapper.xml

@@ -182,6 +182,54 @@
         </if>
         GROUP BY uaa.id
     </select>
+
+    <select id="pageByArchivesAuto2" resultMap="archivesAutoResultMap">
+        select uaa.* from
+        (SELECT id FROM m_archive_tree_contract WHERE project_id =#{vo.projectId}
+        <foreach collection="vo.nodeIdArray" item="nodeId">
+            and ancestors like concat('%',#{nodeId},'%') or id = #{nodeId}
+        </foreach>
+        ) matc left join u_archives_auto uaa on matc.id = uaa.node_id left join u_archive_file uaf on uaa.id = uaf.archive_id
+        where uaa.is_deleted = 0
+        <if test="vo.searchType == 1 and vo.queryValue != null and vo.queryValue != ''">
+            and uaa.name like concat('%',#{vo.queryValue},'%')
+        </if>
+        <if test="vo.searchType == 2 and vo.queryValue != null and vo.queryValue != ''">
+            and uaf.file_name like concat('%',#{vo.queryValue},'%')
+        </if>
+        <if test="vo.storageTimes != null and vo.storageTimes != ''">
+            and uaa.storage_time in
+            <foreach collection="vo.storageTimes" item="storageTime" open="(" separator="," close=")">
+                #{storageTime}
+            </foreach>
+        </if>
+        <if test="vo.secretLevels != null and vo.secretLevels != ''">
+            and uaa.secret_level in
+            <foreach collection="vo.secretLevels" item="secretLevel" open="(" separator="," close=")">
+                #{secretLevel}
+            </foreach>
+        </if>
+        <if test="vo.carrierTypes != null and vo.carrierTypes != ''">
+            and uaa.carrier_type in
+            <foreach collection="vo.carrierTypes" item="carrierType" open="(" separator="," close=")">
+                #{carrierType}
+            </foreach>
+        </if>
+        <if test="vo.years != null and vo.years != ''">
+            and
+            <foreach collection="vo.years" item="year" separator=" or" open="(" close=")" >
+                #{year} BETWEEN  DATE_FORMAT(uaa.start_date,'%Y') and DATE_FORMAT(uaa.end_date ,'%Y')
+            </foreach>
+        </if>
+        <if test="vo.months != null and vo.months != ''">
+            and
+            <foreach collection="vo.months" item="month" separator=" or" open="(" close=")">
+                #{month} BETWEEN  DATE_FORMAT(uaa.start_date,'%c') and DATE_FORMAT(uaa.end_date ,'%c')
+            </foreach>
+        </if>
+        GROUP BY uaa.id
+    </select>
+
     <select id="getAllArchiveByContractType" resultType="org.springblade.archive.vo.ArchivesAutoVO">
         SELECT uaa.id,matc.tree_code as 'contractType'
         FROM m_archive_tree_contract matc left join u_archives_auto uaa on uaa.node_id =matc.id
@@ -193,6 +241,27 @@
         WHERE matc.project_id =#{projectId} and uaa.is_deleted =0
         GROUP BY uaa.storage_time
     </select>
+<!--    档案鉴定,档案查询-->
+    <select id="pageByAuthenticate" resultType="org.springblade.archive.vo.ArchivesAutoVO">
+        select uaa.*
+        from(
+                select id from m_archive_tree_contract
+                where project_id = #{vo.projectId} and ancestors like concat('%', #{vo.nodeId}, '%') or id = #{vo.nodeId}
+            ) matc
+        left join u_archives_auto uaa on matc.id = uaa.node_id
+        where uaa.is_deleted = #{vo.isDeleted}
+        <if test="vo.storageTime != null and vo.storageTime != ''">
+            and uaa.storage_time = #{vo.storageTime}
+        </if>
+        <if test="vo.filingUnit != null and vo.filingUnit != ''">
+            and uaa.filing_unit = #{vo.filingUnit}
+        </if>
+    </select>
+    <select id="getFilingUnitList" resultType="java.lang.String">
+        SELECT filing_unit
+        FROM  u_archives_auto WHERE project_id =#{projectId} AND filing_unit is not NULL
+        GROUP BY filing_unit
+    </select>
 
 
 </mapper>

+ 4 - 1
blade-service/blade-archive/src/main/java/org/springblade/archive/service/IArchiveAutoPdfService.java

@@ -18,11 +18,14 @@ public interface IArchiveAutoPdfService {
     void builtFilePageNo(ArchivesAuto archivesAuto, List<ArchiveFile> waitArchiveFiles);
 
     // 单个pdf 生成
-    String getBussPdfInfo(String fileName, Map<String, Object> DataInfo, String excelUrl, String filePath )throws Exception;
+    String getBussPdfInfo(String fileName, Map<String, Object> DataInfo, String excelUrl, String localPath ,String ossPath, Long projectId )throws Exception;
 
     //获取文件的pdf文件的url
     String getPdfFileUrl(ArchiveFile file);
 
     //只刷新档号
     boolean refreshFileNumber(ArchivesAuto archive,String fileNumber);
+
+    //合并pdf
+    String MergePdfAndUpload(List<String> urlList,String fileName,String filePath,Long projectId) ;
 }

+ 2 - 0
blade-service/blade-archive/src/main/java/org/springblade/archive/service/IArchiveExaminingReportService.java

@@ -2,6 +2,7 @@ package org.springblade.archive.service;
 
 import com.itextpdf.text.DocumentException;
 import org.springblade.archive.entity.ArchiveExaminingReport;
+import org.springblade.archive.vo.ArchiveExaminingSocketVo;
 import org.springblade.archive.vo.ArchiveExaminingVo;
 import org.springblade.core.mp.base.BaseService;
 
@@ -17,4 +18,5 @@ public interface IArchiveExaminingReportService extends BaseService<ArchiveExami
 
     void getExamining(ArchiveExaminingVo vo, Long id) throws InterruptedException, DocumentException, IOException;
 
+    ArchiveExaminingSocketVo getCurrentExaminingInfo(Long reportId);
 }

+ 8 - 0
blade-service/blade-archive/src/main/java/org/springblade/archive/service/IArchivesAutoService.java

@@ -51,7 +51,15 @@ public interface IArchivesAutoService extends BaseService<ArchivesAuto> {
 
 	List<Map<String, String>> getAllArchiveAgeByContractType(Long projectId);
 
+    IPage<ArchivesAutoVO> pageByAuthenticate(ArchivesAutoVO archivesAuto);
+
+	List<String> getFilingUnitList(Long projectId);
+
+	void batchDestroyArchive(String ids);
+
 	void archiveAutoMethod(Long project);
 
 	void splitArchvies(Long project);
+
+	public String getMergeArchivesFile(Long archiveId);
 }

+ 57 - 17
blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveAutoPdfServiceImpl.java

@@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import com.itextpdf.text.Element;
 import com.itextpdf.text.pdf.*;
 import lombok.AllArgsConstructor;
+import org.apache.commons.lang.StringUtils;
 import org.apache.poi.ss.usermodel.*;
 import org.apache.poi.util.IOUtils;
 import org.springblade.archive.entity.ArchiveFormulaConfig;
@@ -18,11 +19,13 @@ import org.springblade.archive.utils.FileUtils;
 import org.springblade.archive.utils.FormulaUtil;
 import org.springblade.business.entity.ArchiveFile;
 import org.springblade.business.feign.ArchiveFileClient;
+import org.springblade.common.constant.OssConstant;
 import org.springblade.common.utils.CommonUtil;
 import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.common.vo.DataVO;
 import org.springblade.common.vo.FileSize;
 import org.springblade.core.oss.model.BladeFile;
+import org.springblade.core.secure.utils.AuthUtil;
 import org.springblade.core.tool.utils.ObjectUtil;
 import org.springblade.core.tool.utils.ResourceUtil;
 import org.springblade.core.tool.utils.StringUtil;
@@ -91,7 +94,7 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
         String key1 =  "2__"+ dataVO1.getY() + "_" + dataVO1.getX();
         DataInfo.put(key1,"hahahahaa");
         try {
-            String url = getBussPdfInfo(pkeyId.toString(),DataInfo,excelUrl,file_path);
+            String url = getBussPdfInfo(pkeyId.toString(),DataInfo,excelUrl,file_path,null,null);
         } catch (Exception e) {
             e.printStackTrace();
         }
@@ -265,7 +268,7 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
 
         List<String> pageUrls = FileUtils.doForPageNumberUseItextpdf(urls,newIOSSClient);
         for(int i=0;i<waitArchiveFiles.size();i++){
-            waitArchiveFiles.get(i).setPdfFileUrl(pageUrls.get(i));
+            waitArchiveFiles.get(i).setPdfPageUrl(pageUrls.get(i));
         }
 
         return;
@@ -288,7 +291,8 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
         Map<String, Object> dataInfo = new HashMap<>();
 
         ArchiveFormulaConfig multiLineconfig = null;
-        String fileName = NAME_MAP.get(number)+ "-" + archivesAuto.getId();
+        //采取
+        String fileName = FileUtils.generateFilename(number,0,archivesAuto.getId());
 
         for (ArchiveFormulaConfig config : formulaConfigs) {
             String coords = config.getCoords();
@@ -309,11 +313,11 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
         if (multiLineconfig != null) {
             String coords = multiLineconfig.getCoords();
             String formula = multiLineconfig.getFormula();
-            handleArchiveFile(coords, formula, variables, file_path, excelUrl, dataInfo,urls,fileName);
+            handleArchiveFile(coords, formula, variables, file_path, excelUrl, dataInfo,urls,fileName, archivesAuto.getProjectId());
 
         }else {
             try {
-                String url = getBussPdfInfo(fileName, dataInfo, excelUrl, file_path);
+                String url = getBussPdfInfo(fileName, dataInfo, excelUrl, file_path,OssConstant.ARCHIVE_DIRECTORY,archivesAuto.getProjectId());
                 urls.add(url);
             } catch (Exception e) {
                 e.printStackTrace();
@@ -334,7 +338,7 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
      */
     private void handleArchiveFile(String coords, String formula,
                                    Map<String,Object> variables,String file_path,
-                                   String excelUrl, Map<String, Object> dataInfo,List<String> urls,String fileName){
+                                   String excelUrl, Map<String, Object> dataInfo,List<String> urls,String fileName,Long projectId){
         //todo  目录多页合并一页,文件名带上
 
 
@@ -377,7 +381,7 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
                         subIndex++;
                     }
                     try {
-                        String url = getBussPdfInfo(fileName + subIndex, pageMap, excelUrl, file_path);
+                        String url = getBussPdfInfo(fileName + subIndex, pageMap, excelUrl, file_path,OssConstant.ARCHIVE_DIRECTORY,projectId);
                         localUrls.add(url);
                     } catch (Exception e) {
                         e.printStackTrace();
@@ -395,11 +399,11 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
         //合并成一个
         if (localUrls.size() > 1) {
             Long id = SnowFlakeUtil.getId();
-            String trialPdf = file_path + "/pdf/" + id + ".pdf";
+            String localPdf = file_path + "/pdf/" + id + ".pdf";
 
             //合并当前所有选择的试验pdf
-            FileUtils.mergePdfPublicMethods(localUrls, trialPdf);
-            BladeFile bladeFile = this.newIOSSClient.uploadFile(fileName + ".pdf", trialPdf);
+            FileUtils.mergePdfPublicMethods(localUrls, localPdf);
+            BladeFile bladeFile = this.newIOSSClient.uploadFile(fileName + ".pdf", localPdf, OssConstant.ARCHIVE_DIRECTORY,projectId);
 
 
 //            ByteArrayOutputStream bos = new ByteArrayOutputStream();
@@ -452,19 +456,23 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
      * @param fileName   文件名
      * @param DataInfo  excel和数据
      * @param excelUrl  excel模板
-     * @param filePath  本地路径
+     * @param localPath  本地路径
+     * @param ossPath  oss上的路径
+     * @param projectId 项目ID
      * @return
      * @throws Exception
      */
-    public String getBussPdfInfo(String fileName,Map<String, Object> DataInfo,String excelUrl,String filePath) throws Exception{
+    public String getBussPdfInfo(String fileName,Map<String, Object> DataInfo,String excelUrl,String localPath,
+         String ossPath, Long projectId) throws Exception{
 
         if (fileName == null) {
             fileName = SnowFlakeUtil.getId().toString();
         }
 
-        String pdfPath = filePath + "/pdf//" + fileName + ".pdf";
-        String excelPath = filePath + "/pdf//" + fileName + ".xlsx";
-        File tabPdf = ResourceUtil.getFile(pdfPath);
+        //本地文件路径
+        String localPdfPath = localPath + "/pdf//" + fileName + ".pdf";
+        String excelPath = localPath + "/pdf//" + fileName + ".xlsx";
+        File tabPdf = ResourceUtil.getFile(localPdfPath);
         if (tabPdf.exists()) {
             tabPdf.delete();
         }
@@ -546,8 +554,8 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
 
         FileOutputStream outputStream = new FileOutputStream(excelPath);
         workbook.write(outputStream);
-        FileUtils.setExcelScaleToPdf(excelPath, pdfPath);
-        BladeFile bladeFile = newIOSSClient.uploadFile(fileName + ".pdf", pdfPath);
+        FileUtils.setExcelScaleToPdf(excelPath, localPdfPath);
+        BladeFile bladeFile = newIOSSClient.uploadFile(fileName + ".pdf", localPdfPath,ossPath, projectId);
 
         String pdfLink = "";
         if (bladeFile!= null ){
@@ -734,4 +742,36 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
         return true;
     }
 
+    /**
+     * 合并pdf并上传到oss
+     * @param urlList
+     * @param fileName
+     * @return
+     */
+    public String MergePdfAndUpload(List<String> urlList,String fileName,String filePath,Long pojectId) {
+       String url = "";
+       Long id = SnowFlakeUtil.getId();
+       String localPdf = FileUtils.LocalPath + "/pdf/" + id + ".pdf";
+
+       try {
+            //合并pdf
+            FileUtils.mergePdfPublicMethods(urlList,localPdf);
+
+            if (StringUtils.isEmpty(filePath)) {
+                filePath = OssConstant.TEMP_DIRECTORY;
+            }
+
+            fileName += (OssConstant.SEPARATOR + id);
+
+            //上传到oss
+            BladeFile file  = newIOSSClient.uploadFile(fileName+ ".pdf", localPdf,filePath,pojectId);
+            url = file.getLink();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return url;
+    }
+
+
+
 }

+ 49 - 19
blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveExaminingReportImpl.java

@@ -56,22 +56,28 @@ public class ArchiveExaminingReportImpl extends BaseServiceImpl<ArchiveExamining
     @Async
     @Override
     public void pushStatusBySocket(Long userId,Long id) throws IOException, InterruptedException {
-        Integer status;
-        //获取检测状态,如果正在检测,则一直推送
+        Integer status=1;
+        Date date = new Date();
+        //获取检测状态,如果正在检测,则数据变化时发送
         do {
-            Thread.sleep(5000L);
-            //获取最新检测的状态
+            Thread.sleep(4000L);
+            //判断报告状态
             ArchiveExaminingReport report = this.getById(id);
-            status = report.getStatus();
-            //获取检测详情
-            List<ArchiveExaminingReportDetail> list = detailService.list(new LambdaQueryWrapper<ArchiveExaminingReportDetail>()
-                    .eq(ArchiveExaminingReportDetail::getReportId, id));
-            for (ArchiveExaminingReportDetail detail : list) {
-                detail.setExaminingItem(detail.getExaminingType()+":"+detail.getExaminingItem());
+            Integer reportStatus = report.getStatus();
+            //判断详情状态
+            ArchiveExaminingReportDetail detail = detailService.getOne(new LambdaQueryWrapper<ArchiveExaminingReportDetail>()
+                    .eq(ArchiveExaminingReportDetail::getReportId, id)
+                    .orderByDesc(ArchiveExaminingReportDetail::getCreateTime)
+                    .last("limit 1"));
+            if (detail == null){
+                detail = new ArchiveExaminingReportDetail();
+                detail.setCreateTime(date);
+            }
+            if (reportStatus != status || detail.getCreateTime() != date){
+                webSocketServer.sendMessagesToArchive(userId+"","true");
+                status = reportStatus;
+                date = detail.getCreateTime();
             }
-            ArchiveExaminingSocketVo vo = new ArchiveExaminingSocketVo(status,list);
-            webSocketServer.sendMessagesToArchive(userId+"", JSON.toJSONString(vo));
-            status = report.getStatus();
         }while (status != 4);
 
     }
@@ -90,7 +96,7 @@ public class ArchiveExaminingReportImpl extends BaseServiceImpl<ArchiveExamining
         //检测中
             //真实性
         if (StringUtils.isNotBlank(vo.getAuthenticity()) && "1".equals(vo.getAuthenticity())) {
-            Thread.sleep(7000L);
+            Thread.sleep(5000L);
             detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_AUTHENTICITY,
                     ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对固化信息有效性检测", 0, "无", 0));
             detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_AUTHENTICITY,
@@ -117,7 +123,7 @@ public class ArchiveExaminingReportImpl extends BaseServiceImpl<ArchiveExamining
                     ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对电子档案封装包电子前面有效性检测", 0, "无", 0));
         }
         if (StringUtils.isNotBlank(vo.getIntegrality()) && "1".equals(vo.getIntegrality())) {
-            Thread.sleep(7000L);
+            Thread.sleep(5000L);
             //完整性
             detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_INTEGRALITY,
                     ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对总件数相符性检测", 0, "无", 0));
@@ -144,7 +150,7 @@ public class ArchiveExaminingReportImpl extends BaseServiceImpl<ArchiveExamining
         }
             //可用性
         if (StringUtils.isNotBlank(vo.getUsability()) && "1".equals(vo.getUsability())) {
-            Thread.sleep(7000L);
+            Thread.sleep(5000L);
             detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_USABILITY,
                     ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对信息包中元数据的可读性检测", 0, "无", 0));
             detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_USABILITY,
@@ -164,7 +170,7 @@ public class ArchiveExaminingReportImpl extends BaseServiceImpl<ArchiveExamining
         }
             //安全性
         if (StringUtils.isNotBlank(vo.getSecurity()) && "1".equals(vo.getSecurity())) {
-            Thread.sleep(7000L);
+            Thread.sleep(5000L);
             detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_SECURITY,
                     ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对系统环境中是否安装杀毒软件检测", 0, "无", 0));
             detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_SECURITY,
@@ -174,13 +180,32 @@ public class ArchiveExaminingReportImpl extends BaseServiceImpl<ArchiveExamining
         report.setStatus(3);
         this.updateById(report);
         String url = this.generateReportPdf(id);
-        Thread.sleep(7000L);
+        Thread.sleep(3000L);
         //完成
         report.setReportPdfUrl(url);
         report.setStatus(4);
         this.updateById(report);
     }
 
+    /**
+     * 获取最新的文档状态和详情
+     * @param reportId
+     * @return
+     */
+    @Override
+    public ArchiveExaminingSocketVo getCurrentExaminingInfo(Long reportId) {
+        //获取最新检测的状态
+        ArchiveExaminingReport report = this.getById(reportId);
+        //获取检测详情
+        List<ArchiveExaminingReportDetail> list = detailService.list(new LambdaQueryWrapper<ArchiveExaminingReportDetail>()
+                .eq(ArchiveExaminingReportDetail::getReportId, reportId));
+        for (ArchiveExaminingReportDetail detail : list) {
+            detail.setExaminingItem(detail.getExaminingType()+":"+detail.getExaminingItem());
+        }
+        ArchiveExaminingSocketVo vo = new ArchiveExaminingSocketVo(report.getStatus(),report.getReportPdfUrl(),list);
+        return vo;
+    }
+
     /**
      * 生成检测报告PDF
      */
@@ -189,6 +214,7 @@ public class ArchiveExaminingReportImpl extends BaseServiceImpl<ArchiveExamining
         int widthPercentage = 100;
         String uuid = StringUtil.randomUUID();
         String localUrl = "/www/wwwroot/Users/hongchuangyanfa/Desktop/archiveExaminingPdf/";
+//        String localUrl = "D:\\develop\\test\\";
         //新建一个pdf文档对象,前一个参数是纸张大小,后四个为边距
         Document document = new Document(PageSize.A4, 5, 5, 30, 30);
         //建立一个书写器
@@ -255,7 +281,11 @@ public class ArchiveExaminingReportImpl extends BaseServiceImpl<ArchiveExamining
         document.close();
         writer.close();
         BladeFile bladeFile = iossClient.uploadFile(uuid+".pdf", localUrl+uuid+".pdf");
-        return bladeFile.getLink();
+        if (bladeFile != null && StringUtils.isNotBlank(bladeFile.getLink())){
+            return bladeFile.getLink();
+        }else {
+            return null;
+        }
     }
 
 

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

@@ -27,14 +27,17 @@ import org.apache.commons.lang.StringUtils;
 import org.springblade.archive.entity.ArchivesAuto;
 import org.springblade.archive.service.IArchiveAutoPdfService;
 import org.springblade.archive.utils.ArchiveTreeUtil;
+import org.springblade.archive.utils.FileUtils;
 import org.springblade.archive.vo.ArchivesAutoVO;
 import org.springblade.archive.mapper.ArchivesAutoMapper;
 import org.springblade.archive.service.IArchivesAutoService;
 import org.springblade.business.entity.ArchiveFile;
 import org.springblade.business.feign.ArchiveFileClient;
+import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.core.mp.base.BaseServiceImpl;
 import org.springblade.core.mp.support.Condition;
 import org.springblade.core.mp.support.Query;
+import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.tool.utils.Func;
 import org.springblade.core.tool.utils.StringUtil;
 import org.springblade.manager.entity.ArchiveTreeContract;
@@ -72,7 +75,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 	private ContractClient contractClient;
 	private ProjectClient projectClient;
 
-	private Map<String,Integer> indexMap; //按立卷位区分和生成流水号
+	private Map<String,Integer> indexMap = new HashMap<>(); //按立卷位区分和生成流水号
 	private IArchiveAutoPdfService archiveAutoPdfService;
 
 
@@ -100,15 +103,23 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		if (StringUtils.isNotBlank(vo.getMonth())) {
 			vo.setMonths(Arrays.asList(vo.getMonth().split(",")));
 		}
-		List<ArchivesAutoVO> archivesAutos = baseMapper.pageByArchivesAuto(page, vo);
-		archivesAutos.stream().forEach(aa->{
-			if (StringUtils.isNotBlank(aa.getStorageTime())){
-				aa.setStorageTimeValue("9999".equals(aa.getStorageTime())?"永久":("30".equals(aa.getStorageTime())?"30年":"10年"));
-			}
-			if (StringUtils.isNotBlank(aa.getSecretLevel())){
-				aa.setSecretLevelValue("1".equals(aa.getSecretLevel())?"机密":("2".equals(aa.getSecretLevel())?"绝密":"秘密"));
-			}
-		});
+		List<ArchivesAutoVO> archivesAutos = null;
+		if (StringUtils.isNotBlank(vo.getNodeIds())){
+			vo.setNodeIdArray(Arrays.asList(vo.getNodeIds().split(",")));
+			archivesAutos = baseMapper.pageByArchivesAuto2(page, vo);
+		}else {
+			archivesAutos = baseMapper.pageByArchivesAuto(page, vo);
+		}
+		if (archivesAutos != null && archivesAutos.size() >0) {
+			archivesAutos.stream().forEach(aa -> {
+				if (StringUtils.isNotBlank(aa.getStorageTime())) {
+					aa.setStorageTimeValue("9999".equals(aa.getStorageTime()) ? "永久" : ("30".equals(aa.getStorageTime()) ? "30年" : "10年"));
+				}
+				if (StringUtils.isNotBlank(aa.getSecretLevel())) {
+					aa.setSecretLevelValue("1".equals(aa.getSecretLevel()) ? "机密" : ("2".equals(aa.getSecretLevel()) ? "绝密" : "秘密"));
+				}
+			});
+		}
 		return page.setRecords(archivesAutos);
 	}
 
@@ -221,8 +232,8 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 
 	@Override
 	public void archiveAutoMethod(Long projectId){
-		//步骤一:把项目下未锁定的案卷拆卷。
-
+		//步骤一:把档号集合初始化
+		indexMap = new HashMap<>();
 		//步骤二:查询归档树节点。存在未归档文件的节点。
 		List<ArchiveTreeContract> list = archiveTreeContractClient.getHavedFileNodeByProjectID(projectId);
 		//步骤三:遍历归档树节点整理出 默认规则节点,分类并卷节点,单独组卷节点 三个集合。
@@ -246,7 +257,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		//步骤四:按照单独,分类,默认,分盒的顺序执行组卷流程。
 
 		//分盒文件集合
-		Map<Integer,List<ArchiveFile>> boxMap = new HashMap<>();
+		Map<Integer,List<ArchiveFile>> boxMap = new LinkedHashMap<>();
 
 		archiveAutoMethod3(list3,boxMap);//单独组卷
 		archiveAutoMethod2(list2,projectId,boxMap);//分类组卷
@@ -267,6 +278,32 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		}
 	}
 
+	@Override
+	public IPage<ArchivesAutoVO> pageByAuthenticate(ArchivesAutoVO vo) {
+		IPage<ArchivesAutoVO> page = new Page<>(vo.getCurrent(),vo.getSize());
+		List<ArchivesAutoVO> list = baseMapper.pageByAuthenticate(page, vo);
+		return page.setRecords(list);
+	}
+
+	@Override
+	public List<String> getFilingUnitList(Long projectId) {
+		return baseMapper.getFilingUnitList(projectId);
+	}
+
+	@Override
+	public void batchDestroyArchive(String ids) {
+		List<String> list = Arrays.asList(ids.split(","));
+		//查询出档案的文件
+		List<ArchiveFile> files = archiveFileClient.getAllArchiveFileByArchiveIds(list);
+		//销毁阿里云上文件
+
+		//删除文件
+		List<Long> collect = files.stream().map(file -> file.getId()).collect(Collectors.toList());
+		archiveFileClient.batchDeleteArchiveFile(collect);
+		//删除案卷
+		baseMapper.deleteBatchIds(list);
+	}
+
 
 	/**
 	 * 检查当前案卷的文件集合是否在规格内,能否开始组卷。
@@ -407,7 +444,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		if(isCrossNode){
 			archiveName=projectName;
 			//存在跨节点  项目名称+文件对应的所有节点名称
-			Set<String> nodeIdSet = new HashSet<>();
+			Set<String> nodeIdSet = new LinkedHashSet<>();
 			for(ArchiveFile file:waitArchiveFiles){
 				String nodeId = file.getNodeId();
 				nodeIdSet.add(nodeId);
@@ -429,10 +466,8 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		return archiveName;
 	}
 	private String builtFilePageNo(ArchivesAuto archivesAuto,List<ArchiveFile> waitArchiveFiles){
-		//TODO 生成文件对应的页码,返回url
-
+		//生成文件对应的页码,返回url
 		archiveAutoPdfService.builtFilePageNo(archivesAuto,waitArchiveFiles);
-
 		this.updateById(archivesAuto);
 
 		return "";
@@ -494,8 +529,6 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		for(ArchiveFile file:waitArchiveFiles){
 			pageN=pageN+file.getFilePage();
 		}
-
-
 		//默认组卷存在跨节点组卷  注意案卷归属节点,案卷命名方式
 		//获取案卷题名
 		String archiveName=builtArchiveName(waitArchiveFiles,node,true);//获取案卷题名
@@ -611,14 +644,13 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		for(ArchiveTreeContract node:list){
 			//步骤2:获取当前节点的案卷规格
 			String specificationStr = node.getSpecification();
+			if(StringUtils.isEmpty(specificationStr)){
+				specificationStr="30";
+			}
 			int specification = Integer.parseInt(specificationStr);
 			int specificationSize=specification*10;
 			//步骤3:查询节点下的未组卷文件
-			List<ArchiveFile> archiveFiles = archiveFileClient.listWrappers(Wrappers.<ArchiveFile>lambdaQuery()
-					.eq(ArchiveFile::getNodeId, node)
-					.eq(ArchiveFile::getIsArchive, 0)
-					.eq(ArchiveFile::getIsDeleted,0)
-					.orderByAsc(ArchiveFile::getSort));
+			List<ArchiveFile> archiveFiles = archiveFileClient.getListByNodeID(node.getId().toString(),0);
 			//步骤4:遍历未归档文件
 			//待组卷文件集合
 			List<ArchiveFile> waitArchiveFiles = new ArrayList<>();
@@ -629,7 +661,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 				for(ArchiveFile file:archiveFiles){
 					archiveFilesSize++;
 					//步骤5:判断文件是否存在分盒设置
-					if(file.getBoxNumber()!=null){
+					if(file.getBoxNumber()!=null && file.getBoxNumber()!=-1){
 						//添加到分盒文件集合
 						addBoxMap(file,boxMap);
 						if(archiveFilesSize==archiveFiles.size() && waitArchiveFiles.size()>0){
@@ -667,7 +699,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 							//如果waitArchiveFiles集合size>0,先将集合中文件组卷。再将当前文件放入集合
 							if(waitArchiveFiles.size()>0){
 								//将waitArchiveFiles组卷,
-								createArchive3(waitArchiveFiles,node,archivesSize);
+								createArchive3(waitArchiveFiles,node,archivesSize-filePage);
 								//然后将待组卷文件集合,总页数还原初始值,
 								waitArchiveFiles.clear();
 								//保存当前文件进入待组卷集合,待组卷页数=当前文件页数
@@ -790,22 +822,21 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 			if(waitArchiveFiles.size()==0){
 				//waitArchiveFiles待组卷文件为空时,按当前节点的规格
 				String specificationStr = node.getSpecification();
+				if(StringUtils.isEmpty(specificationStr)){
+					specificationStr="30";
+				}
 				int specification = Integer.parseInt(specificationStr);
 				specificationSize=specification*10;
 			}
 
 			//步骤3.2:查询出当前节点未组卷的文件
-			List<ArchiveFile> archiveFiles = archiveFileClient.listWrappers(Wrappers.<ArchiveFile>lambdaQuery()
-					.eq(ArchiveFile::getNodeId, node)
-					.eq(ArchiveFile::getIsArchive, 0)
-					.eq(ArchiveFile::getIsDeleted,0)
-					.orderByAsc(ArchiveFile::getSort));
+			List<ArchiveFile> archiveFiles = archiveFileClient.getListByNodeID(node.getId().toString(),0);
 			//步骤3.3:遍历未组卷文件
 			int archiveFilesSize=0;
 			for(ArchiveFile file:archiveFiles){
 				archiveFilesSize++;
 				//步骤3.4:判断文件是否存在分盒设置
-				if(file.getBoxNumber()!=null) {
+				if(file.getBoxNumber()!=null && file.getBoxNumber()!=-1) {
 					//添加到分盒文件集合
 					addBoxMap(file,boxMap);
 					if(nodeSize==list.size() && archiveFilesSize==archiveFiles.size()){
@@ -841,6 +872,9 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 						archivesSize=0;
 
 						String specificationStr = node.getSpecification();
+						if(StringUtils.isEmpty(specificationStr)){
+							specificationStr="30";
+						}
 						int specification = Integer.parseInt(specificationStr);
 						specificationSize=specification*10;//更新specificationSize待组卷规格为 当前节点的组卷规格
 					}
@@ -858,6 +892,9 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 							archivesSize=filePage;
 
 							String specificationStr = node.getSpecification();
+							if(StringUtils.isEmpty(specificationStr)){
+								specificationStr="30";
+							}
 							int specification = Integer.parseInt(specificationStr);
 							specificationSize=specification*10;//更新specificationSize待组卷规格为 当前节点的组卷规格
 
@@ -951,5 +988,64 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		this.updateBatchById(changeList);
 	}
 
+	/**
+	 *	获取案卷合成pdf文件
+	 * @param archiveId
+	 * @return
+	 */
+	public String getMergeArchivesFile(Long archiveId){
+		String url = "";
+
+		List<String> urlList= new ArrayList<>();//合成pdf集合
+
+		ArchivesAuto archivesAuto = this.getById(archiveId);
+
+		//判断archivesAuto是否为空
+		if (archivesAuto == null){
+			return url;
+		}
+		String outUrl = archivesAuto.getOutUrl();
+		//判断outUrl是否为空
+		String[] frontUrls = null;
+		if (StringUtils.isNotEmpty(outUrl)){
+			frontUrls = outUrl.split(",");
+		}
+
+		List<String> fileUrls =new ArrayList<>();
+		if (!archivesAuto.isMedia()) {
+			List<ArchiveFile> result = this.archiveFileClient.getArchiveFileByArchivesId(archivesAuto.getId().toString(),"");
+			if(result != null && result.size() > 0){
+				//循环访问result,如果pdfpageurl不为空则取出,否则取pdffileurl
+				for (ArchiveFile archiveFile : result) {
+					String pdfPageUrl = archiveFile.getPdfPageUrl();
+					if (StringUtils.isEmpty(pdfPageUrl)) {
+						fileUrls.add(archiveFile.getPdfFileUrl());
+					}else{
+						fileUrls.add(pdfPageUrl);
+					}
+				}
+			}
+		}
+
+		if (fileUrls.size() > 0){
+			//此处暂时这么处理,等oss上传接口里文件名可以区分后,再单独取
+			if (frontUrls != null && frontUrls.length > 3){
+
+				urlList.add(frontUrls[0]);
+				urlList.add(frontUrls[1]);
+			}
+
+			urlList.addAll(fileUrls);
+
+			if (frontUrls != null && frontUrls.length > 3){
+				urlList.add(frontUrls[2]);
+				urlList.add(frontUrls[3]);
+			}
+
+			url = archiveAutoPdfService.MergePdfAndUpload(urlList,archivesAuto.getName(),null,archivesAuto.getProjectId());
+		}
+		return  url;
+	}
+
 
 }

+ 23 - 2
blade-service/blade-archive/src/main/java/org/springblade/archive/utils/FileUtils.java

@@ -19,7 +19,9 @@ import org.apache.poi.xssf.usermodel.XSSFPrintSetup;
 import org.apache.poi.xssf.usermodel.XSSFSheet;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 
+import org.springblade.common.constant.OssConstant;
 import org.springblade.common.utils.CommonUtil;
+import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.common.vo.DataVO;
 import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.tool.utils.IoUtil;
@@ -32,6 +34,7 @@ import java.awt.*;
 import java.awt.image.BufferedImage;
 import java.io.*;
 import java.net.URLEncoder;
+import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
@@ -572,11 +575,29 @@ public class FileUtils {
             }
             doc.close();
         }
+    }
 
-
-
+    /**
+     * 生成名字 参考 haha__125645646565.pdf
+     * @param filename
+     * @param style 0则按照雪花算法。1则按照时间戳
+     * @return
+     */
+    public static String generateFilename(String filename, int style,Long fid) {
+        String timestamp = "";
+        if (fid != null ) {
+            timestamp = Long.toString(fid);
+        }
+        else if (style == 0) {
+            timestamp = Long.toString(SnowFlakeUtil.getId());
+        } else if (style == 1) {
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
+            timestamp = sdf.format(new Date());
+        }
+        return filename + OssConstant.SEPARATOR + timestamp;
     }
 
+
     public static final  String MAP4_AVI = "avi、wmv、mpeg、mp4、m4v、mov、asf、flv、f4v、rmvb、rm、3gp、vob";
     public static final  String XLS_XLSX = "xlsx、xls";
     public static final  String DOC_DOCX = "doc、docx";

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

@@ -117,13 +117,13 @@ public class EVisaTaskCheckController {
     /**
      * 资料查询批量上报,检查自定义流程,审批人权限
      */
-    @PostMapping("/checkCustomFlowUserIsEVisaPermissions2")
+    @PostMapping("/batchCheckCustomFlowUserIsEVisaPermissions2")
     @ApiOperation(value = "资料查询批量上报,检查自定义流程,审批人权限")
     @ApiOperationSupport(order = 6)
     @ApiImplicitParams({
             @ApiImplicitParam(name = "customFlowUserList", value = "所选的任务人集合,集合形式", required = true),
             @ApiImplicitParam(name = "contractId", value = "合同段ID", required = true),
-            @ApiImplicitParam(name = "privatePKeyId", value = "表单列表中的isTypePrivatePid字段,集合形式"),
+            @ApiImplicitParam(name = "privatePKeyId", value = "资料查看选择的节点主键集合"),
             @ApiImplicitParam(name = "theLogPrimaryKeyId", value = "日志左侧所选的填报类型ID"),
             @ApiImplicitParam(name = "firstId", value = "首件记录ID,列表批量上报时传任意一个即可")
     })
@@ -138,7 +138,7 @@ public class EVisaTaskCheckController {
             }
 
             //获取电签配置
-            List<String> list = json.getJSONArray("wbsIds").toJavaList(String.class);
+            List<String> list = json.getJSONArray("privatePKeyId").toJavaList(String.class);
             Set<String> userNameFail = new HashSet<>();
             for (String nodeId : list) {
                 WbsTreeContract contract = wbsTreeContractClient.getContractWbsTreeByPrimaryKeyId(Long.valueOf(nodeId));

+ 183 - 79
blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java

@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.google.common.collect.Lists;
 import io.swagger.annotations.*;
 import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
 import lombok.AllArgsConstructor;
@@ -1345,15 +1346,20 @@ public class InformationWriteQueryController extends BladeController {
             //首先查询需要复制的节点及其下级所有子节点的信息
             WbsTreeContract needCopyNode = this.wbsTreeContractClient.getContractNodeByPrimaryKeyId(vo.getNeedCopyPrimaryKeyId());
             // 获取当前节点的所有子节点
-            String vocational = SnowFlakeUtil.getId() + "";
+            /*String vocational = SnowFlakeUtil.getId() + "";*/
+
             //新增施工台账
             List<WbsTreeContract> saveList = new ArrayList<>();
             List<ConstructionLedger> saveLedger = new ArrayList<>();
-            // 获取附件
+
+            //获取子级节点、表信息
             List<WbsTreeContract> nodeChildAll = informationQueryService.getNodeChildAllByNodeId(needCopyNode.getId() + "", needCopyNode.getContractId(), vo.getNeedCopyPrimaryKeyId());
-            // 获取实体表列对象
+            //获取数据源表(附件复制使用)
+            Set<WbsTreeContract> oldTabs = nodeChildAll.stream().filter(f -> (new Integer(2).equals(f.getType()))).collect(Collectors.toSet());
+
+            //获取实体表列对象
             List<QueryProcessDataVO> nodeTabCols = informationQueryService.getNodeChildTabColsAllByNodeId(needCopyNode.getId() + "", needCopyNode.getContractId());
-            // 转化为map
+            //转化为map
             Map<String, String> nodeTabColsMap = nodeTabCols.stream().collect(Collectors.toMap(QueryProcessDataVO::getQueryType, QueryProcessDataVO::getAncestors, (key1, key2) -> key2));
             StringBuilder copeSql = new StringBuilder();
 
@@ -1432,14 +1438,24 @@ public class InformationWriteQueryController extends BladeController {
                     }
                 });
             }
-            //保存节点信息
+
+            //复制保存节点、表信息
             R<Boolean> booleanR = this.saveOrCopyNodeTree(saveList, saveLedger, 32, needCopyNode);
-            //复制数据逻辑
+
+            //复制元素表附件信息
+            List<WbsTreeContract> newTabs = saveList.stream().filter(f -> (new Integer(2).equals(f.getType()))).collect(Collectors.toList());
+            if (newTabs.size() > 0 && oldTabs.size() > 0 && vo.getIsCopyData() == 1) {
+                this.addCopyTabFile(newTabs, oldTabs);
+            }
+
+            //复制表单数据
             if (copeSql.length() >= 10) {
                 jdbcTemplate.execute(copeSql.toString());
             }
-            //获取父节点信息
+
+            //更新redis缓存
             informationQueryService.AsyncWbsTree(needCopyNode.getParentId() + "", needCopyNode.getParentId() + "", needCopyNode.getContractId(), "", "1");
+
             return booleanR;
 
         } else if (("2").equals(vo.getCopyType())) {
@@ -1473,7 +1489,7 @@ public class InformationWriteQueryController extends BladeController {
 
                 WbsTreeContract needCopyNodeRoot = this.wbsTreeContractClient.getContractNodeByPrimaryKeyId(vo.getNeedCopyPrimaryKeyId());
                 if (needCopyNodeRoot != null) {
-                    //缓存需要复制的节点信息、表信息
+                    //缓存需要复制的节点、表信息
                     Map<String, List<WbsTreeContract>> needCopyNodeAndTabMap = new HashMap<>();
                     List<WbsTreeContract> needCopyChildNodes = this.getChildNodes(needCopyNodeRoot);
                     if (ObjectUtil.isEmpty(needCopyChildNodes) || needCopyChildNodes.size() == 0) {
@@ -1486,10 +1502,11 @@ public class InformationWriteQueryController extends BladeController {
                     needCopyNodeAndTabMap.put("tab:" + needCopyNodeRoot.getPKeyId(), addChildNodesTables);
 
                     //结果集
-                    List<WbsTreeContract> addNodeList = new ArrayList<>();//节点
-                    List<WbsTreeContract> addTabList = new ArrayList<>(); //表单
-                    List<WbsTreeContract> asyncWbsTreeNodes = new ArrayList<>(); //redis同步信息
-                    Set<WbsTreeContract> addChildNodesTablesOldAll = new HashSet<>(addChildNodesTables);//表单附件数据源
+                    List<WbsTreeContract> addNodeList = new ArrayList<>();//新增节点
+                    List<WbsTreeContract> addTabList = new ArrayList<>(); //新增表单
+                    List<WbsTreeContract> asyncWbsTreeNodes = new ArrayList<>(); //redis同步节点
+                    Set<WbsTreeContract> addChildNodesTablesOldAll = new HashSet<>(addChildNodesTables);//数据源表附件
+                    Set<WbsTreeContract> addNewFileTabs = new HashSet<>(addChildNodesTables);//新增到目标表附件
                     List<String> resultTablesData = new ArrayList<>();//表单数据
 
                     //创建线程池,默认设置4个线程
@@ -1523,7 +1540,7 @@ public class InformationWriteQueryController extends BladeController {
                                                 //1.2 选择同父级的同级节点,只复制数据
                                             } else if (needCopyNode.getParentId().equals(toCopyNode.getParentId())) {
                                                 //构造数据
-                                                this.addCopyTabData(needCopyNode, toCopyNode, finalTabOwner, resultTablesData, addTabList, vo.getIsCopyData());
+                                                this.addCopyTabData(needCopyNode, toCopyNode, finalTabOwner, resultTablesData, addTabList, vo.getIsCopyData(), addNewFileTabs);
                                             }
 
                                             //TODO 跨节点复制
@@ -1565,7 +1582,7 @@ public class InformationWriteQueryController extends BladeController {
                                             //2.2 如果点击选择的是当前复制节点本身的同等级节点,那么就只复制数据。(如果是跨节点,类型相同的情况下,只复制数据),且var=false,表示没有进行到跨节点新增的逻辑,只是跨节点复制数据
                                             if (needCopyNode.getNodeType().equals(toCopyNode.getNodeType()) && !needCopyNode.getParentId().equals(toCopyNode.getParentId()) && !var) {
                                                 //构造数据
-                                                this.addCopyTabData(needCopyNode, toCopyNode, finalTabOwner, resultTablesData, addTabList, vo.getIsCopyData());
+                                                this.addCopyTabData(needCopyNode, toCopyNode, finalTabOwner, resultTablesData, addTabList, vo.getIsCopyData(), addNewFileTabs);
                                             }
                                         }
                                     }
@@ -1593,18 +1610,29 @@ public class InformationWriteQueryController extends BladeController {
                     //入库
                     Boolean row = false;
                     if (nodes.size() > 0) {
+                        //复制新增节点
                         row = wbsTreeContractClient.saveBatch(nodes);
                     }
+
                     if (tabs.size() > 0) {
+                        //复制新增表
                         row = wbsTreeContractClient.saveBatch(tabs);
-                        if (addChildNodesTablesOldAll.size() > 0 && vo.getIsCopyData() == 1) {
-                            this.addCopyTabFile(tabs, addChildNodesTablesOldAll);
-                        }
                     }
-                    if (resultTablesData.size() > 0) {
-                        jdbcTemplate.execute(StringUtils.join(resultTablesData, ""));
+
+                    if (addNewFileTabs.size() > 0 && addChildNodesTablesOldAll.size() > 0 && vo.getIsCopyData() == 1) {
+                        //复制新增表附件
+                        this.addCopyTabFile(tabs, addChildNodesTablesOldAll);
+                    }
+
+                    if (resultTablesData.size() > 0 && vo.getIsCopyData() == 1) {
+                        //复制新增表数据
+                        List<List<String>> partition = Lists.partition(resultTablesData, 20);
+                        for (List<String> strings : partition) {
+                            jdbcTemplate.execute(StringUtils.join(strings, ""));
+                        }
                     }
                     if (row && asyncWbsTreeNodes.size() > 0) {
+                        //更新redis缓存
                         List<WbsTreeContract> collect = asyncWbsTreeNodes.stream().distinct().collect(Collectors.toList());
                         for (WbsTreeContract asyncWbsTreeNode : collect) {
                             informationQueryService.AsyncWbsTree("", asyncWbsTreeNode.getId() + "", contractId, "", "1");
@@ -1658,6 +1686,7 @@ public class InformationWriteQueryController extends BladeController {
         Map<String, List<TableFile>> tableFileOldMap = tableFileClient.getTabFilesByTabIds(StringUtils.join(tabFileIds, ",")).stream().collect(Collectors.groupingBy(TableFile::getTabId));
         if (tableFileOldMap != null && tableFileOldMap.size() > 0) {
             List<TableFile> resultFileData = new ArrayList<>();
+            List<Long> updatePKeyIds = new ArrayList<>();
             for (WbsTreeContract tabOld : addChildNodesTablesOld) {
                 for (WbsTreeContract tabNew : addChildNodesTables) {
                     //获取对应表
@@ -1670,12 +1699,20 @@ public class InformationWriteQueryController extends BladeController {
                                 file.setId(SnowFlakeUtil.getId());
                             });
                             resultFileData.addAll(tab);
+                            if (ObjectUtil.isNotEmpty(tabOld) && tabOld.getTabFileType() == 2) {
+                                updatePKeyIds.add(tabNew.getPKeyId());
+                            }
                         }
                     }
                 }
             }
             if (resultFileData.size() > 0) {
+                //入库
                 tableFileClient.saveBatch(resultFileData);
+                if (updatePKeyIds.size() > 0) {
+                    //修改表的文件按钮状态
+                    wbsTreeContractClient.updateTabFileTypeByPkeyIds(updatePKeyIds);
+                }
             }
         }
     }
@@ -1683,32 +1720,25 @@ public class InformationWriteQueryController extends BladeController {
     /**
      * 新增复制的数据
      */
-    private void addCopyTabData(WbsTreeContract needCopyNode, WbsTreeContract toCopyNode, String tabOwner, List<String> resultTablesData, List<WbsTreeContract> addChildNodesTablesAll, Integer isCopyData) {
+    private void addCopyTabData(WbsTreeContract needCopyNode, WbsTreeContract toCopyNode, String tabOwner, List<String> resultTablesData, List<WbsTreeContract> addChildNodesTablesAll, Integer isCopyData, Set<WbsTreeContract> addNewFileTabs) {
         List<WbsTreeContract> wbsTreeContractsNeed = Collections.singletonList(needCopyNode);
         List<WbsTreeContract> wbsTreeContractsTo = Collections.singletonList(toCopyNode);
         List<WbsTreeContract> needCopyNodeTabs = this.getChildNodesTables(wbsTreeContractsNeed, needCopyNode.getContractId());
         List<WbsTreeContract> toCopyNodeTabs = this.getChildNodesTables(wbsTreeContractsTo, needCopyNode.getContractId());
+        Map<String, WbsTreeContract> toCopyNodeTabsMaps = toCopyNodeTabs.stream().collect(Collectors.toMap(obj -> obj.getNodeName() + "-" + obj.getHtmlUrl(), Function.identity()));
         if (needCopyNodeTabs.size() > 0) {
             for (WbsTreeContract needTab : needCopyNodeTabs) {
-                for (WbsTreeContract toCopyNodeTab : toCopyNodeTabs) {
-                    //获取相同表单 nodeName 、HtmlUrl相同
-                    if (needTab.getNodeName().equals(toCopyNodeTab.getNodeName()) && (ObjectUtil.isNotEmpty(needTab.getHtmlUrl()) && ObjectUtil.isNotEmpty(toCopyNodeTab.getHtmlUrl()) && needTab.getHtmlUrl().equals(toCopyNodeTab.getHtmlUrl()))) {
-                        if (StringUtils.isEmpty(needTab.getInitTableName())) {
-                            //没有对应实体表,跳过
-                            continue;
-                        }
+                if (ObjectUtil.isNotEmpty(needTab.getHtmlUrl())) {
+                    String pKey = needTab.getNodeName() + "-" + needTab.getHtmlUrl();
+                    //获取目标表对象
+                    WbsTreeContract toCopyNodeTab = toCopyNodeTabsMaps.get(pKey);
+                    //如果存在,只复制数据
+                    if (toCopyNodeTab != null) {
                         Long oldPKeyId = needTab.getPKeyId();
-
                         //表单所属方,只有勾选了对应的所属方权限才复制数据;勾选了复制数据才能复制,否则只是创建节点、表
                         if (tabOwner.contains(needTab.getTableOwner()) && isCopyData == 1) {
-
-                            //源表obj对象,文件附件使用
-                            if (!needTab.getTabFileType().equals(toCopyNodeTab.getTabFileType())) {
-                                toCopyNodeTab.setTabFileType(needTab.getTabFileType()); //已上传
-                            }
                             //目标表obj对象,文件附件使用
-                            addChildNodesTablesAll.add(toCopyNodeTab);
-
+                            addNewFileTabs.add(toCopyNodeTab);
                             //获取实体表列对象
                             List<QueryProcessDataVO> nodeTabColOneTab = informationQueryService.getNodeChildTabColsAllByTabName(needTab.getInitTableName());
                             //转化为map
@@ -1727,6 +1757,52 @@ public class InformationWriteQueryController extends BladeController {
                                 resultTablesData.add(copyDataSql.toString());
                             }
                         }
+
+                    } else if (ObjectUtil.isNotEmpty(needTab.getIsCopeTab()) && (new Integer(2).equals(needTab.getIsCopeTab()) || new Integer(3).equals(needTab.getIsCopeTab()))) {
+                        //如果不存在,则获新增复制的表,toCopyNodeTab == null && getIsCopeTab != null && =2为复制表、=3为频率表
+                        WbsTreeContract objTab = BeanUtil.copyProperties(needTab, WbsTreeContract.class);
+                        if (objTab != null) {
+                            Long oldPKeyId = needTab.getPKeyId();
+                            Long tabId = SnowFlakeUtil.getId();
+                            objTab.setId(tabId);
+                            objTab.setParentId(toCopyNode.getId());
+                            objTab.setPKeyId(SnowFlakeUtil.getId());
+                            //初始化是否显示表格,默认显示
+                            objTab.setIsBussShow(1);
+                            //初始化表格是否上传附件,默认未上传
+                            objTab.setTabFileType(1);
+                            //初始化单表是否可以预览,默认不能
+                            objTab.setIsTabPdf(1);
+                            //初始化PDF路径
+                            objTab.setPdfUrl(null);
+                            objTab.setCreateTime(new Date());
+                            //获取当前复制的表的sort
+                            objTab.setSort(ObjectUtils.isNotEmpty(needTab.getSort()) ? needTab.getSort() : 0);
+
+                            //复制表
+                            addChildNodesTablesAll.add(objTab);
+
+                            //表单所属方,只有勾选了对应的所属方权限才复制数据;勾选了复制数据才能复制,否则只是创建节点、表
+                            if (tabOwner.contains(objTab.getTableOwner()) && isCopyData == 1) {
+                                //获取实体表列对象
+                                List<QueryProcessDataVO> nodeTabColOneTab = informationQueryService.getNodeChildTabColsAllByTabName(objTab.getInitTableName());
+                                //转化为map
+                                Map<String, String> nodeTabColsMap = nodeTabColOneTab.stream().collect(Collectors.toMap(QueryProcessDataVO::getQueryType, QueryProcessDataVO::getAncestors, (key1, key2) -> key2));
+                                //组织复制表的数据的sql
+                                if (nodeTabColsMap.size() > 0) {
+                                    StringBuilder copyDataSql = new StringBuilder();
+                                    String tableName = objTab.getInitTableName();
+                                    String col = nodeTabColsMap.get(tableName);
+                                    String colVal = nodeTabColsMap.get(tableName);
+                                    colVal = colVal.replaceAll("id,p_key_id,", "'" + SnowFlakeUtil.getId() + "' as id,'" + objTab.getPKeyId() + "' as p_key_id,");
+                                    //delete SQL (先删除旧数据,再新增)
+                                    String delSql = "delete from " + tableName + " where p_key_id = " + objTab.getPKeyId() + " ; ";
+                                    //insert into SQL
+                                    copyDataSql.append(delSql).append("insert into ").append(tableName).append("  (").append(col).append(") select ").append(colVal).append(" from ").append(tableName).append(" where p_key_id='").append(oldPKeyId).append("' ;");
+                                    resultTablesData.add(copyDataSql.toString());
+                                }
+                            }
+                        }
                     }
                 }
             }
@@ -1736,9 +1812,7 @@ public class InformationWriteQueryController extends BladeController {
     /**
      * 新增复制的节点、表的数据构造
      */
-    private void addCopyNodesAndTabsBuildData(List<WbsTreeContract> addNodeList, List<WbsTreeContract> addTabList, List<WbsTreeContract> needNodes, List<WbsTreeContract> needTabs, WbsTreeContract
-            needCopyNode, WbsTreeContract toCopyNode, List<String> resultTablesData, Integer isSameNode, String
-                                                      tabOwner, Integer isCopyData) {
+    private void addCopyNodesAndTabsBuildData(List<WbsTreeContract> addNodeList, List<WbsTreeContract> addTabList, List<WbsTreeContract> needNodes, List<WbsTreeContract> needTabs, WbsTreeContract needCopyNode, WbsTreeContract toCopyNode, List<String> resultTablesData, Integer isSameNode, String tabOwner, Integer isCopyData) {
         int var = 0;
         if (needNodes.size() == 1) {
             //判断是否为最下级节点
@@ -1766,6 +1840,9 @@ public class InformationWriteQueryController extends BladeController {
                     obj.setFullName(toCopyNode.getNodeName());
                     obj.setPartitionCode(toCopyNode.getPartitionCode());
                     obj.setCreateTime(new Date());
+                    //获取当前复制的节点的sort
+                    obj.setSort(ObjectUtils.isNotEmpty(needNode.getSort()) ? needNode.getSort() : 0);
+
                     addNodeList.add(obj);
                     break;
                 }
@@ -1790,6 +1867,9 @@ public class InformationWriteQueryController extends BladeController {
                     //初始化PDF路径
                     obj.setPdfUrl(null);
                     obj.setCreateTime(new Date());
+                    //获取当前复制的表的sort
+                    obj.setSort(ObjectUtils.isNotEmpty(needTab.getSort()) ? needTab.getSort() : 0);
+
                     addTabList.add(obj);
 
                     //表单所属方,只有勾选了对应的所属方权限才复制数据;勾选了复制数据才能复制,否则只是创建节点、表
@@ -1805,7 +1885,10 @@ public class InformationWriteQueryController extends BladeController {
                             String col = nodeTabColsMap.get(tableName);
                             String colVal = nodeTabColsMap.get(tableName);
                             colVal = colVal.replaceAll("id,p_key_id,", "'" + SnowFlakeUtil.getId() + "' as id,'" + obj.getPKeyId() + "' as p_key_id,");
-                            copyDataSql.append("insert into ").append(tableName).append("  (").append(col).append(") select ").append(colVal).append(" from ").append(tableName).append(" where p_key_id='").append(oldPKeyId).append("' ;");
+                            //delete SQL (先删除旧数据,再新增)
+                            String delSql = "delete from " + tableName + " where p_key_id = " + obj.getPKeyId() + " ; ";
+                            //insert into SQL
+                            copyDataSql.append(delSql).append("insert into ").append(tableName).append("  (").append(col).append(") select ").append(colVal).append(" from ").append(tableName).append(" where p_key_id='").append(oldPKeyId).append("' ;");
                             resultTablesData.add(copyDataSql.toString());
                         }
                     }
@@ -1850,6 +1933,9 @@ public class InformationWriteQueryController extends BladeController {
                     obj.setId(id);
                     obj.setParentId(newParentId);
                     obj.setCreateTime(new Date());
+                    //获取当前复制的节点的sort
+                    obj.setSort(ObjectUtils.isNotEmpty(node.getSort()) ? node.getSort() : 0);
+
                     addNodeList.add(obj);
 
                     //构造当前节点下所有元素表
@@ -1877,6 +1963,9 @@ public class InformationWriteQueryController extends BladeController {
                                 //初始化PDF路径
                                 objTab.setPdfUrl(null);
                                 objTab.setCreateTime(new Date());
+                                //获取当前复制的表的sort
+                                objTab.setSort(ObjectUtils.isNotEmpty(needTab.getSort()) ? needTab.getSort() : 0);
+
                                 addTabList.add(objTab);
 
                                 //表单所属方,只有勾选了对应的所属方权限才复制数据;勾选了复制数据才能复制,否则只是创建节点、表
@@ -1888,7 +1977,10 @@ public class InformationWriteQueryController extends BladeController {
                                         String col = queryProcessDataVO.getAncestors();
                                         String colVal = queryProcessDataVO.getAncestors();
                                         colVal = colVal.replaceAll("id,p_key_id,", "'" + SnowFlakeUtil.getId() + "' as id,'" + needTab.getPKeyId() + "' as p_key_id,");
-                                        copyDataSql.append("insert into ").append(tableName).append("  (").append(col).append(") select ").append(colVal).append(" from ").append(tableName).append(" where p_key_id='").append(oldPKeyId).append("' ;");
+                                        //delete SQL (先删除旧数据,再新增)
+                                        String delSql = "delete from " + tableName + " where p_key_id = " + needTab.getPKeyId() + " ; ";
+                                        //insert into SQL
+                                        copyDataSql.append(delSql).append("insert into ").append(tableName).append("  (").append(col).append(") select ").append(colVal).append(" from ").append(tableName).append(" where p_key_id='").append(oldPKeyId).append("' ;");
                                         resultTablesData.add(copyDataSql.toString());
                                     }
                                 }
@@ -1911,6 +2003,8 @@ public class InformationWriteQueryController extends BladeController {
             needCopyNode.setNodeName(toCopyNode.getNodeName());
             needCopyNode.setFullName(toCopyNode.getNodeName());
             needCopyNode.setPartitionCode(toCopyNode.getPartitionCode());
+            needCopyNode.setCreateTime(new Date());
+
             addNodeList.add(needCopyNode);
         }
     }
@@ -2181,7 +2275,7 @@ public class InformationWriteQueryController extends BladeController {
      * 生成施工日志记录
      */
     private void createLedger(WbsTreeContract
-                                      newData, List<ConstructionLedger> saveLedger, Map<String, WbsTreeContract> contractNodeMap, Map<String, WbsTreePrivate> projectNodeMap) {
+                                      newData, List<ConstructionLedger> saveLedger, Map<String, WbsTreeContract> contractNodeMap, Map<String, WbsTreeContract> projectNodeMap) {
         //工序,需要新增施工台账
         ConstructionLedger ledger = new ConstructionLedger();
         //获取这个节点的原始信息
@@ -2203,13 +2297,13 @@ public class InformationWriteQueryController extends BladeController {
             }
         } else if (projectNodeMap != null) {
             if (projectNodeMap.containsKey(newData.getOldId())) {
-                WbsTreePrivate contractNode = projectNodeMap.get(newData.getOldId());
+                WbsTreeContract contractNode = projectNodeMap.get(newData.getOldId());
                 if (contractNode.getParentId() != null && StringUtils.isNotEmpty(contractNode.getParentId().toString())) {
-                    WbsTreePrivate parentNode;
+                    WbsTreeContract parentNode;
                     if (projectNodeMap.containsKey(contractNode.getParentId().toString())) {
                         parentNode = projectNodeMap.get(contractNode.getParentId().toString());
                     } else {
-                        parentNode = this.wbsTreePrivateClient.queryPeersNodeByProjectIdAndId(contractNode.getProjectId(), contractNode.getParentId());
+                        parentNode = this.wbsTreeContractClient.queryCurrentNodeAllParent(Long.parseLong(contractNode.getContractId()), contractNode.getParentId());
                     }
                     if (parentNode != null) {
                         ledger.setStation(StringUtils.isNotEmpty(parentNode.getFullName()) ? parentNode.getFullName() : parentNode.getNodeName());
@@ -2381,7 +2475,7 @@ public class InformationWriteQueryController extends BladeController {
     private void currentNodeAllParent(StringBuilder nodeName, WbsTreeContract currentNode) {
         if (!"0".equals(String.valueOf(currentNode.getParentId()))) {
             //如果父节点不是0说明没到顶层
-            WbsTreeContract parentNode = this.wbsTreeContractClient.queryCurrentNodeAllParent(Long.parseLong(currentNode.getContractId()), currentNode.getParentId());
+            WbsTreeContract parentNode = jdbcTemplate.query("select full_name,node_name from m_wbs_tree_contract where is_deleted = 0 and contract_id = " + currentNode.getContractId() + " and id = " + currentNode.getParentId(), new BeanPropertyRowMapper<>(WbsTreeContract.class)).stream().findAny().orElse(null);
             if (parentNode != null) {
                 nodeName.append("-").append(StringUtils.isNotEmpty(parentNode.getFullName()) ? parentNode.getFullName() : parentNode.getNodeName());
                 this.currentNodeAllParent(nodeName, parentNode);
@@ -2407,7 +2501,7 @@ public class InformationWriteQueryController extends BladeController {
         this.currentNodeAllParent(parentNodeName, removeNode);
 
         //查询所有子节点
-        List<WbsTreeContract> removeNodeList = this.wbsTreeContractClient.queryCurrentNodeAllChild(Long.parseLong(removeNode.getContractId()), removeNode.getId());
+        List<WbsTreeContract> removeNodeList = jdbcTemplate.query("select p_key_id,type from m_wbs_tree_contract where is_deleted = 0 and contract_id = " + removeNode.getContractId() + " and ancestors like '%" + removeNode.getId() + "%'", new BeanPropertyRowMapper<>(WbsTreeContract.class));
         //获取pKeyId
         List<Long> removeList = removeNodeList.stream().map(WbsTreeContract::getPKeyId).distinct().collect(Collectors.toList());
         //拼接
@@ -2415,7 +2509,7 @@ public class InformationWriteQueryController extends BladeController {
         //删除掉表格
         removeNodeList.removeIf(tree -> tree.getType() != null && new Integer("2").equals(tree.getType()));
         //获取被删除节点名称
-        String nodeName = StringUtils.isNotEmpty(removeNode.getFullName()) ? removeNode.getFullName() : removeNode.getNodeName() + "," + removeNodeList.stream().map(wbs -> StringUtils.isNotEmpty(wbs.getFullName()) ? wbs.getFullName() : wbs.getNodeName()).collect(Collectors.joining());
+        //String nodeName = StringUtils.isNotEmpty(removeNode.getFullName()) ? removeNode.getFullName() : removeNode.getNodeName() + "," + removeNodeList.stream().map(wbs -> StringUtils.isNotEmpty(wbs.getFullName()) ? wbs.getFullName() : wbs.getNodeName()).collect(Collectors.joining());
 
         //获取当前节点下所有填报节点
         List<QueryProcessDataVO> queryProcess = new ArrayList<>();
@@ -2430,7 +2524,6 @@ public class InformationWriteQueryController extends BladeController {
         if (queryProcess != null && queryProcess.size() > 0) {
             //检查这些填报节点是否存在已经审批或已经上报的节点,如果存在则不允许删除
             List<QueryProcessDataVO> approvalList = queryProcess.stream().filter(vo -> new Integer("2").equals(vo.getStatus()) && vo.getInformationQueryId() != null).collect(Collectors.toList());
-            //
             List<QueryProcessDataVO> runTaskList = queryProcess.stream().filter(vo -> new Integer("1").equals(vo.getStatus()) && vo.getInformationQueryId() != null).collect(Collectors.toList());
             if (approvalList.size() > 0 || runTaskList.size() > 0) {
                 //说明存在已经审批或已经上报的节点,不允许删除
@@ -2457,7 +2550,7 @@ public class InformationWriteQueryController extends BladeController {
         //保存进回收站
         this.recycleBinClient.saveDelBusinessData(idArray, StringUtils.isNotEmpty(removeNode.getFullName()) ? removeNode.getFullName() : removeNode.getNodeName(), 2, parentNodeName.toString(), removeNode.getProjectId(), removeNode.getContractId());
         Boolean aBoolean = this.wbsTreeContractClient.removeContractTreeNode(idArray);
-        // 更新redis
+        //更新redis
         this.informationQueryService.AsyncWbsTree(removeNode.getParentId() + "", removeNode.getParentId() + "", removeNode.getContractId(), "", "1");
         return R.data(aBoolean);
     }
@@ -2484,7 +2577,7 @@ public class InformationWriteQueryController extends BladeController {
         selectList.addAll(allSelectedNodeList);
 
         //所有相关节点集合
-        List<WbsTreePrivate> selectedNodeList = new ArrayList<>();
+        List<WbsTreeContract> selectedNodeList = new ArrayList<>();
 
         //检查新增类型
         if ("1".equals(vo.getSaveType())) {
@@ -2492,12 +2585,12 @@ public class InformationWriteQueryController extends BladeController {
             //当前节点及其子节点时,半选说明其下的子节点并不是全部选中的,所以这时候只需要根据全选的查询其全部子节点即可
             if (allSelectedNodeList.size() > 0) {
                 //查询数据
-                selectedNodeList = this.unifiedCode(allSelectedNodeList, treeContract);
+                selectedNodeList = this.unifiedCode(allSelectedNodeList, treeContract, "1");
 
                 //检查当前操作的节点是否是填报节点,如果是则需要查询相关联表格
-                List<WbsTreePrivate> submitNodeList = selectedNodeList.stream().filter(treePrivate -> Arrays.asList("1,2,3,4".split(",")).contains(treePrivate.getMajorDataType().toString())).distinct().collect(Collectors.toList());
+                List<WbsTreeContract> submitNodeList = selectedNodeList.stream().filter(treeContract1 -> Arrays.asList("1,2,3,4".split(",")).contains(treeContract1.getMajorDataType().toString())).distinct().collect(Collectors.toList());
 
-                List<WbsTreePrivate> childList = new ArrayList<>();
+                List<WbsTreeContract> childList = new ArrayList<>();
                 if (submitNodeList.size() > 0) {
                     this.foreachQueryChild(submitNodeList, childList);
                     //将表格数据设置
@@ -2506,11 +2599,11 @@ public class InformationWriteQueryController extends BladeController {
 
                 if (childList.size() > 0) {
                     //处理重复的数据
-                    Iterator<WbsTreePrivate> iterator = childList.iterator();
+                    Iterator<WbsTreeContract> iterator = childList.iterator();
                     while (iterator.hasNext()) {
-                        WbsTreePrivate next = iterator.next();
-                        for (WbsTreePrivate treePrivate : selectedNodeList) {
-                            if (treePrivate.getPKeyId().equals(next.getPKeyId())) {
+                        WbsTreeContract next = iterator.next();
+                        for (WbsTreeContract wbsTreeContract : selectedNodeList) {
+                            if (wbsTreeContract.getPKeyId().equals(next.getPKeyId())) {
                                 //删掉重复数据
                                 iterator.remove();
                                 break;
@@ -2528,20 +2621,18 @@ public class InformationWriteQueryController extends BladeController {
             //todo 仅当前节点操作
             if (allSelectedNodeList.size() > 0) {
                 //查询数据
-                selectedNodeList = this.unifiedCode(allSelectedNodeList, treeContract);
+                selectedNodeList = this.unifiedCode(allSelectedNodeList, treeContract, "0");
 
                 //检查当前操作的节点是否是填报节点,如果是则需要查询相关联表格
-                List<WbsTreePrivate> submitNodeList = selectedNodeList.stream().filter(treePrivate -> Arrays.asList("1,2,3,4".split(",")).contains(treePrivate.getMajorDataType().toString())).distinct().collect(Collectors.toList());
+                List<WbsTreeContract> submitNodeList = selectedNodeList.stream().filter(treePrivate -> Arrays.asList("1,2,3,4".split(",")).contains(treePrivate.getMajorDataType().toString())).distinct().collect(Collectors.toList());
 
-                List<WbsTreePrivate> childList = new ArrayList<>();
+                List<WbsTreeContract> childList = new ArrayList<>();
                 if (submitNodeList.size() > 0) {
                     this.foreachQueryChild(submitNodeList, childList);
                     //将表格数据设置
                     selectedNodeList.addAll(childList);
                 }
             }
-            //处理半选
-            this.disposeHalfSelectList(treeContract, halfSelectedNodeList, selectedNodeList);
         }
 
         //保存集合
@@ -2550,7 +2641,7 @@ public class InformationWriteQueryController extends BladeController {
         if (selectedNodeList.size() > 0) {
             //重塑关键信息
             Map<Long, Long> OldIdToNewIdMap = new HashMap<>();
-            Map<String, WbsTreePrivate> nodeMap = new HashMap<>();
+            Map<String, WbsTreeContract> nodeMap = new HashMap<>();
             selectedNodeList.forEach(half -> {
                 OldIdToNewIdMap.put(half.getId(), SnowFlakeUtil.getId());
                 nodeMap.put(half.getId().toString(), half);
@@ -2567,7 +2658,22 @@ public class InformationWriteQueryController extends BladeController {
                 if (new Integer("1").equals(half.getType())) {
                     newData.setId(OldIdToNewIdMap.containsKey(half.getId()) ? OldIdToNewIdMap.get(half.getId()) : SnowFlakeUtil.getId());
                 }
-                newData.setParentId(OldIdToNewIdMap.containsKey(half.getParentId()) ? OldIdToNewIdMap.get(half.getParentId()) : treeContract.getId().equals(half.getParentId()) || treeContract.getOldId().equals(half.getParentId().toString()) ? treeContract.getId() : SnowFlakeUtil.getId());
+
+                //设置父级id
+                if (("1").equals(vo.getSaveType())) {
+                    //当前节点及其子节点操作
+                    newData.setParentId(OldIdToNewIdMap.containsKey(half.getParentId()) ? OldIdToNewIdMap.get(half.getParentId()) : treeContract.getId().equals(half.getParentId()) || treeContract.getOldId().equals(half.getParentId().toString()) ? treeContract.getId() : SnowFlakeUtil.getId());
+                } else {
+                    //仅当前节点新增操作时,父级id=选择新增的节点父级id
+                    if (new Integer("1").equals(half.getType())) {
+                        //节点
+                        newData.setParentId(half.getParentId());
+                    } else if (new Integer("2").equals(half.getType())) {
+                        //表
+                        newData.setParentId(OldIdToNewIdMap.containsKey(half.getParentId()) ? OldIdToNewIdMap.get(half.getParentId()) : treeContract.getId().equals(half.getParentId()) || treeContract.getOldId().equals(half.getParentId().toString()) ? treeContract.getId() : SnowFlakeUtil.getId());
+                    }
+                }
+
                 //记录旧ID
                 newData.setOldId(half.getId().toString());
                 //设置合同段等信息
@@ -2635,21 +2741,20 @@ public class InformationWriteQueryController extends BladeController {
         R<Boolean> booleanR = this.saveOrCopyNodeTree(saveList, saveLedger, 2, treeContract);
 
         //更新redis
-        List<WbsTreeContractTreeVOS> wbsTreeContractTreeVOS = this.informationQueryService.queryContractTree(treeContract.getId() + "", treeContract.getContractId(), "", "1");
-
         informationQueryService.AsyncWbsTree(treeContract.getId() + "", treeContract.getId() + "", treeContract.getContractId(), "", "1");
+        informationQueryService.AsyncWbsTree(treeContract.getParentId() + "", treeContract.getParentId() + "", treeContract.getContractId(), "", "1");
         return booleanR;
     }
 
-    private List<WbsTreePrivate> unifiedCode
-            (List<AddContractTreeNodeVO.Node> allSelectedNodeList, WbsTreeContract treeContract) {
+    private List<WbsTreeContract> unifiedCode(List<AddContractTreeNodeVO.Node> allSelectedNodeList, WbsTreeContract treeContract, String saveType) {
         //获取主键
-        List<String> halfSelectedList = allSelectedNodeList.stream().map(AddContractTreeNodeVO.Node::getPrimaryKeyId).distinct().collect(Collectors.toList());
+        List<Long> halfSelectedList = allSelectedNodeList.stream().map(AddContractTreeNodeVO.Node::getPrimaryKeyId).map(Long::parseLong).distinct().collect(Collectors.toList());
         //查询数据
-        List<WbsTreePrivate> selectedNodeList = this.wbsTreePrivateClient.queryByPKeyIds(halfSelectedList);
-        //剔除与当前操作节点相同的ID
-        selectedNodeList.removeIf(wbsTreePrivate -> treeContract.getId().equals(wbsTreePrivate.getId()) || treeContract.getOldId().equals(wbsTreePrivate.getId().toString()));
-
+        List<WbsTreeContract> selectedNodeList = this.wbsTreeContractClient.queryContractTreeNodeByPKIds(halfSelectedList);
+        //剔除与当前操作节点相同的ID,(如果saveType=1,表示当前及子级节点,那么就要剔除自己本身,否则视为仅当前节点操作,会存在自己本身)
+        if (("1").equals(saveType)) {
+            selectedNodeList.removeIf(wbsTreePrivate -> treeContract.getId().equals(wbsTreePrivate.getId()) || treeContract.getOldId().equals(wbsTreePrivate.getId().toString()));
+        }
         return selectedNodeList;
     }
 
@@ -2710,13 +2815,12 @@ public class InformationWriteQueryController extends BladeController {
     /**
      * 处理半选集合
      */
-    private void disposeHalfSelectList(@RequestBody WbsTreeContract
-                                               treeContract, List<AddContractTreeNodeVO.Node> allSelectedNodeList, List<WbsTreePrivate> selectedNodeList) {
+    private void disposeHalfSelectList(@RequestBody WbsTreeContract treeContract, List<AddContractTreeNodeVO.Node> allSelectedNodeList, List<WbsTreeContract> selectedNodeList) {
         if (allSelectedNodeList != null && allSelectedNodeList.size() > 0) {
             //获取主键
-            List<String> allSelectedList = allSelectedNodeList.stream().map(AddContractTreeNodeVO.Node::getPrimaryKeyId).distinct().collect(Collectors.toList());
+            List<Long> allSelectedList = allSelectedNodeList.stream().map(AddContractTreeNodeVO.Node::getPrimaryKeyId).map(Long::parseLong).distinct().collect(Collectors.toList());
             //查询对应数据
-            List<WbsTreePrivate> allSelectedNodeLists = this.wbsTreePrivateClient.queryByPKeyIds(allSelectedList);
+            List<WbsTreeContract> allSelectedNodeLists = this.wbsTreeContractClient.queryContractTreeNodeByPKIds(allSelectedList);
             //剔除与当前操作节点相同的ID
             allSelectedNodeLists.removeIf(wbsTreePrivate -> treeContract.getId().equals(wbsTreePrivate.getId()) || treeContract.getOldId().equals(wbsTreePrivate.getId().toString()));
             //设置到集合中
@@ -2730,9 +2834,9 @@ public class InformationWriteQueryController extends BladeController {
      * @param parentList 父节点集合
      * @param childList  保存集合
      */
-    private void foreachQueryChild(List<WbsTreePrivate> parentList, List<WbsTreePrivate> childList) {
+    private void foreachQueryChild(List<WbsTreeContract> parentList, List<WbsTreeContract> childList) {
         parentList.forEach(parent -> {
-            List<WbsTreePrivate> childs = this.wbsTreePrivateClient.queryChildByParentId(parent);
+            List<WbsTreeContract> childs = this.wbsTreeContractClient.queryChildByParentId(parent, "", "");
 
             if (childs != null && childs.size() > 0) {
                 //添加入结果集

+ 7 - 1
blade-service/blade-business/src/main/java/org/springblade/business/controller/MetadataController.java

@@ -79,12 +79,18 @@ public class MetadataController extends BladeController {
         String[] split = byId.getFileStorageType().split(",");
         StringBuffer str = new StringBuffer();
         for(String s :split){
+            if(s.isEmpty()){
+                continue;
+            }
             if(s.equals(type)){
                 continue;
             }
             str.append(s+",");
         }
-        String substring = str.toString().substring(0, str.lastIndexOf(","));
+        String substring = str.toString();
+        if(str.lastIndexOf(",") > 0){
+            substring = str.toString().substring(0, str.lastIndexOf(","));
+        }
         byId.setFileStorageType(substring);
         iMetadataClassificationService.updateById(byId);
         return R.status(iMetadataClassificationService.updateById(byId));

+ 15 - 0
blade-service/blade-business/src/main/java/org/springblade/business/feignClient/ArchiveFileClientImpl.java

@@ -187,6 +187,21 @@ public class ArchiveFileClientImpl implements ArchiveFileClient {
         }
     }
 
+    /**
+     * 根据案卷id集合返回所有的文件列表
+     * @param ids
+     * @return
+     */
+    @Override
+    public List<ArchiveFile> getAllArchiveFileByArchiveIds(List<String> ids) {
+        return fileMapper.getAllArchiveFileByArchiveIds(ids);
+    }
+
+    @Override
+    public void batchDeleteArchiveFile(List<Long> ids) {
+        fileMapper.deleteBatchIds(ids);
+    }
+
     @Override
     public List<ArchiveFile> getListByNodeID(String nodeId,Integer isArchive) {
         List<ArchiveFile> files = fileMapper.getListByNodeID(nodeId, isArchive);

+ 2 - 0
blade-service/blade-business/src/main/java/org/springblade/business/mapper/ArchiveFileMapper.java

@@ -73,5 +73,7 @@ public interface ArchiveFileMapper extends BaseMapper<ArchiveFile> {
 
 	List<ArchiveFile> getAllArchiveFileUrl(@Param("projectId")Long projectId);
 
+    List<ArchiveFile> getAllArchiveFileByArchiveIds(@Param("ids") List<String> ids);
+
 	public List<ArchiveFile> getListByNodeID(@Param("nodeId") String nodeId,@Param("isArchive")Integer isArchive);
 }

+ 9 - 0
blade-service/blade-business/src/main/java/org/springblade/business/mapper/ArchiveFileMapper.xml

@@ -54,6 +54,8 @@
         <result column="page_num" property="pageNum"/>
         <result column="file_size" property="fileSize"/>
         <result column="source_type" property="sourceType"/>
+        <result column="is_element" property="isElement"/>
+        <result column="pdf_page_url" property="pdfPageUrl"/>
     </resultMap>
     <update id="recoveryByIds">
         update u_archive_file set is_deleted = 0 where
@@ -286,6 +288,13 @@
         FROM u_archive_file uaf
         WHERE  uaf.project_id = #{projectId};
     </select>
+    <select id="getAllArchiveFileByArchiveIds" resultType="org.springblade.business.entity.ArchiveFile">
+        SELECT * FROM u_archive_file
+        WHERE archive_id in
+        <foreach collection="ids" item="id" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </select>
 
 
 

+ 4 - 12
blade-service/blade-business/src/main/java/org/springblade/business/mapper/InformationQueryMapper.xml

@@ -201,20 +201,13 @@
         contract_id
         =
         #{contractId}
-        -- ORDER BY wtc.sort,wtc.create_time
         )
-        c
-        ORDER
-        BY
-        c
-        .
-        sort,
-        c
-        .
-        create_time
+        c ORDER BY
+        c.sort,
+        c.title,
+        c.create_time
     </select>
 
-
     <select id="queryContractTreeSupervision" resultMap="queryContractTreeMap">
         SELECT
         wtc.is_concealed_works_node AS "isConcealedWorksNode",
@@ -816,7 +809,6 @@
             AND wtc.contract_id = #{contractId}
             AND wtc.is_deleted = 0
            or wtc.p_key_id = #{pKeyId}
-
     </select>
 
     <!--获取当前节点下,所有表单的字段数据-->

+ 2 - 0
blade-service/blade-business/src/main/java/org/springblade/business/mapper/MetadataClassificationMapper.java

@@ -20,4 +20,6 @@ public interface MetadataClassificationMapper extends BaseMapper<MetadataClassif
 
 
     void deleteTableField(@Param("containerInitTabName") String containerInitTabName,@Param("fieldKey") String fieldKey);
+
+    void removeMetadataBytype(@Param("type") String type);
 }

+ 5 - 1
blade-service/blade-business/src/main/java/org/springblade/business/mapper/MetadataClassificationMapper.xml

@@ -77,6 +77,10 @@
         <foreach collection="ids" item="ids" index="ids" open="(" separator="," close=")">
             ${ids}
         </foreach>
-        and locate(#{type},file_storage_type) = 0
+--         and locate(#{type},file_storage_type) = 0
+    </update>
+    <update id="removeMetadataBytype">
+        update u_metadata_classification set file_storage_type = REPLACE(file_storage_type,#{type},'')
+        where  locate(#{type},file_storage_type) = 0
     </update>
 </mapper>

+ 2 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/MetadataClassificationServiceImpl.java

@@ -91,6 +91,8 @@ public class MetadataClassificationServiceImpl
     @Override
     public boolean updateMetadataBytype(List<Long> ids, String type) {
         try {
+            //先删除在保存
+            baseMapper.removeMetadataBytype(type);
             baseMapper.updateMetadataBytype(ids,type);
         } catch (Exception e) {
             e.printStackTrace();

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

@@ -338,4 +338,20 @@ public class ArchiveTreeContractController extends BladeController {
 		return R.fail(200, "同步失败");
 	}
 
+	/**
+	 * 根据节点类型获取档案,档案查询选择目录
+	 */
+	@GetMapping("getArchiveTreeByNodeType")
+	@ApiOperation(value = "根据节点类型获取档案,档案查询选择目录", notes = "传入项目id,节点类型")
+	public R getArchiveTreeByNodeType(Long projectId,Long nodeType){
+		return R.data(archiveTreeContractService.getArchiveTreeByNodeType(projectId,nodeType));
+	}
+	/**
+	 * 根据父节点获取子节点集合
+	 */
+	@GetMapping("getChildrenNodeByNodeId")
+	@ApiOperation(value = "根据节点id获取子节点集合", notes = "传入节点id")
+	public R getChildrenNodeByNodeId(Long nodeId){
+		return R.data(archiveTreeContractService.getChildrenNodeByNodeId(nodeId));
+	}
 }

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

@@ -237,6 +237,9 @@ public class ArchiveTreeController extends BladeController {
     @PostMapping("/removeArchiveAutoRule")
     public R removeArchiveAutoRule(Long nodeId,boolean iswbsNode,Long projectId) {
         Map<String, String> map = archiveTreeService.removeArchiveAutoRule(nodeId, iswbsNode,projectId);
+        if(map.get("code").equals("0")){
+            return  R.fail(map.get("msg").toString());
+        }
         return R.data(map);
     }
 

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

@@ -136,7 +136,7 @@ public class ExcelTabController extends BladeController {
     @ApiOperationSupport(order = 1)
     @ApiOperation(value = "详情", notes = "传入excelTab")
     public R<ExcelTabVO> detail(ExcelTab excelTab) {
-        ExcelTab detail = excelTabService.getOne(Condition.getQueryWrapper(excelTab));
+        ExcelTab detail = excelTabService.getOne(Condition.getQueryWrapper(excelTab) );
         return R.data(ExcelTabWrapper.build().entityVO(detail));
     }
 
@@ -282,8 +282,8 @@ public class ExcelTabController extends BladeController {
     })
     public R putFileAttach(@RequestParam("file") MultipartFile file, Long nodeId) {
 
-        //String file_path = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
-        String file_path = "/Users/hongchuangyanfa/Desktop/"; //ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
+         String file_path = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
+        //String file_path = "/Users/hongchuangyanfa/Desktop/";
 
         ExcelTab detail = excelTabService.getById(nodeId);
         // 上传excel文件
@@ -859,9 +859,7 @@ public class ExcelTabController extends BladeController {
 
             // 计算单元格坐标
             int x = 0;
-            if(i==9 || i==10){
-                System.out.println("1234");
-            }
+
             for (int j = 0; j < tds.size(); j++) {
                 {
                     Element data = tds.get(j);
@@ -887,7 +885,7 @@ public class ExcelTabController extends BladeController {
                     //x 移位 算法
                     String getRowInfo = rowData[y1];
 
-                    if (y1 == 9) {
+                    if (y1 == 17) {
                         System.out.println("1");
                     }
                     if (getRowInfo != null) {
@@ -969,24 +967,51 @@ public class ExcelTabController extends BladeController {
                             if (dataInfo == null) {
                                 dataInfo = x1 + ":" + x2;
                             } else {
-                                String[] dataInfo2 = dataInfo.split(",");
-                                String dataInfo3 = dataInfo2[dataInfo2.length - 1];
-                                int mx1 = Integer.parseInt(dataInfo3.split(":")[0]);
-                                int mx2 = Integer.parseInt(dataInfo3.split(":")[1]);
-                                if (mx2 + 1 == x1) {
-                                    String [] data3=new String[dataInfo2.length-1];
-                                    System.arraycopy(dataInfo2,0,data3,0,data3.length);
-                                    dataInfo = StringUtils.join(data3); //removing element at index 2
-
-                                    if (dataInfo2.length == 1) {
-                                        dataInfo = mx1 + ":" + x2;
-                                    } else {
-                                        dataInfo = dataInfo + "," + mx1 + ":" + x2;
+                                dataInfo = dataInfo + "," + x1 + ":" + x2;
+                                String[] arr=  dataInfo.split(",");
+                                //排序
+                                for(int r=0;r<arr.length-1;r++) {
+                                    for(int q = arr.length-2;q>=r;q--) {
+                                        Integer jval = Integer.parseInt(arr[q+1].split(":")[0]);
+                                        Integer jval1 = Integer.parseInt(arr[q].split(":")[0]);
+                                        if(jval<jval1) {
+                                            String temp = arr[q+1];
+                                            arr[q+1] = arr[q];
+                                            arr[q] = temp;
+                                        }
                                     }
+                                }
 
-                                } else {
-                                    dataInfo = dataInfo + "," + x1 + ":" + x2;
+                                //组合
+                                String newDataInfo ="";
+                                for(int r=0;r<arr.length;r++) {
+                                    if(r==0){
+                                        newDataInfo = arr[0];
+                                    }else{
+                                        int StrMax = Integer.parseInt(newDataInfo.substring(newDataInfo.lastIndexOf(":")+1,newDataInfo.length()));
+                                        Integer nowMin = Integer.parseInt(arr[r].split(":")[0]);
+                                        Integer nowMax = Integer.parseInt(arr[r].split(":")[1]);
+                                        if((StrMax+1) == nowMin){
+                                            String lastStr = "";
+                                            if(newDataInfo.indexOf(",")>=0){
+                                                lastStr = newDataInfo.substring(newDataInfo.lastIndexOf(",")+1,newDataInfo.length());
+                                                newDataInfo = newDataInfo.substring(0,newDataInfo.lastIndexOf(","));
+                                            }else{
+                                                lastStr=  newDataInfo;
+                                                newDataInfo = "";
+                                            }
+                                            int lastmin = Integer.parseInt(lastStr.split(":")[0]);
+                                            if(StringUtils.isNotEmpty(newDataInfo)){
+                                                newDataInfo = newDataInfo +"," +lastmin+":"+nowMax;
+                                            }else{
+                                                newDataInfo = lastmin+":"+nowMax;
+                                            }
+                                        }else{
+                                            newDataInfo = newDataInfo +"," +nowMin+":"+nowMax;
+                                        }
+                                    }
                                 }
+                                dataInfo = newDataInfo;
                             }
                             rowData[k + 2 + i] = dataInfo;
                         }

+ 6 - 6
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreePrivateController.java

@@ -495,20 +495,20 @@ public class WbsTreePrivateController extends BladeController {
      * 同步项目下所有节点参数
      */
     @ApiOperationSupport(order = 14)
-    @ApiOperation(value = "同步项目下所有节点参数", notes = "传入项目projectId")
+    @ApiOperation(value = "同步项目下所有节点参数", notes = "传入项目projectId、节点pKeyId")
     @RequestMapping(value = "/sync-node-param", method = RequestMethod.POST)
-    public R syncNodeParam(@RequestParam String projectId) {
-        return R.status(wbsTreePrivateService.syncNodeParam(projectId));
+    public R syncNodeParam(@RequestParam String projectId, @RequestParam String pKeyId) {
+        return R.status(wbsTreePrivateService.syncNodeParam(projectId, pKeyId));
     }
 
     /**
      * 同步项目下所有节点的电签默认信息
      */
     @ApiOperationSupport(order = 14)
-    @ApiOperation(value = "同步项目下所有节点的电签默认信息", notes = "传入项目projectId")
+    @ApiOperation(value = "同步项目下所有节点的电签默认信息", notes = "传入项目projectId、节点pKeyId")
     @RequestMapping(value = "/sync-project-eVisa", method = RequestMethod.POST)
-    public R syncProjectEVisa(@RequestParam String projectId) {
-        return R.status(wbsTreePrivateService.syncProjectEVisa(projectId));
+    public R syncProjectEVisa(@RequestParam String projectId, @RequestParam String pKeyId) {
+        return R.status(wbsTreePrivateService.syncProjectEVisa(projectId, pKeyId));
     }
 
     /**

+ 5 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/feign/WbsTreeContractClientImpl.java

@@ -266,6 +266,11 @@ public class WbsTreeContractClientImpl implements WbsTreeContractClient {
         return wbsTreeContractMapper.getAllTableFileSize(projectId);
     }
 
+    @Override
+    public void updateTabFileTypeByPkeyIds(List<Long> updatePKeyIds) {
+        wbsTreeContractServiceImpl.update(Wrappers.<WbsTreeContract>lambdaUpdate().set(WbsTreeContract::getTabFileType, 2).in(WbsTreeContract::getPKeyId, updatePKeyIds));
+    }
+
     private void foreachSetChildList(List<WbsTreeContractTreeVOS> vosResult, List<WbsTreeContractVO> voList) {
         voList.forEach(vo -> {
             WbsTreeContractTreeVOS vos = new WbsTreeContractTreeVOS();

+ 5 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ArchiveTreeContractMapper.java

@@ -24,6 +24,7 @@ import org.springblade.manager.vo.ArchiveTreeContractVO;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import org.springblade.manager.vo.ArchiveTreeContractVO2;
+import org.springblade.manager.vo.ArchiveTreeContractVO3;
 import org.springblade.manager.vo.ArchiveTreeVO;
 
 import java.util.List;
@@ -77,4 +78,8 @@ public interface ArchiveTreeContractMapper extends BaseMapper<ArchiveTreeContrac
 
 	@MapKey("id")
 	List<Map<String, Object>> getArchiveTreeAndArchiveCount(@Param("projectId") Long projectId,@Param("nodeId") Long nodeId);
+
+    List<ArchiveTreeContract> getArchiveTreeByNodeType(@Param("projectId")Long projectId,@Param("nodeType") Long nodeType);
+
+	List<ArchiveTreeContractVO3> getChildrenNodeByNodeId(@Param("nodeId") Long nodeId);
 }

+ 13 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ArchiveTreeContractMapper.xml

@@ -368,5 +368,18 @@
             if((SELECT COUNT(*) from m_archive_tree_contract matc WHERE parent_id = matc1.id)=0,false,true) as hasChildren
         FROM m_archive_tree_contract matc1 WHERE matc1.project_id =#{projectId} and matc1.parent_id = #{nodeId}
     </select>
+    <select id="getArchiveTreeByNodeType" resultType="org.springblade.manager.entity.ArchiveTreeContract">
+        SELECT * FROM m_archive_tree_contract
+        WHERE  parent_id = (select id from m_archive_tree_contract
+                            WHERE parent_id = (select id from m_archive_tree_contract WHERE parent_id = 0 and project_id = #{projectId})
+                            and post_type = #{nodeType})
+          and is_deleted = 0
+
+    </select>
+    <select id="getChildrenNodeByNodeId" resultType="org.springblade.manager.vo.ArchiveTreeContractVO3">
+        select matc1.*,if((SELECT COUNT(*) from m_archive_tree_contract matc WHERE matc.parent_id = matc1.id)=0,true,false)
+            as notExsitChild
+        from m_archive_tree_contract matc1 WHERE matc1.parent_id = #{nodeId} and matc1.is_deleted =0
+    </select>
 
 </mapper>

+ 5 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/IArchiveTreeContractService.java

@@ -28,6 +28,7 @@ import org.springblade.manager.vo.ArchiveTreeContractVO;
 import org.springblade.core.mp.base.BaseService;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import org.springblade.manager.vo.ArchiveTreeContractVO2;
+import org.springblade.manager.vo.ArchiveTreeContractVO3;
 
 
 import java.util.ArrayList;
@@ -35,6 +36,7 @@ import java.util.List;
 
 import java.util.List;
 import java.util.Map;
+import java.util.stream.LongStream;
 
 /**
  *  服务类
@@ -94,4 +96,7 @@ public interface IArchiveTreeContractService extends BaseService<ArchiveTreeCont
 
 	List<Map<String,Object>> getArchiveTreeAndArchiveCount(Long projectId,Long nodeId);
 
+    List<ArchiveTreeContract> getArchiveTreeByNodeType(Long projectId, Long nodeType);
+
+	List<ArchiveTreeContractVO3> getChildrenNodeByNodeId(Long nodeId);
 }

+ 7 - 7
blade-service/blade-manager/src/main/java/org/springblade/manager/service/IWbsTreePrivateService.java

@@ -48,15 +48,19 @@ public interface IWbsTreePrivateService extends BaseService<WbsTreePrivate> {
 
     boolean updateStatus(String pKeyId);
 
-    boolean updateBatchByIds(List<WbsTree> wbsTreeListAll, List<WbsTreePrivate> wbsTreePrivatesAll, String projectId, Integer wbsType);
+    boolean asyncUpdateWbsPublic(List<WbsTree> wbsTreeListAll, List<WbsTreePrivate> wbsTreePrivatesAll, String projectId, Integer wbsType);
 
-    boolean updateBatchByIds2(List<WbsTreePrivate> wbsTreePrivates, List<WbsTreePrivate> wbsTreePrivatesAllNow, String projectId, String wbsId, Integer wbsType);
+    boolean asyncUpdateWbsPrivate(List<WbsTreePrivate> wbsTreePrivates, List<WbsTreePrivate> wbsTreePrivatesAllNow, String projectId, String wbsId, Integer wbsType);
 
     WbsNodeTabAndParamVO getNodeTabAndParam(String id, String wbsId, String projectId);
 
     boolean submitFullName(String pKeyId, String fullNames);
 
-    boolean syncNodeParam(String projectId);
+    boolean syncNodeParam(String projectId, String pKeyId);
+
+    boolean syncProjectEVisa(String projectId, String pKeyId);
+
+    void eVisInfoRepeatDel(String pid);
 
     boolean syncNodeTable(String primaryKeyId);
 
@@ -77,10 +81,6 @@ public interface IWbsTreePrivateService extends BaseService<WbsTreePrivate> {
 
     Object getExcelHtml(String primaryKeyId) throws IOException;
 
-    boolean syncProjectEVisa(String projectId);
-
-    void eVisInfoRepeatDel(String pid);
-
     //批量重新保存文件htmlUrl
     void batchResetHtmlUrl(List<WbsTreePrivate> wbsTreePrivateList) throws IOException, InterruptedException;
 

+ 19 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ArchiveTreeContractServiceImpl.java

@@ -854,5 +854,24 @@ public class ArchiveTreeContractServiceImpl extends BaseServiceImpl<ArchiveTreeC
 		return baseMapper.getArchiveTreeAndArchiveCount(projectId,nodeId);
 	}
 
+	@Override
+	public List<ArchiveTreeContract> getArchiveTreeByNodeType(Long projectId, Long nodeType) {
+		if (nodeType == 1){
+			nodeType = 1537246243393589249L;
+		}else if (nodeType == 2){
+			nodeType = 1537247986361782274L;
+		}else if (nodeType == 3){
+			nodeType = 1537246384519335938L;
+		}else {
+			nodeType = 1607574141119365122L;
+		}
+		return baseMapper.getArchiveTreeByNodeType(projectId,nodeType);
+	}
+
+	@Override
+	public List<ArchiveTreeContractVO3> getChildrenNodeByNodeId(Long nodeId) {
+		return baseMapper.getChildrenNodeByNodeId(nodeId);
+	}
+
 
 }

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

@@ -235,7 +235,8 @@ public class ContractInfoServiceImpl extends BaseServiceImpl<ContractInfoMapper,
     private void recursionGetChildNodes(List<WbsTreeContract> list, List<WbsTreeContract> result, String contractId) {
         List<Long> ids = list.stream().map(WbsTreeContract::getId).collect(Collectors.toList());
         if (ids.size() > 0) {
-            List<WbsTreeContract> query = jdbcTemplate.query("select * from m_wbs_tree_contract where type = 1 and parent_id in(" + org.apache.commons.lang.StringUtils.join(ids, ",") + ") and status = 1 and is_deleted = 0 and contract_id = " + contractId, new BeanPropertyRowMapper<>(WbsTreeContract.class));
+            //只查询原始节点
+            List<WbsTreeContract> query = jdbcTemplate.query("select * from m_wbs_tree_contract where type = 1 and old_id is null and parent_id in(" + org.apache.commons.lang.StringUtils.join(ids, ",") + ") and status = 1 and is_deleted = 0 and contract_id = " + contractId, new BeanPropertyRowMapper<>(WbsTreeContract.class));
             if (query.size() > 0) {
                 result.addAll(query);
                 recursionGetChildNodes(query, result, contractId);

+ 7 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ExcelTabServiceImpl.java

@@ -1128,6 +1128,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
                         if (StringUtils.isNotEmpty(tabData[0])) {
                             if (tabVal.contains("[") && tabVal.contains("年")) {
                                 String[] strings = StringUtils.strip(tabData[0], "[]").split(",");
+
                                 reData.put(key + "__" + tabData[1], strings);
                             }else {
                                 reData.put(key + "__" + tabData[1], tabData[0]);
@@ -1314,6 +1315,12 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
                                                         myData = StringUtil.format("{}年{}月{}日", dataStr[0], dataStr[1], Integer.parseInt(dataStr[2]) + 1);
                                                     }
                                                 }
+
+                                                if(myData.indexOf("lang.String")>=0){
+                                                    String[]  dataDate = (String[]) DataInfo.get(val);
+                                                    myData = dataDate[0]+" - "+dataDate[1].trim();
+                                                }
+
                                                 //https:bladex-test-info.oss-cn-chengdu.aliyuncs.com//upload/20220819/b53cb6700db369381e3b03d7737bcdec.jpg__16_1
                                                 if (myData.indexOf("https") >= 0 && myData.indexOf("aliyuncs") >= 0) {
 

+ 526 - 396
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreePrivateServiceImpl.java

@@ -393,125 +393,116 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
     }
 
     @Override
-    public boolean updateBatchByIds(List<WbsTree> wbsTreeListAll, List<WbsTreePrivate> wbsTreePrivatesAll, String projectId, Integer wbsType) {
+    public boolean asyncUpdateWbsPublic(List<WbsTree> wbsTreeListAll, List<WbsTreePrivate> wbsTreePrivatesAll, String projectId, Integer wbsType) {
+        //结果集
         List<WbsTreePrivate> listPrivate = new ArrayList<>();
         List<WbsTreeContract> listContract = new ArrayList<>();
+
         //获取当前项目下所有合同段信息
-        List<ContractInfo> contractInfos = contractInfoMapper.selectList(Wrappers.<ContractInfo>query().lambda().eq(ContractInfo::getPId, projectId));
+        List<ContractInfo> contractInfos = contractInfoMapper.selectList(Wrappers.<ContractInfo>query().lambda().select(ContractInfo::getId, ContractInfo::getContractType).eq(ContractInfo::getPId, projectId));
+        List<Long> contractInfosIds = contractInfos.stream().filter(f -> 1 == f.getContractType()).map(ContractInfo::getId).collect(Collectors.toList());
+        Map<Long, WbsTreePrivate> maps = wbsTreePrivatesAll.stream().collect(Collectors.toMap(WbsTreePrivate::getId, wbsTreePrivate -> wbsTreePrivate, (obj1, obj2) -> obj1));
 
         for (WbsTree wbsTree : wbsTreeListAll) {
-            for (WbsTreePrivate wbsTreePrivate : wbsTreePrivatesAll) {
-                //判断相同节点基础信息、元素表类型、元素表所属方是否发生改变
-                if (wbsTree.getId().equals(wbsTreePrivate.getId()) &&
-                        (!wbsTree.getNodeName().equals(wbsTreePrivate.getNodeName())
-                                || (ObjectUtils.isNotEmpty(wbsTree.getNodeType()) && !wbsTree.getNodeType().equals(wbsTreePrivate.getNodeType()))
-                                || (ObjectUtils.isNotEmpty(wbsTree.getMajorDataType()) && !wbsTree.getMajorDataType().equals(wbsTreePrivate.getMajorDataType()))
-                                || (ObjectUtils.isNotEmpty(wbsTree.getTableType()) && !wbsTree.getTableType().equals(wbsTreePrivate.getTableType()))
-                                || (ObjectUtils.isNotEmpty(wbsTree.getTableOwner()) && !wbsTree.getTableOwner().equals(wbsTreePrivate.getTableOwner()))
-                                || (ObjectUtils.isNotEmpty(wbsTree.getImportMatchingInfo()) && !wbsTree.getImportMatchingInfo().equals(wbsTreePrivate.getImportMatchingInfo()))
-                                || (ObjectUtils.isNotEmpty(wbsTree.getMixRatioTestIds()) && !wbsTree.getMixRatioTestIds().equals(wbsTreePrivate.getMixRatioTestIds()))
-                                || (ObjectUtils.isNotEmpty(wbsTree.getInitTableId()) && !wbsTree.getInitTableId().toString().equals(wbsTreePrivate.getInitTableId()))
-                                || (ObjectUtils.isNotEmpty(wbsTree.getInitTableName()) && !wbsTree.getInitTableName().equals(wbsTreePrivate.getInitTableName()))
-                                || ((new Integer(1)).equals(wbsTreePrivate.getType()) && ObjectUtils.isNotEmpty(wbsTree.getSort()) && !wbsTree.getSort().equals(wbsTreePrivate.getSort()))
-                        )) {
-                    //修改项目wbs信息
-                    WbsTreePrivate wbsPrivate = BeanUtil.copyProperties(wbsTree, WbsTreePrivate.class);
-                    if (wbsPrivate != null) {
-                        wbsPrivate.setProjectId(projectId);
-                        listPrivate.add(wbsPrivate);
-                    }
-                    for (ContractInfo contractInfo : contractInfos) {
-                        //修改合同段wbs信息
-                        WbsTreeContract wbsContract = BeanUtil.copyProperties(wbsTree, WbsTreeContract.class);
-                        if (wbsContract != null) {
-                            wbsContract.setContractId(String.valueOf(contractInfo.getId()));
-                            wbsContract.setProjectId(projectId);
-                            listContract.add(wbsContract);
-                        }
+            WbsTreePrivate wbsTreePrivate = maps.get(wbsTree.getId());
+            //判断相同节点基础信息、元素表类型、元素表所属方是否发生改变
+            if (wbsTreePrivate != null && this.fieldsNotEqualPublicWbs(wbsTree, wbsTreePrivate)) {
+                //修改项目wbs信息
+                WbsTreePrivate wbsPrivate = BeanUtil.copyProperties(wbsTree, WbsTreePrivate.class);
+                if (wbsPrivate != null) {
+                    wbsPrivate.setProjectId(projectId);
+                    listPrivate.add(wbsPrivate);
+                }
+                for (ContractInfo contractInfo : contractInfos) {
+                    //修改合同段wbs信息
+                    WbsTreeContract wbsContract = BeanUtil.copyProperties(wbsTree, WbsTreeContract.class);
+                    if (wbsContract != null) {
+                        wbsContract.setContractId(String.valueOf(contractInfo.getId()));
+                        wbsContract.setProjectId(projectId);
+                        listContract.add(wbsContract);
                     }
                 }
             }
         }
 
+        //修改到项目
         if (listPrivate.size() > 0) {
             baseMapper.updateBatchWbsPrivate(listPrivate);
         }
-        if (listContract.size() > 0) {
-            //获取合同段下的复制、新增节点
-            List<WbsTreeContract> wbsTreeContractsCopyOrAddAll = new ArrayList<>();
-            for (ContractInfo contractInfo : contractInfos) {
-                List<WbsTreeContract> wbsTreeContractsCopyOrAdd = wbsTreeContractMapper.selectList(Wrappers.<WbsTreeContract>lambdaQuery()
-                        .eq(WbsTreeContract::getProjectId, projectId)
-                        .eq(WbsTreeContract::getContractId, contractInfo.getId())
-                        .eq(WbsTreeContract::getWbsType, wbsType)
-                        .eq(WbsTreeContract::getType, 1)
-                        .isNotNull(WbsTreeContract::getOldId)
-                );
-                wbsTreeContractsCopyOrAddAll.addAll(wbsTreeContractsCopyOrAdd);
-            }
 
+        //修改到合同段
+        if (listContract.size() > 0) {
+            //获取当前项目下所有合同段下的复制、新增节点
+            String sql = "select id,old_id,project_id,contract_id from m_wbs_tree_contract where project_id = " + projectId + " and contract_id in(" + org.apache.commons.lang.StringUtils.join(contractInfosIds, ",") + ") and wbs_type = " + wbsType + " and type = 1 and status = 1 and is_deleted = 0 and old_id is not null";
+            List<WbsTreeContract> wbsTreeContractsCopyOrAddAll = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(WbsTreeContract.class));
+            Map<String, List<WbsTreeContract>> copyAddNodes = wbsTreeContractsCopyOrAddAll.stream().collect(Collectors.groupingBy(WbsTreeContract::getOldId));
             List<WbsTreeContract> listContractAdd = new ArrayList<>();
-
             for (WbsTreeContract obj1 : listContract) {
-                for (WbsTreeContract obj2 : wbsTreeContractsCopyOrAddAll) {
-                    if (obj1.getId().toString().equals(obj2.getOldId()) && obj1.getProjectId().equals(obj2.getProjectId()) && obj1.getContractId().equals(obj2.getContractId())) {
+                List<WbsTreeContract> copyAddNodesNow = copyAddNodes.get(obj1.getId().toString());
+                if (ObjectUtils.isNotEmpty(copyAddNodesNow) && copyAddNodesNow.size() > 0) {
+                    WbsTreeContract obj2 = copyAddNodesNow.stream().filter(f -> f.getContractId().equals(obj1.getContractId()) && f.getProjectId().equals(obj1.getProjectId())).findAny().orElse(null);
+                    if (obj2 != null) {
                         obj2.setNodeName(obj1.getNodeName());
                         obj2.setNodeType(obj1.getNodeType());
                         obj2.setMajorDataType(obj1.getMajorDataType());
                         obj2.setTableType(obj1.getTableType());
                         obj2.setTableOwner(obj1.getTableOwner());
+                        obj2.setHtmlUrl(obj1.getHtmlUrl());
                         listContractAdd.add(obj2);
                     }
                 }
             }
-
             listContractAdd.addAll(listContract);
             wbsTreeContractMapper.updateBatchWbsContract(listContractAdd);
+
+            //更新redis缓存
+            this.refreshRedisCache(listContractAdd);
         }
         return true;
     }
 
+    @Async
+    public void refreshRedisCache(List<WbsTreeContract> listContractAdd) {
+        Map<Long, List<String>> contractIdByParentIds = listContractAdd.stream()
+                .collect(Collectors.groupingBy(WbsTreeContract::getParentId,
+                        Collectors.mapping(WbsTreeContract::getContractId, Collectors.toList())));
+        Set<Long> parentIds = contractIdByParentIds.keySet();
+        for (Long parentId : parentIds) {
+            String contractId = contractIdByParentIds.get(parentId).stream().findAny().orElse(null);
+            informationQueryClient.AsyncWbsTree("", parentId + "", contractId + "", "", "1");
+        }
+    }
+
     @Override
-    public boolean updateBatchByIds2(List<WbsTreePrivate> wbsTreePrivates, List<WbsTreePrivate> wbsTreePrivatesAllNow, String projectId, String wbsId, Integer wbsType) {
+    public boolean asyncUpdateWbsPrivate(List<WbsTreePrivate> wbsTreePrivates, List<WbsTreePrivate> wbsTreePrivatesAllNow, String projectId, String wbsId, Integer wbsType) {
+        //结果集
         List<WbsTreePrivate> listPrivate = new ArrayList<>();
         List<WbsTreeContract> listContract = new ArrayList<>();
+
         //获取当前项目下所有合同段信息
-        List<ContractInfo> contractInfos = contractInfoMapper.selectList(Wrappers.<ContractInfo>query().lambda().select(ContractInfo::getId, ContractInfo::getContractType)
-                .eq(ContractInfo::getContractType, 1)
-                .eq(ContractInfo::getPId, projectId));
+        List<ContractInfo> contractInfos = contractInfoMapper.selectList(Wrappers.<ContractInfo>query().lambda().select(ContractInfo::getId, ContractInfo::getContractType).eq(ContractInfo::getContractType, 1).eq(ContractInfo::getPId, projectId));
         List<Long> contractInfosIds = contractInfos.stream().filter(f -> 1 == f.getContractType()).map(ContractInfo::getId).collect(Collectors.toList());
 
         Map<Long, WbsTreePrivate> maps = wbsTreePrivatesAllNow.stream().collect(Collectors.toMap(WbsTreePrivate::getId, wbsTreePrivate -> wbsTreePrivate, (obj1, obj2) -> obj1));
 
         for (WbsTreePrivate wbsTreePrivate : wbsTreePrivates) {
             WbsTreePrivate treePrivateNow = maps.get(wbsTreePrivate.getId());
-            if (treePrivateNow != null) {
-                if (!wbsTreePrivate.getNodeName().equals(treePrivateNow.getNodeName())
-                        || (ObjectUtils.isNotEmpty(wbsTreePrivate.getNodeType()) && !wbsTreePrivate.getNodeType().equals(treePrivateNow.getNodeType()))
-                        || (ObjectUtils.isNotEmpty(wbsTreePrivate.getMajorDataType()) && !wbsTreePrivate.getMajorDataType().equals(treePrivateNow.getMajorDataType()))
-                        || (ObjectUtils.isNotEmpty(wbsTreePrivate.getTableType()) && !wbsTreePrivate.getTableType().equals(treePrivateNow.getTableType()))
-                        || (ObjectUtils.isNotEmpty(wbsTreePrivate.getTableOwner()) && !wbsTreePrivate.getTableOwner().equals(treePrivateNow.getTableOwner()))
-                        || (ObjectUtils.isNotEmpty(wbsTreePrivate.getImportMatchingInfo()) && !wbsTreePrivate.getImportMatchingInfo().equals(treePrivateNow.getImportMatchingInfo()))
-                        || (ObjectUtils.isNotEmpty(wbsTreePrivate.getMixRatioTestIds()) && !wbsTreePrivate.getMixRatioTestIds().equals(treePrivateNow.getMixRatioTestIds()))
-                        || (ObjectUtils.isNotEmpty(wbsTreePrivate.getInitTableId()) && !wbsTreePrivate.getInitTableId().equals(treePrivateNow.getInitTableId()))
-                        || (ObjectUtils.isNotEmpty(wbsTreePrivate.getInitTableName()) && !wbsTreePrivate.getInitTableName().equals(treePrivateNow.getInitTableName())
-                        || (ObjectUtils.isNotEmpty(wbsTreePrivate.getHtmlUrl()) && !wbsTreePrivate.getHtmlUrl().equals(treePrivateNow.getHtmlUrl())))
-                        || ((new Integer(1)).equals(wbsTreePrivate.getType()) && ObjectUtils.isNotEmpty(wbsTreePrivate.getSort()) && !wbsTreePrivate.getSort().equals(treePrivateNow.getSort()))) {
-                    //修改项目wbs信息
-                    WbsTreePrivate wbsPrivate = BeanUtil.copyProperties(wbsTreePrivate, WbsTreePrivate.class);
-                    if (wbsPrivate != null) {
-                        wbsPrivate.setWbsId(wbsId);
-                        wbsPrivate.setProjectId(projectId);
-                        listPrivate.add(wbsPrivate);
-                    }
-                    for (Long id : contractInfosIds) {
-                        //修改合同段wbs信息
-                        WbsTreeContract wbsContract = BeanUtil.copyProperties(wbsTreePrivate, WbsTreeContract.class);
-                        if (wbsContract != null) {
-                            wbsContract.setContractId(id.toString());
-                            wbsContract.setProjectId(projectId);
-                            listContract.add(wbsContract);
-                        }
+            //判断相同节点基础信息、元素表类型、元素表所属方是否发生改变
+            if (treePrivateNow != null && this.fieldsNotEqualPrivateWbs(wbsTreePrivate, treePrivateNow)) {
+                //修改项目wbs信息
+                WbsTreePrivate wbsPrivate = BeanUtil.copyProperties(wbsTreePrivate, WbsTreePrivate.class);
+                if (wbsPrivate != null) {
+                    wbsPrivate.setWbsId(wbsId);
+                    wbsPrivate.setProjectId(projectId);
+                    listPrivate.add(wbsPrivate);
+                }
+                for (Long id : contractInfosIds) {
+                    //修改合同段wbs信息
+                    WbsTreeContract wbsContract = BeanUtil.copyProperties(wbsTreePrivate, WbsTreeContract.class);
+                    if (wbsContract != null) {
+                        wbsContract.setContractId(id.toString());
+                        wbsContract.setProjectId(projectId);
+                        listContract.add(wbsContract);
                     }
                 }
             }
@@ -528,7 +519,6 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
             String sql = "select id,old_id,project_id,contract_id from m_wbs_tree_contract where project_id = " + projectId + " and contract_id in(" + org.apache.commons.lang.StringUtils.join(contractInfosIds, ",") + ") and wbs_type = " + wbsType + " and type = 1 and status = 1 and is_deleted = 0 and old_id is not null";
             List<WbsTreeContract> wbsTreeContractsCopyOrAddAll = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(WbsTreeContract.class));
             Map<String, List<WbsTreeContract>> copyAddNodes = wbsTreeContractsCopyOrAddAll.stream().collect(Collectors.groupingBy(WbsTreeContract::getOldId));
-
             List<WbsTreeContract> listContractAdd = new ArrayList<>();
             for (WbsTreeContract obj1 : listContract) {
                 List<WbsTreeContract> copyAddNodesNow = copyAddNodes.get(obj1.getId().toString());
@@ -545,13 +535,89 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
                     }
                 }
             }
-
             listContractAdd.addAll(listContract);
             wbsTreeContractMapper.updateBatchWbsContract(listContractAdd);
+
+            //更新redis缓存
+            this.refreshRedisCache(listContractAdd);
         }
         return true;
     }
 
+    /**
+     * 比较对象字段是否相等 公有wbs
+     *
+     * @param a
+     * @param b
+     * @return boolean
+     */
+    private boolean fieldsNotEqualPublicWbs(WbsTree a, WbsTreePrivate b) {
+        if (new Integer(1).equals(a.getType())) {
+            return !Objects.equals(nonNull(a.getNodeName()), nonNull(b.getNodeName()))
+                    || !Objects.equals(nonNull(a.getNodeType()), nonNull(b.getNodeType()))
+                    || !Objects.equals(nonNull(a.getMajorDataType()), nonNull(b.getMajorDataType()))
+                    || !Objects.equals(nonNull(a.getTableType()), nonNull(b.getTableType()))
+                    || !Objects.equals(nonNull(a.getTableOwner()), nonNull(b.getTableOwner()))
+                    || !Objects.equals(nonNull(a.getImportMatchingInfo()), nonNull(b.getImportMatchingInfo()))
+                    || !Objects.equals(nonNull(a.getMixRatioTestIds()), nonNull(b.getMixRatioTestIds()))
+                    || !Objects.equals(nonNull(a.getInitTableId()), nonNull(b.getInitTableId()))
+                    || !Objects.equals(nonNull(a.getInitTableName()), nonNull(b.getInitTableName()))
+                    || !Objects.equals(a.getSort(), b.getSort());
+        }
+        return !Objects.equals(nonNull(a.getNodeName()), nonNull(b.getNodeName()))
+                || !Objects.equals(nonNull(a.getNodeType()), nonNull(b.getNodeType()))
+                || !Objects.equals(nonNull(a.getMajorDataType()), nonNull(b.getMajorDataType()))
+                || !Objects.equals(nonNull(a.getTableType()), nonNull(b.getTableType()))
+                || !Objects.equals(nonNull(a.getTableOwner()), nonNull(b.getTableOwner()))
+                || !Objects.equals(nonNull(a.getImportMatchingInfo()), nonNull(b.getImportMatchingInfo()))
+                || !Objects.equals(nonNull(a.getMixRatioTestIds()), nonNull(b.getMixRatioTestIds()))
+                || !Objects.equals(nonNull(a.getInitTableId()), nonNull(b.getInitTableId()))
+                || !Objects.equals(nonNull(a.getInitTableName()), nonNull(b.getInitTableName()));
+    }
+
+    /**
+     * 比较对象字段是否相等 私有wbs
+     *
+     * @param a
+     * @param b
+     * @return boolean
+     */
+    private boolean fieldsNotEqualPrivateWbs(WbsTreePrivate a, WbsTreePrivate b) {
+        if (new Integer(1).equals(a.getType())) {
+            return !Objects.equals(nonNull(a.getNodeName()), nonNull(b.getNodeName()))
+                    || !Objects.equals(nonNull(a.getNodeType()), nonNull(b.getNodeType()))
+                    || !Objects.equals(nonNull(a.getMajorDataType()), nonNull(b.getMajorDataType()))
+                    || !Objects.equals(nonNull(a.getTableType()), nonNull(b.getTableType()))
+                    || !Objects.equals(nonNull(a.getTableOwner()), nonNull(b.getTableOwner()))
+                    || !Objects.equals(nonNull(a.getImportMatchingInfo()), nonNull(b.getImportMatchingInfo()))
+                    || !Objects.equals(nonNull(a.getMixRatioTestIds()), nonNull(b.getMixRatioTestIds()))
+                    || !Objects.equals(nonNull(a.getInitTableId()), nonNull(b.getInitTableId()))
+                    || !Objects.equals(nonNull(a.getInitTableName()), nonNull(b.getInitTableName()))
+                    || !Objects.equals(nonNull(a.getHtmlUrl()), nonNull(b.getHtmlUrl()))
+                    || !Objects.equals(nonNull(a.getSort()), nonNull(b.getSort()));
+        }
+        return !Objects.equals(nonNull(a.getNodeName()), nonNull(b.getNodeName()))
+                || !Objects.equals(nonNull(a.getNodeType()), nonNull(b.getNodeType()))
+                || !Objects.equals(nonNull(a.getMajorDataType()), nonNull(b.getMajorDataType()))
+                || !Objects.equals(nonNull(a.getTableType()), nonNull(b.getTableType()))
+                || !Objects.equals(nonNull(a.getTableOwner()), nonNull(b.getTableOwner()))
+                || !Objects.equals(nonNull(a.getImportMatchingInfo()), nonNull(b.getImportMatchingInfo()))
+                || !Objects.equals(nonNull(a.getMixRatioTestIds()), nonNull(b.getMixRatioTestIds()))
+                || !Objects.equals(nonNull(a.getInitTableId()), nonNull(b.getInitTableId()))
+                || !Objects.equals(nonNull(a.getInitTableName()), nonNull(b.getInitTableName()))
+                || !Objects.equals(nonNull(a.getHtmlUrl()), nonNull(b.getHtmlUrl()));
+    }
+
+    /**
+     * 字段非空判断
+     *
+     * @param obj
+     * @return
+     */
+    private Object nonNull(Object obj) {
+        return obj != null ? obj : "";
+    }
+
     @Override
     public WbsNodeTabAndParamVO getNodeTabAndParam(String id, String wbsId, String projectId) {
         WbsNodeTabAndParamVO resultList = new WbsNodeTabAndParamVO();
@@ -591,230 +657,366 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
         return false;
     }
 
+    /**
+     * 节点参数同步-获取所有子级节点
+     */
+    private List<WbsTreePrivate> getChildNodes(WbsTreePrivate obj) {
+        if (obj != null) {
+            List<WbsTreePrivate> wbsTreePrivates = Collections.singletonList(obj);
+            List<WbsTreePrivate> result = new ArrayList<>();
+            this.recursionGetChildNodes(wbsTreePrivates, result, obj);
+            if (result.size() > 0) {
+                return result;
+            }
+        }
+        return null;
+    }
+
+    private void recursionGetChildNodes(List<WbsTreePrivate> list, List<WbsTreePrivate> result, WbsTreePrivate obj) {
+        List<Long> ids = list.stream().map(WbsTreePrivate::getId).collect(Collectors.toList());
+        if (ids.size() > 0) {
+            List<WbsTreePrivate> query = baseMapper.selectList(Wrappers.<WbsTreePrivate>lambdaQuery()
+                    .select(WbsTreePrivate::getPKeyId, WbsTreePrivate::getId)
+                    .in(WbsTreePrivate::getParentId, ids)
+                    .eq(WbsTreePrivate::getProjectId, obj.getProjectId())
+                    .eq(WbsTreePrivate::getWbsId, obj.getWbsId())
+                    .eq(WbsTreePrivate::getWbsType, obj.getWbsType())
+                    .eq(WbsTreePrivate::getType, 1)
+                    .eq(WbsTreePrivate::getStatus, 1));
+            if (query.size() > 0) {
+                result.addAll(query);
+                recursionGetChildNodes(query, result, obj);
+            }
+        }
+    }
+
+
     @Override
-    public boolean syncNodeParam(String projectId) {
-        if (StringUtils.isNotEmpty(projectId)) {
+    public boolean syncNodeParam(String projectId, String pKeyId) {
+        if (StringUtils.isNotEmpty(projectId) && StringUtils.isNotEmpty(pKeyId)) {
+            //当前选择同步的节点信息
+            WbsTreePrivate selectNodeNow = baseMapper.selectOne(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getPKeyId, pKeyId).eq(WbsTreePrivate::getStatus, 1));
+            if (selectNodeNow == null) {
+                throw new ServiceException("未获取到当前选择同步的节点信息,请联系管理员");
+            }
+
             //结果集
             List<WbsParam> updateList = new ArrayList<>();
             List<WbsParam> insertList = new ArrayList<>();
+            List<WbsParamVO> paramListData = new ArrayList<>();
+            List<WbsParam> wbsParamOldList = new ArrayList<>();
+
+            //获取当前选择的节点与它所有子节点
+            List<WbsTreePrivate> selectNodeAndChildNodes = this.getChildNodes(selectNodeNow);
+            if (selectNodeAndChildNodes == null || selectNodeAndChildNodes.size() == 0) {
+                selectNodeAndChildNodes = new ArrayList<>();
+                selectNodeAndChildNodes.add(selectNodeNow);
+            } else {
+                selectNodeAndChildNodes.add(selectNodeNow);
+            }
+            List<Long> privateNodeIds = selectNodeAndChildNodes.stream().map(WbsTreePrivate::getId).collect(Collectors.toList());
+            List<Long> privateNodePKeyIds = selectNodeAndChildNodes.stream().map(WbsTreePrivate::getPKeyId).collect(Collectors.toList());
+
+            //获取对应公有树节点
+            Map<Long, WbsTree> treePublicNodeAll = wbsTreeMapper.selectList(Wrappers.<WbsTree>query().lambda()
+                    .select(WbsTree::getId)
+                    .in(WbsTree::getId, privateNodeIds)
+                    .eq(WbsTree::getStatus, 1)
+                    .eq(WbsTree::getType, 1))
+                    .stream().collect(Collectors.toMap(WbsTree::getId, Function.identity()));
+
+            if (treePublicNodeAll.size() > 0) {
+                //TODO ---------公有引用同步---------
+                Map<String, Long> map = new HashMap<>();
+                for (WbsTreePrivate wbsTreePrivate : selectNodeAndChildNodes) {
+                    WbsTree wbsTree = treePublicNodeAll.get(wbsTreePrivate.getId());
+                    if (wbsTree != null) {
+                        map.put(wbsTreePrivate.getPKeyId() + "," + wbsTree.getId(), wbsTree.getId());
+                    }
+                }
 
-            //获取项目节点树、包括试验、资料填报
-            List<WbsTreePrivate> wbsTreePrivateAllNow = baseMapper.selectList(Wrappers.<WbsTreePrivate>query().lambda()
-                    .select(WbsTreePrivate::getPKeyId, WbsTreePrivate::getId, WbsTreePrivate::getWbsId)
-                    .eq(WbsTreePrivate::getProjectId, projectId)
-                    .eq(WbsTreePrivate::getStatus, 1)
-                    .eq(WbsTreePrivate::getType, 1)
-                    .in(WbsTreePrivate::getWbsType, Arrays.asList(1, 2)));
-
-            Map<String, List<String>> collect = wbsTreePrivateAllNow.stream().map(WbsTreePrivate::getWbsId).collect(Collectors.groupingBy(Object::toString));
-            for (Map.Entry<String, List<String>> wbsIds : collect.entrySet()) {
-                String wbsId = wbsIds.getKey();
-                if (StringUtils.isNotEmpty(wbsId)) {
-                    List<WbsParamVO> paramListData = new ArrayList<>();
-                    //获取公有树
-                    Map<Long, WbsTree> treePublicNodeAll = wbsTreeMapper.selectList(Wrappers.<WbsTree>query().lambda()
-                            .select(WbsTree::getId)
-                            .eq(WbsTree::getWbsId, wbsId)
-                            .eq(WbsTree::getStatus, 1)
-                            .eq(WbsTree::getType, 1))
-                            .stream().collect(Collectors.toMap(WbsTree::getId, Function.identity()));
-
-                    if (treePublicNodeAll.size() > 0) {
-                        //TODO ---------公有引用同步---------
-                        Map<String, Long> map = new HashMap<>();
-                        for (WbsTreePrivate wbsTreePrivate : wbsTreePrivateAllNow) {
-                            WbsTree wbsTree = treePublicNodeAll.get(wbsTreePrivate.getId());
-                            if (wbsTree != null) {
-                                map.put(wbsTreePrivate.getPKeyId() + "," + wbsTree.getId(), wbsTree.getId());
+                //分组查询公有节点的对应节点参数信息
+                Set<String> keyIds = map.keySet();
+                List<Long> wbsTreeIds = new ArrayList<>(map.values());
+                List<List<Long>> partition = Lists.partition(wbsTreeIds, 1000);
+                for (List<Long> ids : partition) {
+                    String sql = "select id,name,k,v,node_id,remark from m_wbs_param where node_id in (" + org.apache.commons.lang.StringUtils.join(ids, ",") + ")";
+                    List<WbsParam> wbsParams = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(WbsParam.class));
+                    wbsParamOldList.addAll(wbsParams);
+                }
+
+                //构造当前项目的节点参数信息
+                for (String ids : keyIds) {
+                    String nodePKeyIdNow = ids.split(",")[0];
+                    String nodeIdOld = ids.split(",")[1];
+                    List<WbsParam> wbsParams = wbsParamOldList.stream().filter(f -> ObjectUtils.isNotEmpty(f.getNodeId()) && f.getNodeId().toString().equals(nodeIdOld)).collect(Collectors.toList());
+                    //获取引用的节点参数
+                    if (wbsParams.size() > 0) {
+                        for (WbsParam wbsParam : wbsParams) {
+                            WbsParamVO param = BeanUtil.copyProperties(wbsParam, WbsParamVO.class);
+                            if (param != null) {
+                                param.setProjectId(Long.parseLong(projectId));
+                                param.setId(SnowFlakeUtil.getId());
+                                param.setNodeId(Long.parseLong(nodePKeyIdNow));
+                                param.setOldId(wbsParam.getId());
+                                param.setType(1);
+                                param.setStatus(1);
+                                param.setIsDeleted(0);
+                                paramListData.add(param);
                             }
                         }
+                    }
+                }
 
-                        Set<String> keyIds = map.keySet();
-                        List<Long> wbsTreeIds = new ArrayList<>(map.values());
-                        List<WbsParam> wbsParamList = new ArrayList<>();
-                        //分组查询
-                        List<List<Long>> partition = Lists.partition(wbsTreeIds, 1000);
-                        for (List<Long> ids : partition) {
-                            String sql = "select id,name,k,v,node_id,remark from m_wbs_param where node_id in (" + org.apache.commons.lang.StringUtils.join(ids, ",") + ")";
-                            List<WbsParam> wbsParams = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(WbsParam.class));
-                            wbsParamList.addAll(wbsParams);
-                        }
+            } else {
+                //TODO ---------私有引用同步---------
+                Map<String, Long> map = new HashMap<>();
+                //获取当前私有引用模板的根节点信息
+                WbsTreePrivate treePrivateRootNode = baseMapper.selectOne(Wrappers.<WbsTreePrivate>query().lambda()
+                        .select(WbsTreePrivate::getWbsId, WbsTreePrivate::getProjectId)
+                        .eq(WbsTreePrivate::getPKeyId, selectNodeNow.getWbsId()).eq(WbsTreePrivate::getParentId, 0L).eq(WbsTreePrivate::getStatus, 1).eq(WbsTreePrivate::getType, 1));
+
+                //获取当前私有引用模板的对应节点与它的所有子节点
+                WbsTreePrivate selectRecordNode = baseMapper.selectOne(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getWbsId, treePrivateRootNode.getWbsId()).eq(WbsTreePrivate::getId, selectNodeNow.getId()).eq(WbsTreePrivate::getProjectId, treePrivateRootNode.getProjectId()).eq(WbsTreePrivate::getStatus, 1));
+                List<WbsTreePrivate> selectNodeAndChildNodesRecord = this.getChildNodes(selectRecordNode);
+                selectNodeAndChildNodesRecord.add(selectRecordNode);
+                Map<Long, WbsTreePrivate> treePrivateNodeAll = selectNodeAndChildNodesRecord.stream().collect(Collectors.toMap(WbsTreePrivate::getId, Function.identity()));
+
+                for (WbsTreePrivate wbsTreePrivate : selectNodeAndChildNodes) {
+                    WbsTreePrivate wbsTreePrivateYS = treePrivateNodeAll.get(wbsTreePrivate.getId());
+                    if (wbsTreePrivateYS != null) {
+                        map.put(wbsTreePrivate.getPKeyId() + "," + wbsTreePrivateYS.getPKeyId(), wbsTreePrivateYS.getPKeyId());
+                    }
+                }
 
-                        for (String ids : keyIds) {
-                            String nodePKeyIdNow = ids.split(",")[0];
-                            String nodeIdOld = ids.split(",")[1];
-                            List<WbsParam> wbsParams = wbsParamList.stream().filter(f -> ObjectUtils.isNotEmpty(f.getNodeId()) && f.getNodeId().toString().equals(nodeIdOld)).collect(Collectors.toList());
-                            //获取引用的节点参数
-                            if (wbsParams.size() > 0) {
-                                for (WbsParam wbsParam : wbsParams) {
-                                    WbsParamVO param = BeanUtil.copyProperties(wbsParam, WbsParamVO.class);
-                                    if (param != null) {
-                                        param.setProjectId(Long.parseLong(projectId));
-                                        param.setId(SnowFlakeUtil.getId());
-                                        param.setNodeId(Long.parseLong(nodePKeyIdNow));
-                                        param.setOldId(wbsParam.getId());
-                                        param.setType(1);
-                                        param.setStatus(1);
-                                        param.setIsDeleted(0);
-                                        paramListData.add(param);
-                                    }
-                                }
-                            }
-                        }
+                //分组查询公有节点的对应节点参数信息
+                Set<String> keyIds = map.keySet();
+                List<Long> wbsTreeIds = new ArrayList<>(map.values());
+                List<List<Long>> partition = Lists.partition(wbsTreeIds, 1000);
+                for (List<Long> ids : partition) {
+                    String sql = "select id,name,k,v,node_id,remark from m_wbs_param where node_id in (" + org.apache.commons.lang.StringUtils.join(ids, ",") + ")";
+                    List<WbsParam> wbsParams = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(WbsParam.class));
+                    wbsParamOldList.addAll(wbsParams);
+                }
 
 
-                    } else {
-                        //TODO ---------私有引用同步---------
-                        Map<String, Long> map = new HashMap<>();
-                        WbsTreePrivate treePrivateRootNode = baseMapper.selectOne(Wrappers.<WbsTreePrivate>query().lambda()
-                                .select(WbsTreePrivate::getWbsId, WbsTreePrivate::getProjectId)
-                                .eq(WbsTreePrivate::getPKeyId, wbsId).eq(WbsTreePrivate::getParentId, 0L).eq(WbsTreePrivate::getStatus, 1).eq(WbsTreePrivate::getType, 1));
-
-                        Map<Long, WbsTreePrivate> treePrivateNodeAll = baseMapper.selectList(Wrappers.<WbsTreePrivate>query().lambda()
-                                .select(WbsTreePrivate::getPKeyId, WbsTreePrivate::getId)
-                                .eq(WbsTreePrivate::getWbsId, treePrivateRootNode.getWbsId()).eq(WbsTreePrivate::getProjectId, treePrivateRootNode.getProjectId())
-                                .eq(WbsTreePrivate::getStatus, 1).eq(WbsTreePrivate::getType, 1)).stream().collect(Collectors.toMap(WbsTreePrivate::getId, Function.identity()));
-
-                        for (WbsTreePrivate wbsTreePrivate : wbsTreePrivateAllNow) {
-                            WbsTreePrivate wbsTreePrivateYS = treePrivateNodeAll.get(wbsTreePrivate.getId());
-                            if (wbsTreePrivateYS != null) {
-                                map.put(wbsTreePrivate.getPKeyId() + "," + wbsTreePrivateYS.getPKeyId(), wbsTreePrivateYS.getPKeyId());
+                //构造当前项目的节点参数信息
+                for (String ids : keyIds) {
+                    String nodePKeyIdNow = ids.split(",")[0];
+                    String nodePKeyIdYs = ids.split(",")[1];
+                    List<WbsParam> wbsParams = wbsParamOldList.stream().filter(f -> ObjectUtils.isNotEmpty(f.getNodeId()) && f.getNodeId().toString().equals(nodePKeyIdYs)).collect(Collectors.toList());
+                    //获取引用的节点参数
+                    if (wbsParams.size() > 0) {
+                        for (WbsParam wbsParam : wbsParams) {
+                            WbsParamVO param = BeanUtil.copyProperties(wbsParam, WbsParamVO.class);
+                            if (param != null) {
+                                param.setProjectId(Long.parseLong(projectId));
+                                param.setId(SnowFlakeUtil.getId());
+                                param.setNodeId(Long.parseLong(nodePKeyIdNow));
+                                param.setOldId(wbsParam.getId());
+                                param.setType(1);
+                                param.setStatus(1);
+                                param.setIsDeleted(0);
+                                paramListData.add(param);
                             }
                         }
+                    }
+                }
+            }
 
-                        Set<String> keyIds = map.keySet();
-                        List<Long> wbsTreeIds = new ArrayList<>(map.values());
-                        List<WbsParam> wbsParamList = new ArrayList<>();
-                        //分组查询
-                        List<List<Long>> partition = Lists.partition(wbsTreeIds, 1000);
-                        for (List<Long> ids : partition) {
-                            String sql = "select id,name,k,v,node_id,remark from m_wbs_param where node_id in (" + org.apache.commons.lang.StringUtils.join(ids, ",") + ")";
-                            List<WbsParam> wbsParams = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(WbsParam.class));
-                            wbsParamList.addAll(wbsParams);
-                        }
+            //当前引用模板的节点参数,数据源Map
+            Map<Long, WbsParam> paramOldDataMap = wbsParamOldList.stream().collect(Collectors.toMap(WbsParam::getId, Function.identity()));
+            //获取当前项目的选择的该节点的节点、以及子节点下的参数信息
+            List<WbsParam> paramListNow = wbsParamMapper.selectList(Wrappers.<WbsParam>lambdaQuery().select(WbsParam::getK, WbsParam::getV, WbsParam::getName, WbsParam::getId, WbsParam::getRemark, WbsParam::getNodeId).eq(WbsParam::getProjectId, Long.parseLong(projectId)).in(WbsParam::getNodeId, privateNodePKeyIds));
+            //将参数名称、K和nodeId作为唯一标识存储到一个Map中
+            Map<String, WbsParam> paramMap = new HashMap<>();
+            for (WbsParam nowObj : paramListNow) {
+                String key = nowObj.getName() + "_" + nowObj.getK() + "_" + nowObj.getNodeId();
+                paramMap.put(key, nowObj);
+            }
 
-                        for (String ids : keyIds) {
-                            String nodePKeyIdNow = ids.split(",")[0];
-                            String nodePKeyIdYs = ids.split(",")[1];
-                            List<WbsParam> wbsParams = wbsParamList.stream().filter(f -> ObjectUtils.isNotEmpty(f.getNodeId()) && f.getNodeId().toString().equals(nodePKeyIdYs)).collect(Collectors.toList());
-                            //获取引用的节点参数
-                            if (wbsParams.size() > 0) {
-                                for (WbsParam wbsParam : wbsParams) {
-                                    WbsParamVO param = BeanUtil.copyProperties(wbsParam, WbsParamVO.class);
-                                    if (param != null) {
-                                        param.setProjectId(Long.parseLong(projectId));
-                                        param.setId(SnowFlakeUtil.getId());
-                                        param.setNodeId(Long.parseLong(nodePKeyIdNow));
-                                        param.setOldId(wbsParam.getId());
-                                        param.setType(1);
-                                        param.setStatus(1);
-                                        param.setIsDeleted(0);
-                                        paramListData.add(param);
-                                    }
-                                }
-                            }
+            //数据构造
+            for (WbsParamVO next : paramListData) {
+                //获取引用模板节点上的源数据节点参数信息
+                WbsParam oldObj = paramOldDataMap.get(next.getOldId());
+                if (oldObj != null) {
+                    //获取当前项目选择的节点、子节点上的现有参数信息,通过name、K、nodeId判断
+                    WbsParam nowObj = paramMap.getOrDefault(next.getName() + "_" + next.getK() + "_" + next.getNodeId(), null);
+                    if (nowObj == null) {
+                        //新增
+                        WbsParam wbsParam = BeanUtil.copyProperties(next, WbsParam.class);
+                        if (wbsParam != null) {
+                            wbsParam.setId(SnowFlakeUtil.getId());
+                            insertList.add(wbsParam);
+                        }
+                    } else if (!Objects.equals(oldObj.getV(), nowObj.getV()) || !Objects.equals(oldObj.getRemark(), nowObj.getRemark())) {
+                        //修改
+                        WbsParam wbsParam1 = BeanUtil.copyProperties(nowObj, WbsParam.class);
+                        if (wbsParam1 != null) {
+                            wbsParam1.setProjectId(Long.parseLong(projectId));
+                            wbsParam1.setV(oldObj.getV());
+                            wbsParam1.setRemark(oldObj.getRemark());
+                            wbsParam1.setType(1);
+                            wbsParam1.setStatus(1);
+                            wbsParam1.setIsDeleted(0);
+                            updateList.add(wbsParam1);
                         }
                     }
+                }
+            }
+
+            //修改
+            if (!updateList.isEmpty()) {
+                List<List<WbsParam>> partition = Lists.partition(updateList, 1000);
+                for (List<WbsParam> updateData : partition) {
+                    this.wbsParamServiceImpl.updateBatchById(updateData, 1000);
+                }
+            }
+
+            //新增
+            if (!insertList.isEmpty()) {
+                List<List<WbsParam>> partition = Lists.partition(insertList, 1000);
+                for (List<WbsParam> addData : partition) {
+                    wbsParamServiceImpl.insertBatch(addData, 1000);
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 电签同步-获取所有子级节点、表
+     */
+    private List<WbsTreePrivate> getChildNodesAndTabs(WbsTreePrivate obj) {
+        if (obj != null) {
+            List<WbsTreePrivate> wbsTreePrivates = Collections.singletonList(obj);
+            List<WbsTreePrivate> result = new ArrayList<>();
+            this.recursionGetChildNodesAndTabs(wbsTreePrivates, result, obj);
+            if (result.size() > 0) {
+                return result;
+            }
+        }
+        return null;
+    }
+
+    private void recursionGetChildNodesAndTabs(List<WbsTreePrivate> list, List<WbsTreePrivate> result, WbsTreePrivate obj) {
+        List<Long> ids = list.stream().map(WbsTreePrivate::getId).collect(Collectors.toList());
+        if (ids.size() > 0) {
+            List<WbsTreePrivate> query = jdbcTemplate.query("select p_key_id,id,type,parent_id,html_url from m_wbs_tree_private where parent_id in(" + org.apache.commons.lang.StringUtils.join(ids, ",") + ") and status = 1 and is_deleted = 0 and project_id = " + obj.getProjectId(), new BeanPropertyRowMapper<>(WbsTreePrivate.class));
+            if (query.size() > 0) {
+                result.addAll(query);
+                recursionGetChildNodesAndTabs(query, result, obj);
+            }
+        }
+    }
+
+    @Override
+    public boolean syncProjectEVisa(String projectId, String pKeyId) {
+        if (StringUtils.isNotEmpty(projectId) && StringUtils.isNotEmpty(pKeyId)) {
+            ProjectInfo projectInfo = projectInfoMapper.selectById(projectId);
+            if (projectInfo != null && ("private").equals(projectInfo.getReferenceWbsTemplateType()) && ObjectUtils.isNotEmpty(projectInfo.getReferenceWbsTemplateId())) {
+                //构造参数集合
+                List<TextdictInfo> insertData = new ArrayList<>();
+                Map<Long, List<TextdictInfo>> textDictInfoData = new HashMap<>();
+
+                //获取当前选择的节点下的所有节点、表、独立表
+                WbsTreePrivate selectNodeNow = baseMapper.selectOne(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getPKeyId, pKeyId).eq(WbsTreePrivate::getStatus, 1));
+                if (selectNodeNow == null) {
+                    throw new ServiceException("未获取到当前选择同步的节点信息,请联系管理员");
+                }
+                List<WbsTreePrivate> wbsTreePrivatesNodeAndTabNow = this.getChildNodesAndTabs(selectNodeNow);
+
+                //当前项目独立表
+                Map<Long, WbsTreePrivate> wbsTreePrivatesTableDL = wbsTreePrivatesNodeAndTabNow.stream().filter(f -> f.getType().equals(10) && f.getParentId().equals(-10L)).collect(Collectors.toMap(WbsTreePrivate::getId, Function.identity()));
+                //当前项目选择的同步的节点信息
+                Map<Long, WbsTreePrivate> nowNodeTreeAll = wbsTreePrivatesNodeAndTabNow.stream().filter(f -> f.getType().equals(1)).collect(Collectors.toList()).stream().collect(Collectors.toMap(WbsTreePrivate::getId, WbsTreePrivate -> WbsTreePrivate, (obj1, obj2) -> obj1));
+
+                //获取当前引用的项目节点树的根节点信息
+                WbsTreePrivate oneRecordRoot = this.getOne(Wrappers.<WbsTreePrivate>lambdaQuery().select(WbsTreePrivate::getProjectId, WbsTreePrivate::getWbsId).eq(WbsTreePrivate::getPKeyId, projectInfo.getReferenceWbsTemplateId()));
+                //选择节点对应所引用的关联对应的节点、表、独立表
+                WbsTreePrivate selectOneRecord = baseMapper.selectOne(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getProjectId, oneRecordRoot.getProjectId()).eq(WbsTreePrivate::getId, selectNodeNow.getId()).eq(WbsTreePrivate::getWbsId, oneRecordRoot.getWbsId()));
+                List<WbsTreePrivate> wbsTreePrivatesNodeAndTabRecord = this.getChildNodesAndTabs(selectOneRecord);
+
+                //引用的节点树对应的节点、表、独立表
+
+                //获取当前对应电签位置配置信息
+                List<WbsTreePrivate> collect1 = wbsTreePrivatesNodeAndTabRecord.stream().filter(f -> f.getType().equals(10) || f.getType().equals(2)).collect(Collectors.toList());
+                List<Long> pKeyIds = collect1.stream().map(WbsTreePrivate::getPKeyId).collect(Collectors.toList());
 
-                    List<WbsParam> paramListOldAll = new ArrayList<>();
+                //分组查询
+                List<TextdictInfo> textDictInfosAll = new ArrayList<>();
+                List<List<Long>> partition = Lists.partition(pKeyIds, 1000);
+                for (List<Long> ids : partition) {
+                    String sql = "select id,name,type,tab_id,col_key,sig_role_id,is_deleted,sig_role_name,col_name,pyzbx,pyzby from m_textdict_info where tab_id in(" + org.apache.commons.lang.StringUtils.join(ids, ",") + ")";
+                    List<TextdictInfo> textDictInfos = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(TextdictInfo.class));
+                    textDictInfosAll.addAll(textDictInfos);
+                }
 
-                    List<Long> oldIds = paramListData.stream().map(WbsParamVO::getOldId).distinct().collect(Collectors.toList());
-                    //分组查询
-                    List<List<Long>> partition = Lists.partition(oldIds, 1000);
-                    for (List<Long> ids : partition) {
-                        String sql1 = "select id,name,k,v,node_id,remark from m_wbs_param where id in( " + org.apache.commons.lang.StringUtils.join(ids, ",") + ")";
-                        List<WbsParam> query = jdbcTemplate.query(sql1, new BeanPropertyRowMapper<>(WbsParam.class));
-                        paramListOldAll.addAll(query);
+                //构造原始电签信息
+                Map<String, List<TextdictInfo>> collect3 = textDictInfosAll.stream().collect(Collectors.groupingBy(TextdictInfo::getTabId));
+                for (WbsTreePrivate wbsTreePrivate : collect1) {
+                    if (wbsTreePrivate.getType() == 2) {
+                        WbsTreePrivate obj = nowNodeTreeAll.get(wbsTreePrivate.getParentId());
+                        if (obj != null) {
+                            List<TextdictInfo> textDictInfos = collect3.get(String.valueOf(wbsTreePrivate.getPKeyId()));
+                            if (textDictInfos != null && textDictInfos.size() > 0) {
+                                textDictInfoData.put(wbsTreePrivate.getId(), textDictInfos);
+                            }
+                        }
                     }
 
-                    //转换为map
-                    Map<Long, WbsParam> mapOld = paramListOldAll.stream().collect(Collectors.toMap(WbsParam::getId, Function.identity()));
-
-                    //获取当前项目的节点参数
-                    List<WbsParam> paramListNow = wbsParamMapper.selectList(Wrappers.<WbsParam>lambdaQuery()
-                            .select(WbsParam::getK, WbsParam::getV, WbsParam::getName, WbsParam::getId, WbsParam::getRemark, WbsParam::getNodeId)
-                            .eq(WbsParam::getProjectId, Long.parseLong(projectId)));
-
-                    //判断是否存在
-                    Iterator<WbsParamVO> iterator = paramListData.iterator();
-                    while (iterator.hasNext()) {
-                        WbsParamVO next = iterator.next();
-
-                        //获取引用的节点上的源参数信息
-                        WbsParam oldObj = mapOld.get(next.getOldId());
-                        //获取被引用的节点上的现参数信息
-                        WbsParam newObj = paramListNow.stream().filter(f -> f.getK().equals(next.getK())
-                                && f.getV().equals(next.getV())
-                                && f.getName().equals(next.getName())
-                                && f.getRemark().equals(next.getRemark())
-                                && f.getNodeId().equals(next.getNodeId())
-                        ).findAny().orElse(null);
-
-                        if (oldObj != null && newObj != null) {
-                            //如果源节点参数与现节点参数名称、K、V、备注一致,那么就跳过
-                            if (oldObj.getName().equals(newObj.getName()) && oldObj.getK().equals(newObj.getK()) && oldObj.getV().equals(newObj.getV()) && oldObj.getRemark().equals(newObj.getRemark())) {
-                                iterator.remove();
-
-                                //如果源节点参数与现节点参数名称、K一致,V、备注不一致,那么就修改当前名称下的节点参数
-                            } else if (oldObj.getName().equals(newObj.getName()) && oldObj.getK().equals(newObj.getK()) && (!oldObj.getV().equals(newObj.getV()) || !oldObj.getRemark().equals(newObj.getRemark()))) {
-                                newObj.setProjectId(Long.parseLong(projectId));
-                                newObj.setName(oldObj.getName());
-                                newObj.setK(oldObj.getK());
-                                newObj.setV(oldObj.getV());
-                                newObj.setRemark(oldObj.getRemark());
-                                newObj.setType(1);
-                                newObj.setStatus(1);
-                                newObj.setIsDeleted(0);
-                                updateList.add(newObj);
-
-                                //如果源节点参数与现节点参数名称不一致,那么新增
-                            } else if (!oldObj.getName().equals(newObj.getName())) {
-                                insertList.add(next);
+                    if (wbsTreePrivate.getType() == 10 && wbsTreePrivate.getParentId() == -10) { //type=10,parentId=-10 独立库
+                        //判断是否存在独立表单,存在则不新增
+                        WbsTreePrivate wbsTreePrivate1 = wbsTreePrivatesTableDL.get(wbsTreePrivate.getId());
+                        if (ObjectUtils.isEmpty(wbsTreePrivate1)) {
+                            //根据元素表pKeyId,获取电签位置匹配信息、编辑默认信息
+                            List<TextdictInfo> textDictInfos = collect3.get(String.valueOf(wbsTreePrivate.getPKeyId()));
+                            if (textDictInfos != null && textDictInfos.size() > 0) {
+                                textDictInfoData.put(wbsTreePrivate.getId(), textDictInfos);
                             }
+                        }
+                    }
+                }
 
-                        } else if (oldObj != null) {
-                            //二次过滤,节点名称、节点id相同,修改
-                            List<WbsParam> query = paramListNow.stream().filter(f -> f.getName().equals(next.getName())
-                                    && f.getNodeId().equals(next.getNodeId())
-                            ).collect(Collectors.toList());
-
-                            if (query.size() > 0) {
-                                for (WbsParam wbsParam : query) {
-                                    if (oldObj.getName().equals(wbsParam.getName())) {
-                                        //修改
-                                        wbsParam.setProjectId(Long.parseLong(projectId));
-                                        wbsParam.setName(next.getName());
-                                        wbsParam.setK(next.getK());
-                                        wbsParam.setV(next.getV());
-                                        wbsParam.setRemark(next.getRemark());
-                                        wbsParam.setType(1);
-                                        wbsParam.setStatus(1);
-                                        wbsParam.setIsDeleted(0);
-                                        updateList.add(wbsParam);
-                                    }
-                                }
-                            } else {
-                                //新增
-                                insertList.add(next);
+                //只同步独立库中有关联过清表的元素表type=10,以及原始方式的元素表type=2
+                List<WbsTreePrivate> collect = wbsTreePrivatesNodeAndTabNow.stream().filter(f -> f.getType().equals(2) || (f.getHtmlUrl() != null && f.getType().equals(10))).collect(Collectors.toList());
+                collect.forEach(tree -> {
+                    List<TextdictInfo> textDictInfos = textDictInfoData.get(tree.getId());
+                    if (textDictInfos != null) {
+                        for (TextdictInfo textdictInfo : textDictInfos) {
+                            TextdictInfo obj = BeanUtil.copyProperties(textdictInfo, TextdictInfo.class);
+                            if (obj != null) {
+                                obj.setId(SnowFlakeUtil.getId());
+                                obj.setTabId(tree.getPKeyId().toString()); //重新赋值绑定到对应的表上
+                                insertData.add(obj);
                             }
                         }
+                    }
+                });
 
+                //去重,删除当前表的电签信息
+                List<String> collect2 = insertData.stream().map(TextdictInfo::getTabId).collect(Collectors.toList());
+                if (!collect2.isEmpty()) {
+                    List<List<String>> partitionDel = Lists.partition(collect2, 1000);
+                    for (List<String> ids : partitionDel) {
+                        String delSql = "delete from m_textdict_info where tab_id in (" + org.apache.commons.lang.StringUtils.join(ids, ",") + ")";
+                        jdbcTemplate.execute(delSql);
                     }
                 }
-            }
 
-            if (updateList.size() > 0) {
-                this.wbsParamServiceImpl.updateBatchById(updateList, 1000);
-            }
-            if (insertList.size() > 0) {
-                List<List<WbsParam>> partition1 = Lists.partition(insertList, 1000);
-                for (List<WbsParam> addList : partition1) {
-                    wbsParamServiceImpl.insertBatch(addList, 1000);
+                //新增
+                if (!insertData.isEmpty()) {
+                    List<List<TextdictInfo>> partition1 = Lists.partition(insertData, 1000);
+                    for (List<TextdictInfo> addList : partition1) {
+                        textDictInfoService.insertBatch(addList, 1000);
+                    }
                 }
-                return true;
             }
+            return true;
+        } else {
+            throw new ServiceException("当前项目关联的wbs树不是私有关联,无法同步电签信息");
         }
-        return false;
     }
 
     @Override
@@ -823,10 +1025,8 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
             //获取当前节点对应节点信息
             WbsTreePrivate wbsTreePrivate = baseMapper.selectOne(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getPKeyId, primaryKeyId));
             //获取项目信息
-            ProjectInfo projectInfo = projectInfoMapper.selectOne(Wrappers.<ProjectInfo>lambdaQuery()
-                    .select(ProjectInfo::getReferenceWbsTemplateType, ProjectInfo::getReferenceWbsTemplateTypeTrial)
-                    .eq(ProjectInfo::getId, wbsTreePrivate.getProjectId()));
-
+            ProjectInfo projectInfo = projectInfoMapper.selectOne(Wrappers.<ProjectInfo>lambdaQuery().select(ProjectInfo::getReferenceWbsTemplateType, ProjectInfo::getReferenceWbsTemplateTypeTrial).eq(ProjectInfo::getId, wbsTreePrivate.getProjectId()));
+            //结果集
             List<WbsTreePrivate> insertDataPrivateList = new ArrayList<>();
 
             if (("1").equals(wbsTreePrivate.getWbsType())) {
@@ -837,16 +1037,22 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
                     List<WbsTree> wbsTreesPublicTables;
                     if (wbsTree.getAncestors().equals("0")) {
                         //根节点
-                        wbsTreesPublicTables = wbsTreeMapper.selectList(Wrappers.<WbsTree>query().lambda().eq(WbsTree::getWbsId, wbsTree.getWbsId()).eq(WbsTree::getType, 2).eq(WbsTree::getStatus, 1));
+                        wbsTreesPublicTables = wbsTreeMapper.selectList(Wrappers.<WbsTree>query().lambda().eq(WbsTree::getWbsId, wbsTree.getWbsId()).eq(WbsTree::getType, 2)
+                                /*.eq(WbsTree::getStatus,1)*/
+                        );
                     } else {
-                        wbsTreesPublicTables = wbsTreeMapper.selectList(Wrappers.<WbsTree>query().lambda().eq(WbsTree::getWbsId, wbsTree.getWbsId()).eq(WbsTree::getType, 2).eq(WbsTree::getStatus, 1).like(WbsTree::getAncestors, wbsTree.getId()));
+                        wbsTreesPublicTables = wbsTreeMapper.selectList(Wrappers.<WbsTree>query().lambda().eq(WbsTree::getWbsId, wbsTree.getWbsId()).eq(WbsTree::getType, 2)
+                                /*.eq(WbsTree::getStatus,1)*/
+                                .like(WbsTree::getAncestors, wbsTree.getId())
+                        );
                     }
 
                     //获取当前项目树下的元素表 节点
                     List<WbsTreePrivate> wbsTreePrivatesProjectAll = baseMapper.selectList(Wrappers.<WbsTreePrivate>query().lambda()
-                            .eq(WbsTreePrivate::getProjectId, wbsTreePrivate.getProjectId())
-                            .eq(WbsTreePrivate::getWbsId, wbsTreePrivate.getWbsId())
-                            .eq(WbsTreePrivate::getStatus, 1));
+                                    .eq(WbsTreePrivate::getProjectId, wbsTreePrivate.getProjectId())
+                                    .eq(WbsTreePrivate::getWbsId, wbsTreePrivate.getWbsId())
+                            /*.eq(WbsTreePrivate::getStatus, 1)*/
+                    );
                     List<WbsTreePrivate> wbsTreePrivatesProjectNodes = wbsTreePrivatesProjectAll.stream().filter(f -> f.getType().equals(1)).collect(Collectors.toList());
 
                     List<WbsTreePrivate> wbsTreePrivatesProjectTables;
@@ -890,13 +1096,20 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
                     List<WbsTreePrivate> wbsTreePrivateRootTables;
                     if (wbsTreePrivate.getAncestors().equals("0")) {
                         //根节点
-                        wbsTreePrivateRootTables = baseMapper.selectList(Wrappers.<WbsTreePrivate>query().lambda().eq(WbsTreePrivate::getProjectId, wbsTreePrivateRoot.getProjectId()).eq(WbsTreePrivate::getWbsId, wbsTreePrivateRoot.getWbsId()).eq(WbsTreePrivate::getType, 2).eq(WbsTreePrivate::getStatus, 1));
+                        wbsTreePrivateRootTables = baseMapper.selectList(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getProjectId, wbsTreePrivateRoot.getProjectId()).eq(WbsTreePrivate::getWbsId, wbsTreePrivateRoot.getWbsId()).eq(WbsTreePrivate::getType, 2)
+                                /*.eq(WbsTreePrivate::getStatus, 1)*/
+                        );
                     } else {
-                        wbsTreePrivateRootTables = baseMapper.selectList(Wrappers.<WbsTreePrivate>query().lambda().eq(WbsTreePrivate::getProjectId, wbsTreePrivateRoot.getProjectId()).eq(WbsTreePrivate::getWbsId, wbsTreePrivateRoot.getWbsId()).eq(WbsTreePrivate::getType, 2).eq(WbsTreePrivate::getStatus, 1).like(WbsTreePrivate::getAncestors, wbsTreePrivate.getId()));
+                        wbsTreePrivateRootTables = baseMapper.selectList(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getProjectId, wbsTreePrivateRoot.getProjectId())
+                                .eq(WbsTreePrivate::getWbsId, wbsTreePrivateRoot.getWbsId()).eq(WbsTreePrivate::getType, 2)
+                                /*.eq(WbsTreePrivate::getStatus, 1)*/
+                                .like(WbsTreePrivate::getAncestors, wbsTreePrivate.getId()));
                     }
 
                     //获取当前项目选择的节点下的所有元素表 节点
-                    List<WbsTreePrivate> wbsTreePrivatesProjectAll = baseMapper.selectList(Wrappers.<WbsTreePrivate>query().lambda().eq(WbsTreePrivate::getProjectId, wbsTreePrivate.getProjectId()).eq(WbsTreePrivate::getWbsId, wbsTreePrivate.getWbsId()).eq(WbsTreePrivate::getStatus, 1));
+                    List<WbsTreePrivate> wbsTreePrivatesProjectAll = baseMapper.selectList(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getProjectId, wbsTreePrivate.getProjectId()).eq(WbsTreePrivate::getWbsId, wbsTreePrivate.getWbsId())
+                            /*.eq(WbsTreePrivate::getStatus, 1)*/
+                    );
 
                     List<WbsTreePrivate> wbsTreePrivatesProjectNodes = wbsTreePrivatesProjectAll.stream().filter(f -> f.getType().equals(1)).collect(Collectors.toList());
                     List<WbsTreePrivate> wbsTreePrivatesProjectTables;
@@ -933,17 +1146,24 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
                 if (("public").equals(projectInfo.getReferenceWbsTemplateTypeTrial())) {
                     /*TODO-------------------------------------试验公有引用同步--------------------------------------------*/
                     //获取当前节点对应的公有引用树下的元素表
-                    WbsTree wbsTree = wbsTreeMapper.selectOne(Wrappers.<WbsTree>query().lambda().eq(WbsTree::getId, wbsTreePrivate.getId()));
+                    WbsTree wbsTree = wbsTreeMapper.selectOne(Wrappers.<WbsTree>lambdaQuery().eq(WbsTree::getId, wbsTreePrivate.getId()));
                     List<WbsTree> wbsTreesPublicTables;
                     if (wbsTree.getAncestors().equals("0")) {
                         //根节点
-                        wbsTreesPublicTables = wbsTreeMapper.selectList(Wrappers.<WbsTree>query().lambda().eq(WbsTree::getWbsId, wbsTree.getWbsId()).eq(WbsTree::getType, 2).eq(WbsTree::getStatus, 1));
+                        wbsTreesPublicTables = wbsTreeMapper.selectList(Wrappers.<WbsTree>lambdaQuery().eq(WbsTree::getWbsId, wbsTree.getWbsId()).eq(WbsTree::getType, 2)
+                                /*.eq(WbsTree::getStatus, 1)*/
+                        );
                     } else {
-                        wbsTreesPublicTables = wbsTreeMapper.selectList(Wrappers.<WbsTree>query().lambda().eq(WbsTree::getWbsId, wbsTree.getWbsId()).eq(WbsTree::getType, 2).eq(WbsTree::getStatus, 1).like(WbsTree::getAncestors, wbsTree.getId()));
+                        wbsTreesPublicTables = wbsTreeMapper.selectList(Wrappers.<WbsTree>lambdaQuery().eq(WbsTree::getWbsId, wbsTree.getWbsId())
+                                .eq(WbsTree::getType, 2)
+                                /*.eq(WbsTree::getStatus, 1)*/
+                                .like(WbsTree::getAncestors, wbsTree.getId()));
                     }
 
                     //获取当前项目树下的元素表 节点
-                    List<WbsTreePrivate> wbsTreePrivatesProjectAll = baseMapper.selectList(Wrappers.<WbsTreePrivate>query().lambda().eq(WbsTreePrivate::getProjectId, wbsTreePrivate.getProjectId()).eq(WbsTreePrivate::getWbsId, wbsTreePrivate.getWbsId()).eq(WbsTreePrivate::getStatus, 1));
+                    List<WbsTreePrivate> wbsTreePrivatesProjectAll = baseMapper.selectList(Wrappers.<WbsTreePrivate>query().lambda().eq(WbsTreePrivate::getProjectId, wbsTreePrivate.getProjectId()).eq(WbsTreePrivate::getWbsId, wbsTreePrivate.getWbsId())
+                            /*.eq(WbsTreePrivate::getStatus, 1)*/
+                    );
                     List<WbsTreePrivate> wbsTreePrivatesProjectNodes = wbsTreePrivatesProjectAll.stream().filter(f -> f.getType().equals(1)).collect(Collectors.toList());
 
                     List<WbsTreePrivate> wbsTreePrivatesProjectTables;
@@ -980,18 +1200,26 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
                 } else if (("private").equals(projectInfo.getReferenceWbsTemplateTypeTrial())) {
                     /*TODO-------------------------------------试验私有引用同步--------------------------------------------*/
                     //根据wbsTreePrivate的wbsId=私有引用的pKeyId来获取引用树根节点
-                    WbsTreePrivate wbsTreePrivateRoot = baseMapper.selectOne(Wrappers.<WbsTreePrivate>query().lambda().eq(WbsTreePrivate::getPKeyId, wbsTreePrivate.getWbsId()));
+                    WbsTreePrivate wbsTreePrivateRoot = baseMapper.selectOne(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getPKeyId, wbsTreePrivate.getWbsId()));
                     //获取当前私有引用树的元素表信息
                     List<WbsTreePrivate> wbsTreePrivateRootTables;
                     if (wbsTreePrivate.getAncestors().equals("0")) {
                         //根节点
-                        wbsTreePrivateRootTables = baseMapper.selectList(Wrappers.<WbsTreePrivate>query().lambda().eq(WbsTreePrivate::getProjectId, wbsTreePrivateRoot.getProjectId()).eq(WbsTreePrivate::getWbsId, wbsTreePrivateRoot.getWbsId()).eq(WbsTreePrivate::getType, 2).eq(WbsTreePrivate::getStatus, 1));
+                        wbsTreePrivateRootTables = baseMapper.selectList(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getProjectId, wbsTreePrivateRoot.getProjectId())
+                                        .eq(WbsTreePrivate::getWbsId, wbsTreePrivateRoot.getWbsId()).eq(WbsTreePrivate::getType, 2)
+                                /*.eq(WbsTreePrivate::getStatus, 1)*/
+                        );
                     } else {
-                        wbsTreePrivateRootTables = baseMapper.selectList(Wrappers.<WbsTreePrivate>query().lambda().eq(WbsTreePrivate::getProjectId, wbsTreePrivateRoot.getProjectId()).eq(WbsTreePrivate::getWbsId, wbsTreePrivateRoot.getWbsId()).eq(WbsTreePrivate::getType, 2).eq(WbsTreePrivate::getStatus, 1).like(WbsTreePrivate::getAncestors, wbsTreePrivate.getId()));
+                        wbsTreePrivateRootTables = baseMapper.selectList(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getProjectId, wbsTreePrivateRoot.getProjectId())
+                                .eq(WbsTreePrivate::getWbsId, wbsTreePrivateRoot.getWbsId()).eq(WbsTreePrivate::getType, 2)
+                                /*.eq(WbsTreePrivate::getStatus, 1)*/
+                                .like(WbsTreePrivate::getAncestors, wbsTreePrivate.getId()));
                     }
 
                     //获取当前项目选择的节点下的所有元素表 节点
-                    List<WbsTreePrivate> wbsTreePrivatesProjectAll = baseMapper.selectList(Wrappers.<WbsTreePrivate>query().lambda().eq(WbsTreePrivate::getProjectId, wbsTreePrivate.getProjectId()).eq(WbsTreePrivate::getWbsId, wbsTreePrivate.getWbsId()).eq(WbsTreePrivate::getStatus, 1));
+                    List<WbsTreePrivate> wbsTreePrivatesProjectAll = baseMapper.selectList(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getProjectId, wbsTreePrivate.getProjectId()).eq(WbsTreePrivate::getWbsId, wbsTreePrivate.getWbsId())
+                            /*.eq(WbsTreePrivate::getStatus, 1)*/
+                    );
 
                     List<WbsTreePrivate> wbsTreePrivatesProjectNodes = wbsTreePrivatesProjectAll.stream().filter(f -> f.getType().equals(1)).collect(Collectors.toList());
                     List<WbsTreePrivate> wbsTreePrivatesProjectTables;
@@ -1025,115 +1253,17 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
                     }
                 }
             }
-            //新增
-            if (insertDataPrivateList.size() > 0) {
-                this.insertBatch(insertDataPrivateList, 1000);
-            }
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public boolean syncProjectEVisa(String projectId) {
-        if (StringUtils.isNotEmpty(projectId)) {
-            ProjectInfo projectInfo = projectInfoMapper.selectById(projectId);
-            if (projectInfo != null && ("private").equals(projectInfo.getReferenceWbsTemplateType()) && ObjectUtils.isNotEmpty(projectInfo.getReferenceWbsTemplateId())) {
-                //构造参数集合
-                List<TextdictInfo> insertData = new ArrayList<>();
-                Map<Long, List<TextdictInfo>> textDictInfoData = new HashMap<>();
 
-                //获取当前引用的项目节点树的根节点信息
-                WbsTreePrivate oneRecordRoot = this.getOne(Wrappers.<WbsTreePrivate>lambdaQuery().select(WbsTreePrivate::getProjectId, WbsTreePrivate::getWbsId).eq(WbsTreePrivate::getPKeyId, projectInfo.getReferenceWbsTemplateId()));
-
-                //获取当前项目下节点树所有节点、表、独立表
-                String sqlNodeTreeAllNow = "SELECT p_key_id,id,type,parent_id,html_url FROM m_wbs_tree_private WHERE project_id = " + projectId + " AND STATUS = 1 AND is_deleted = 0 AND (((type = 1 OR type = 2) AND wbs_type = 1) OR (type= 10 AND parent_id = -10 ))";
-                List<WbsTreePrivate> wbsTreePrivatesNodeAndTabNow = jdbcTemplate.query(sqlNodeTreeAllNow, new BeanPropertyRowMapper<>(WbsTreePrivate.class));
-                Map<Long, WbsTreePrivate> wbsTreePrivatesTableDL = wbsTreePrivatesNodeAndTabNow.stream().filter(f -> f.getType().equals(10) && f.getParentId().equals(-10L)).collect(Collectors.toMap(WbsTreePrivate::getId, Function.identity()));
-
-                //获取当前项目节点树
-                Map<Long, WbsTreePrivate> nowNodeTreeAll = wbsTreePrivatesNodeAndTabNow.stream().filter(f -> f.getType().equals(1)).collect(Collectors.toList()).stream()
-                        .collect(Collectors.toMap(WbsTreePrivate::getId, WbsTreePrivate -> WbsTreePrivate, (obj1, obj2) -> obj1));
-
-                //获取当前引用的节点树下所有节点、表、独立表
-                String sqlNodeTreeAllOld = "SELECT p_key_id,id,type,parent_id FROM m_wbs_tree_private WHERE project_id = " + oneRecordRoot.getProjectId() + " AND STATUS = 1 AND is_deleted = 0 AND (((type = 1 OR type = 2) AND wbs_id = " + oneRecordRoot.getWbsId() + ") OR ((type= 10 OR parent_id = -10 ) AND wbs_id IS NULL))";
-                List<WbsTreePrivate> wbsTreePrivatesNodeAndTab = jdbcTemplate.query(sqlNodeTreeAllOld, new BeanPropertyRowMapper<>(WbsTreePrivate.class));
-
-                //获取当前对应电签位置配置信息
-                List<WbsTreePrivate> collect1 = wbsTreePrivatesNodeAndTab.stream().filter(f -> f.getType().equals(10) || f.getType().equals(2)).collect(Collectors.toList());
-                List<Long> pKeyIds = collect1.stream().map(WbsTreePrivate::getPKeyId).collect(Collectors.toList());
-
-                //分组查询
-                List<TextdictInfo> textDictInfosAll = new ArrayList<>();
-                List<List<Long>> partition = Lists.partition(pKeyIds, 1000);
-                for (List<Long> ids : partition) {
-                    String sql = "select id,name,type,tab_id,col_key,sig_role_id,is_deleted,sig_role_name,col_name,pyzbx,pyzby from m_textdict_info where tab_id in(" + org.apache.commons.lang.StringUtils.join(ids, ",") + ")";
-                    List<TextdictInfo> textDictInfos = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(TextdictInfo.class));
-                    textDictInfosAll.addAll(textDictInfos);
-                }
-
-                //转换map
-                Map<String, List<TextdictInfo>> collect3 = textDictInfosAll.stream().collect(Collectors.groupingBy(TextdictInfo::getTabId));
-
-                //构造原始电签信息
-                for (WbsTreePrivate wbsTreePrivate : collect1) {
-                    if (wbsTreePrivate.getType() == 2) {
-                        WbsTreePrivate obj = nowNodeTreeAll.get(wbsTreePrivate.getParentId());
-                        if (obj != null) {
-                            List<TextdictInfo> textDictInfos = collect3.get(String.valueOf(wbsTreePrivate.getPKeyId()));
-                            if (textDictInfos != null && textDictInfos.size() > 0) {
-                                textDictInfoData.put(wbsTreePrivate.getId(), textDictInfos);
-                            }
-                        }
-                    }
-
-                    if (wbsTreePrivate.getType() == 10 && wbsTreePrivate.getParentId() == -10) { //type=10,parentId=-10 独立库
-                        //判断是否存在独立表单,存在则不新增
-                        WbsTreePrivate wbsTreePrivate1 = wbsTreePrivatesTableDL.get(wbsTreePrivate.getId());
-                        if (ObjectUtils.isEmpty(wbsTreePrivate1)) {
-                            //根据元素表pKeyId,获取电签位置匹配信息、编辑默认信息
-                            List<TextdictInfo> textDictInfos = collect3.get(String.valueOf(wbsTreePrivate.getPKeyId()));
-                            if (textDictInfos != null && textDictInfos.size() > 0) {
-                                textDictInfoData.put(wbsTreePrivate.getId(), textDictInfos);
-                            }
-                        }
-                    }
-                }
-
-                //只同步独立库中有关联过清表的元素表type=10,以及原始方式的元素表type=2
-                List<WbsTreePrivate> collect = wbsTreePrivatesNodeAndTabNow.stream().filter(f -> f.getType().equals(2) || (f.getHtmlUrl() != null && f.getType().equals(10))).collect(Collectors.toList());
-
-                collect.forEach(tree -> {
-                    List<TextdictInfo> textDictInfos = textDictInfoData.get(tree.getId());
-                    if (textDictInfos != null) {
-                        for (TextdictInfo textdictInfo : textDictInfos) {
-                            TextdictInfo obj = BeanUtil.copyProperties(textdictInfo, TextdictInfo.class);
-                            if (obj != null) {
-                                obj.setId(SnowFlakeUtil.getId());
-                                obj.setTabId(tree.getPKeyId().toString()); //重新赋值绑定到对应的表上
-                                insertData.add(obj);
-                            }
-                        }
-                    }
-                });
-
-                //去重,删除当前表的电签信息
-                List<String> collect2 = insertData.stream().map(TextdictInfo::getTabId).collect(Collectors.toList());
-                List<List<String>> partitionDel = Lists.partition(collect2, 1000);
-                for (List<String> ids : partitionDel) {
-                    String delSql = "delete from m_textdict_info where tab_id in (" + org.apache.commons.lang.StringUtils.join(ids, ",") + ")";
-                    jdbcTemplate.execute(delSql);
-                }
-
-                List<List<TextdictInfo>> partition1 = Lists.partition(insertData, 1000);
-                for (List<TextdictInfo> addList : partition1) {
-                    textDictInfoService.insertBatch(addList, 1000);
+            //新增
+            if (!insertDataPrivateList.isEmpty()) {
+                List<List<WbsTreePrivate>> partition = Lists.partition(insertDataPrivateList, 1000);
+                for (List<WbsTreePrivate> wbsTreePrivates : partition) {
+                    this.insertBatch(wbsTreePrivates, 1000);
                 }
             }
             return true;
-        } else {
-            throw new ServiceException("当前项目关联的wbs树不是私有关联");
         }
+        return false;
     }
 
     @Override

+ 142 - 75
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeServiceImpl.java

@@ -320,97 +320,165 @@ public class WbsTreeServiceImpl extends BaseServiceImpl<WbsTreeMapper, WbsTree>
         WbsTreePrivate wbsTreePrivate = wbsTreePrivateService.getBaseMapper().selectOne(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getPKeyId, pKeyId).eq(WbsTreePrivate::getStatus, 1));
 
         //获取当前项目引用
-        String sql = "select reference_wbs_template_id,reference_wbs_template_type,reference_wbs_template_id_trial,reference_wbs_template_type_trial from m_project_info where id = " + wbsTreePrivate.getProjectId();
+        String sql = "select reference_wbs_template_id,reference_wbs_template_type,reference_wbs_template_id_trial,reference_wbs_template_type_trial from m_project_info where is_deleted = 0 and id = " + wbsTreePrivate.getProjectId();
         ProjectInfo projectInfo = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(ProjectInfo.class)).stream().findAny().orElse(null);
         if (projectInfo != null) {
             if (("1").equals(wbsTreePrivate.getWbsType())) {
-                //质检公有
+                //TODO =====质检公有=====
                 if (ObjectUtil.isNotEmpty(projectInfo.getReferenceWbsTemplateId()) && (ObjectUtil.isNotEmpty(projectInfo.getReferenceWbsTemplateType()) && ("public").equals(projectInfo.getReferenceWbsTemplateType()))) {
-                    //获取公有树
-                    List<WbsTree> wbsTreeListAll = wbsTreeMapper.selectList(Wrappers.<WbsTree>lambdaQuery()
-                            .select(WbsTree::getId, WbsTree::getNodeName, WbsTree::getNodeType, WbsTree::getMajorDataType,
-                                    WbsTree::getTableType, WbsTree::getTableOwner, WbsTree::getImportMatchingInfo,
-                                    WbsTree::getMixRatioTestIds, WbsTree::getInitTableId,
-                                    WbsTree::getInitTableName, WbsTree::getSort)
-                            .eq(WbsTree::getWbsId, projectInfo.getReferenceWbsTemplateId()).eq(WbsTree::getType, 1).eq(WbsTree::getStatus, 1));
-                    //获取项目私节点、元素表
-                    List<WbsTreePrivate> wbsTreePrivatesAll = wbsTreePrivateMapper.selectList(Wrappers.<WbsTreePrivate>lambdaQuery()
-                            .select(WbsTreePrivate::getId, WbsTreePrivate::getNodeName, WbsTreePrivate::getNodeType, WbsTreePrivate::getMajorDataType,
-                                    WbsTreePrivate::getTableType, WbsTreePrivate::getTableOwner, WbsTreePrivate::getImportMatchingInfo,
-                                    WbsTreePrivate::getMixRatioTestIds, WbsTreePrivate::getInitTableId,
-                                    WbsTreePrivate::getInitTableName, WbsTreePrivate::getHtmlUrl, WbsTreePrivate::getSort)
-                            .eq(WbsTreePrivate::getWbsId, projectInfo.getReferenceWbsTemplateId()).eq(WbsTreePrivate::getProjectId, wbsTreePrivate.getProjectId()).eq(WbsTreePrivate::getStatus, 1));
-                    //同步修改
-                    this.updateWbsInfoPrivateAsync(wbsTreeListAll, wbsTreePrivatesAll, wbsTreePrivate.getProjectId(), Integer.parseInt(wbsTreePrivate.getWbsType()));
-
-                    //质检私有
+                    //获取引用的公有树节点信息,没有元素表
+                    WbsTree wbsTree = wbsTreeMapper.selectOne(Wrappers.<WbsTree>lambdaQuery().eq(WbsTree::getId, wbsTreePrivate.getId()).eq(WbsTree::getStatus, 1));
+                    List<WbsTree> childNodesAllPublic = this.getChildNodes(wbsTree);
+                    if (childNodesAllPublic == null) {
+                        childNodesAllPublic = new ArrayList<>();
+                    }
+                    childNodesAllPublic.add(wbsTree);
+
+                    //获取当前项目私节点、元素表
+                    List<WbsTreePrivate> childNodesAllNowProject = this.getChildNodesAllNowProject(wbsTreePrivate);
+                    //公有引用,由于没有关联清表,html_url不存在,所以不同步表的html_url信息
+                    List<WbsTreePrivate> childNodesAllNowProjectNodes = childNodesAllNowProject.stream().filter(f -> new Integer(1).equals(f.getType())).collect(Collectors.toList());
+
+                    //修改公有引用信息
+                    this.asyncUpdateWbsPublic(childNodesAllPublic, childNodesAllNowProjectNodes, wbsTreePrivate.getProjectId(), Integer.parseInt(wbsTreePrivate.getWbsType()));
+
                 } else if (ObjectUtil.isNotEmpty(projectInfo.getReferenceWbsTemplateId()) && ObjectUtil.isNotEmpty(projectInfo.getReferenceWbsTemplateType()) && ("private").equals(projectInfo.getReferenceWbsTemplateType())) {
+                    //TODO =====质检私有=====
                     //获取私有引用根节点
-                    WbsTreePrivate wbsTreePrivateRecord = wbsTreePrivateMapper.selectOne(Wrappers.<WbsTreePrivate>query().lambda()
-                            .select(WbsTreePrivate::getProjectId, WbsTreePrivate::getWbsId)
-                            .eq(WbsTreePrivate::getPKeyId, projectInfo.getReferenceWbsTemplateId()));
-                    //获取私有引用项目树
-                    List<WbsTreePrivate> wbsTreePrivateAllOld = wbsTreePrivateMapper.selectList(Wrappers.<WbsTreePrivate>query().lambda()
-                            .select(WbsTreePrivate::getId, WbsTreePrivate::getNodeName, WbsTreePrivate::getNodeType, WbsTreePrivate::getMajorDataType,
-                                    WbsTreePrivate::getTableType, WbsTreePrivate::getTableOwner, WbsTreePrivate::getImportMatchingInfo,
-                                    WbsTreePrivate::getMixRatioTestIds, WbsTreePrivate::getInitTableId,
-                                    WbsTreePrivate::getInitTableName, WbsTreePrivate::getHtmlUrl, WbsTreePrivate::getSort)
-                            .eq(WbsTreePrivate::getStatus, 1)
-                            .eq(WbsTreePrivate::getProjectId, Long.parseLong(wbsTreePrivateRecord.getProjectId()))
-                            .and(obj -> obj.eq(WbsTreePrivate::getWbsId, Long.parseLong(wbsTreePrivateRecord.getWbsId())).or().isNull(WbsTreePrivate::getWbsId))
-                    );
-                    //获取当前项目私有树、元素表
-                    List<WbsTreePrivate> wbsTreePrivatesAllNow = wbsTreePrivateMapper.selectList(Wrappers.<WbsTreePrivate>query().lambda()
-                            .select(WbsTreePrivate::getId, WbsTreePrivate::getNodeName, WbsTreePrivate::getNodeType, WbsTreePrivate::getMajorDataType,
-                                    WbsTreePrivate::getTableType, WbsTreePrivate::getTableOwner, WbsTreePrivate::getImportMatchingInfo,
-                                    WbsTreePrivate::getMixRatioTestIds, WbsTreePrivate::getInitTableId,
-                                    WbsTreePrivate::getInitTableName, WbsTreePrivate::getHtmlUrl, WbsTreePrivate::getSort)
-                            .eq(WbsTreePrivate::getStatus, 1)
-                            .eq(WbsTreePrivate::getProjectId, Long.parseLong(wbsTreePrivate.getProjectId()))
-                            .and(obj -> obj.eq(WbsTreePrivate::getWbsId, projectInfo.getReferenceWbsTemplateId()).or().isNull(WbsTreePrivate::getWbsId))
-                    );
-                    //同步修改
-                    this.updateWbsInfoContractAsync(wbsTreePrivateAllOld, wbsTreePrivatesAllNow, wbsTreePrivate.getProjectId(), projectInfo.getReferenceWbsTemplateId().toString(), Integer.parseInt(wbsTreePrivate.getWbsType()));
+                    WbsTreePrivate wbsTreePrivateRecord = wbsTreePrivateMapper.selectOne(Wrappers.<WbsTreePrivate>query().lambda().select(WbsTreePrivate::getProjectId, WbsTreePrivate::getWbsId).eq(WbsTreePrivate::getPKeyId, projectInfo.getReferenceWbsTemplateId()));
+
+                    //引用模板的对应节点
+                    WbsTreePrivate recordSelectNode = wbsTreePrivateMapper.selectOne(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getId, wbsTreePrivate.getId()).eq(WbsTreePrivate::getProjectId, wbsTreePrivateRecord.getProjectId()).eq(WbsTreePrivate::getWbsId, wbsTreePrivateRecord.getWbsId()));
+                    //关联项目的对应节点的所有子级
+                    List<WbsTreePrivate> childNodesAllRecordProject = this.getChildNodes(recordSelectNode);
+                    if (childNodesAllRecordProject == null) {
+                        childNodesAllRecordProject = new ArrayList<>();
+                    }
+                    childNodesAllRecordProject.add(recordSelectNode);
+
+                    //获取当前项目私节点、元素表
+                    List<WbsTreePrivate> childNodesAllNowProject = this.getChildNodesAllNowProject(wbsTreePrivate);
+
+                    //修改私有引用信息
+                    this.asyncUpdateWbsPrivate(childNodesAllRecordProject, childNodesAllNowProject, wbsTreePrivate.getProjectId(), projectInfo.getReferenceWbsTemplateId().toString(), Integer.parseInt(wbsTreePrivate.getWbsType()));
                 }
 
             } else if (("2").equals(wbsTreePrivate.getWbsType())) {
-                //试验公有
+                //TODO =====试验公有=====
                 if (ObjectUtil.isNotEmpty(projectInfo.getReferenceWbsTemplateIdTrial()) && (ObjectUtil.isNotEmpty(projectInfo.getReferenceWbsTemplateTypeTrial()) && ("public").equals(projectInfo.getReferenceWbsTemplateTypeTrial()))) {
+                    //获取引用的公有树节点信息,没有元素表
+                    WbsTree wbsTree = wbsTreeMapper.selectOne(Wrappers.<WbsTree>lambdaQuery().eq(WbsTree::getId, wbsTreePrivate.getId()).eq(WbsTree::getWbsId, projectInfo.getReferenceWbsTemplateIdTrial()).eq(WbsTree::getStatus, 1));
+                    List<WbsTree> childNodesAllPublic = this.getChildNodes(wbsTree);
+                    if (childNodesAllPublic == null) {
+                        childNodesAllPublic = new ArrayList<>();
+                    }
+                    childNodesAllPublic.add(wbsTree);
 
-                    List<WbsTree> wbsTreeListAll = wbsTreeMapper.selectList(Wrappers.<WbsTree>lambdaQuery().eq(WbsTree::getWbsId, projectInfo.getReferenceWbsTemplateId()).eq(WbsTree::getType, 1).eq(WbsTree::getStatus, 1));
-
-                    List<WbsTreePrivate> wbsTreePrivatesAll = wbsTreePrivateMapper.selectList(Wrappers.<WbsTreePrivate>query().lambda().eq(WbsTreePrivate::getWbsId, projectInfo.getReferenceWbsTemplateId()).eq(WbsTreePrivate::getProjectId, wbsTreePrivate.getProjectId()).eq(WbsTreePrivate::getStatus, 1));
+                    //获取当前项目私节点、元素表
+                    List<WbsTreePrivate> childNodesAllNowProject = this.getChildNodesAllNowProject(wbsTreePrivate);
+                    //公有引用,由于没有关联清表,html_url不存在,所以不同步表的html_url信息
+                    List<WbsTreePrivate> childNodesAllNowProjectNodes = childNodesAllNowProject.stream().filter(f -> new Integer(1).equals(f.getType())).collect(Collectors.toList());
 
-                    this.updateWbsInfoPrivateAsync(wbsTreeListAll, wbsTreePrivatesAll, wbsTreePrivate.getProjectId(), Integer.parseInt(wbsTreePrivate.getWbsType()));
+                    this.asyncUpdateWbsPublic(childNodesAllPublic, childNodesAllNowProjectNodes, wbsTreePrivate.getProjectId(), Integer.parseInt(wbsTreePrivate.getWbsType()));
 
-                    //试验私有
                 } else if (ObjectUtil.isNotEmpty(projectInfo.getReferenceWbsTemplateIdTrial()) && (ObjectUtil.isNotEmpty(projectInfo.getReferenceWbsTemplateTypeTrial()) && ("private").equals(projectInfo.getReferenceWbsTemplateTypeTrial()))) {
+                    //TODO =====试验私有=====
+                    //私有引用试验根节点
+                    WbsTreePrivate wbsTreePrivateRecord = wbsTreePrivateMapper.selectOne(Wrappers.<WbsTreePrivate>query().lambda().select(WbsTreePrivate::getProjectId, WbsTreePrivate::getWbsId).eq(WbsTreePrivate::getPKeyId, projectInfo.getReferenceWbsTemplateIdTrial()).eq(WbsTreePrivate::getStatus, 1));
+                    //引用模板的对应节点
+                    WbsTreePrivate recordSelectNode = wbsTreePrivateMapper.selectOne(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getId, wbsTreePrivate.getId()).eq(WbsTreePrivate::getProjectId, wbsTreePrivateRecord.getProjectId()).eq(WbsTreePrivate::getWbsId, wbsTreePrivateRecord.getWbsId()));
+                    //关联项目的对应节点的所有子级
+                    List<WbsTreePrivate> childNodesAllRecordProject = this.getChildNodes(recordSelectNode);
+                    if (childNodesAllRecordProject == null) {
+                        childNodesAllRecordProject = new ArrayList<>();
+                    }
+                    childNodesAllRecordProject.add(recordSelectNode);
 
-                    WbsTreePrivate wbsTreePrivateRecord = wbsTreePrivateMapper.selectOne(Wrappers.<WbsTreePrivate>query().lambda()
-                            .select(WbsTreePrivate::getProjectId, WbsTreePrivate::getWbsId)
-                            .eq(WbsTreePrivate::getPKeyId, projectInfo.getReferenceWbsTemplateIdTrial()));
-
-                    List<WbsTreePrivate> wbsTreePrivateAllOld = wbsTreePrivateMapper.selectList(Wrappers.<WbsTreePrivate>query().lambda()
-                            .select(WbsTreePrivate::getId, WbsTreePrivate::getNodeName, WbsTreePrivate::getNodeType, WbsTreePrivate::getMajorDataType, WbsTreePrivate::getTableType, WbsTreePrivate::getTableOwner, WbsTreePrivate::getImportMatchingInfo, WbsTreePrivate::getMixRatioTestIds, WbsTreePrivate::getInitTableId, WbsTreePrivate::getInitTableName, WbsTreePrivate::getHtmlUrl)
-                            .eq(WbsTreePrivate::getStatus, 1)
-                            .eq(WbsTreePrivate::getProjectId, Long.parseLong(wbsTreePrivate.getProjectId()))
-                            .and(obj -> obj.eq(WbsTreePrivate::getWbsId, Long.parseLong(wbsTreePrivateRecord.getWbsId())).or().isNull(WbsTreePrivate::getWbsId))
-                    );
-
-                    List<WbsTreePrivate> wbsTreePrivatesAllNow = wbsTreePrivateMapper.selectList(Wrappers.<WbsTreePrivate>query().lambda()
-                            .select(WbsTreePrivate::getId, WbsTreePrivate::getNodeName, WbsTreePrivate::getNodeType, WbsTreePrivate::getMajorDataType, WbsTreePrivate::getTableType, WbsTreePrivate::getTableOwner, WbsTreePrivate::getImportMatchingInfo, WbsTreePrivate::getMixRatioTestIds, WbsTreePrivate::getInitTableId, WbsTreePrivate::getInitTableName, WbsTreePrivate::getHtmlUrl)
-                            .eq(WbsTreePrivate::getStatus, 1)
-                            .eq(WbsTreePrivate::getProjectId, Long.parseLong(wbsTreePrivate.getProjectId()))
-                            .and(obj -> obj.eq(WbsTreePrivate::getWbsId, projectInfo.getReferenceWbsTemplateIdTrial()).or().isNull(WbsTreePrivate::getWbsId))
-                    );
-
-                    this.updateWbsInfoContractAsync(wbsTreePrivateAllOld, wbsTreePrivatesAllNow, wbsTreePrivate.getProjectId(), projectInfo.getReferenceWbsTemplateIdTrial().toString(), Integer.parseInt(wbsTreePrivate.getWbsType()));
+                    //获取当前项目私节点、元素表
+                    List<WbsTreePrivate> childNodesAllNowProject = this.getChildNodesAllNowProject(wbsTreePrivate);
+
+                    this.asyncUpdateWbsPrivate(childNodesAllRecordProject, childNodesAllNowProject, wbsTreePrivate.getProjectId(), projectInfo.getReferenceWbsTemplateIdTrial().toString(), Integer.parseInt(wbsTreePrivate.getWbsType()));
                 }
             }
         }
         return true;
     }
 
+    private List<WbsTreePrivate> getChildNodesAllNowProject(WbsTreePrivate obj) {
+        List<WbsTreePrivate> childNodesAllNowProject = this.getChildNodes(obj);
+        if (childNodesAllNowProject == null) {
+            childNodesAllNowProject = new ArrayList<>();
+        }
+        childNodesAllNowProject.add(obj);
+        return childNodesAllNowProject;
+    }
+
+    /**
+     * 获取所有子级节点-私有项目引用
+     */
+    private List<WbsTreePrivate> getChildNodes(WbsTreePrivate obj) {
+        if (obj != null) {
+            List<WbsTreePrivate> wbsTreePrivates = Collections.singletonList(obj);
+            List<WbsTreePrivate> result = new ArrayList<>();
+            this.recursionGetChildNodes(wbsTreePrivates, result, obj);
+            if (result.size() > 0) {
+                return result;
+            }
+        }
+        return null;
+    }
+
+    private void recursionGetChildNodes(List<WbsTreePrivate> list, List<WbsTreePrivate> result, WbsTreePrivate obj) {
+        List<Long> ids = list.stream().map(WbsTreePrivate::getId).collect(Collectors.toList());
+        if (ids.size() > 0) {
+            List<WbsTreePrivate> query = wbsTreePrivateMapper.selectList(Wrappers.<WbsTreePrivate>lambdaQuery()
+                    .select(WbsTreePrivate::getWbsId,WbsTreePrivate::getPKeyId, WbsTreePrivate::getId, WbsTreePrivate::getType, WbsTreePrivate::getNodeName,
+                            WbsTreePrivate::getNodeType, WbsTreePrivate::getMajorDataType, WbsTreePrivate::getTableType, WbsTreePrivate::getTableOwner,
+                            WbsTreePrivate::getImportMatchingInfo, WbsTreePrivate::getMixRatioTestIds, WbsTreePrivate::getInitTableId,
+                            WbsTreePrivate::getInitTableName, WbsTreePrivate::getSort, WbsTreePrivate::getHtmlUrl)
+                    .in(WbsTreePrivate::getParentId, ids)
+                    .eq(WbsTreePrivate::getProjectId, obj.getProjectId())
+                    .eq(WbsTreePrivate::getWbsId, obj.getWbsId())
+                    .eq(WbsTreePrivate::getWbsType, obj.getWbsType())
+                    //.eq(WbsTreePrivate::getType, 1) 要同步表的html_url,所以表也要同步
+                    .eq(WbsTreePrivate::getStatus, 1));
+            if (query.size() > 0) {
+                result.addAll(query);
+                recursionGetChildNodes(query, result, obj);
+            }
+        }
+    }
+
+    /**
+     * 获取所有子级节点-公有引用
+     */
+    private List<WbsTree> getChildNodes(WbsTree obj) {
+        if (obj != null) {
+            List<WbsTree> wbsTrees = Collections.singletonList(obj);
+            List<WbsTree> result = new ArrayList<>();
+            this.recursionGetChildNodes(wbsTrees, result, obj);
+            if (result.size() > 0) {
+                return result;
+            }
+        }
+        return null;
+    }
+
+    private void recursionGetChildNodes(List<WbsTree> list, List<WbsTree> result, WbsTree obj) {
+        List<Long> ids = list.stream().map(WbsTree::getId).collect(Collectors.toList());
+        if (ids.size() > 0) {
+            List<WbsTree> query = baseMapper.selectList(Wrappers.<WbsTree>lambdaQuery()
+                    .select(WbsTree::getId, WbsTree::getType, WbsTree::getNodeName, WbsTree::getNodeType, WbsTree::getWbsId, WbsTree::getMajorDataType, WbsTree::getTableType, WbsTree::getTableOwner, WbsTree::getImportMatchingInfo, WbsTree::getMixRatioTestIds, WbsTree::getInitTableId, WbsTree::getInitTableName, WbsTree::getSort)
+                    .in(WbsTree::getParentId, ids)
+                    .eq(WbsTree::getWbsId, obj.getWbsId())
+                    .eq(WbsTree::getType, 1) //没有绑定清表,html_url字段为null,不同步
+                    .eq(WbsTree::getStatus, 1));
+            if (query.size() > 0) {
+                result.addAll(query);
+                recursionGetChildNodes(query, result, obj);
+            }
+        }
+    }
 
     @Override
     public List<WbsNodeTableVO> selectByNodeTable(String id) {
@@ -842,14 +910,13 @@ public class WbsTreeServiceImpl extends BaseServiceImpl<WbsTreeMapper, WbsTree>
     }
 
     @Async
-    public boolean updateWbsInfoPrivateAsync(List<WbsTree> wbsTreeListAll, List<WbsTreePrivate> wbsTreePrivatesAll, String projectId, Integer wbsType) {
-        return wbsTreePrivateService.updateBatchByIds(wbsTreeListAll, wbsTreePrivatesAll, projectId, wbsType);
+    public boolean asyncUpdateWbsPublic(List<WbsTree> wbsTreeListAll, List<WbsTreePrivate> wbsTreePrivatesAll, String projectId, Integer wbsType) {
+        return wbsTreePrivateService.asyncUpdateWbsPublic(wbsTreeListAll, wbsTreePrivatesAll, projectId, wbsType);
     }
 
     @Async
-    public boolean updateWbsInfoContractAsync(List<WbsTreePrivate> wbsTreePrivates, List<WbsTreePrivate> wbsTreePrivatesAllNow, String
-            projectId, String primaryKeyId, Integer wbsType) {
-        return wbsTreePrivateService.updateBatchByIds2(wbsTreePrivates, wbsTreePrivatesAllNow, projectId, primaryKeyId, wbsType);
+    public boolean asyncUpdateWbsPrivate(List<WbsTreePrivate> wbsTreePrivates, List<WbsTreePrivate> wbsTreePrivatesAllNow, String projectId, String primaryKeyId, Integer wbsType) {
+        return wbsTreePrivateService.asyncUpdateWbsPrivate(wbsTreePrivates, wbsTreePrivatesAllNow, projectId, primaryKeyId, wbsType);
     }
 
     //新增独立表单库数据