浏览代码

Merge branch 'test-merge' of http://219.151.181.73:3000/zhuwei/bladex into cr

# Conflicts:
#	blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialMaterialMobilizationServiceImpl.java
chenr 2 月之前
父节点
当前提交
d998a1fafe
共有 100 个文件被更改,包括 4960 次插入296 次删除
  1. 1 0
      blade-common/src/main/java/org/springblade/common/utils/FileUtils.java
  2. 1 1
      blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/feign/NewIOSSClient.java
  3. 5 0
      blade-ops/blade-resource/src/main/java/org/springblade/resource/builder/oss/BladeOssRuleRe.java
  4. 6 0
      blade-service-api/blade-archive-api/src/main/java/org/springblade/archive/entity/ArchivesAuto.java
  5. 22 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/PrivateStandardDTO.java
  6. 25 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/StandardInfoDTO.java
  7. 32 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/StandardInfoJoinDTO.java
  8. 31 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/StandardInfoPrivateJoinDTO.java
  9. 121 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/PrivateStandard.java
  10. 118 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/StandardFile.java
  11. 107 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/StandardInfo.java
  12. 58 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/StandardInfoJoin.java
  13. 98 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/StandardInfoPrivateJoin.java
  14. 21 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/TrialMaterialMobilization.java
  15. 17 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/StandardInfoDtoVo.java
  16. 22 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/StandardInfoPrivateJoinVO.java
  17. 23 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/StandardInfoVO.java
  18. 54 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/dto/SignConfigDTO.java
  19. 81 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/SignConfig.java
  20. 66 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/SignConfigRelation.java
  21. 7 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/WbsTreeContract.java
  22. 7 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/WbsTreePrivate.java
  23. 142 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/WbsTreeSynchronousRecord.java
  24. 55 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/enums/WbsSyncTypeEnum.java
  25. 3 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/feign/ArchiveTreeContractClient.java
  26. 2 2
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/feign/TableFileClient.java
  27. 4 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/feign/WbsParamClient.java
  28. 53 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/SignConfigRelationVO.java
  29. 34 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/SignConfigVO.java
  30. 4 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/TextdictInfoVO.java
  31. 25 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/WbsFormElementVO3.java
  32. 2 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/WbsTreeContractLazyVO.java
  33. 27 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/WbsTreeSynchronousRecordVo.java
  34. 370 142
      blade-service/blade-archive/src/main/java/org/springblade/archive/external/utils/TransUtil.java
  35. 3 3
      blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/ArchivesAutoMapper.xml
  36. 17 5
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveAutoPdfServiceImpl.java
  37. 313 4
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchivesAutoServiceImpl.java
  38. 3 3
      blade-service/blade-archive/src/main/java/org/springblade/archive/utils/FileUtils.java
  39. 224 81
      blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java
  40. 152 0
      blade-service/blade-business/src/main/java/org/springblade/business/controller/PrivateStandardController.java
  41. 199 0
      blade-service/blade-business/src/main/java/org/springblade/business/controller/StandardInfoController.java
  42. 20 7
      blade-service/blade-business/src/main/java/org/springblade/business/controller/TaskController.java
  43. 1 1
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/ArchiveFileMapper.xml
  44. 1 1
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/InformationQueryMapper.xml
  45. 20 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/PrivateStandardMapper.java
  46. 35 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/PrivateStandardMapper.xml
  47. 18 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/StandardFileMapper.java
  48. 23 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/StandardFileMapper.xml
  49. 28 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/StandardInfoJoinMapper.java
  50. 31 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/StandardInfoJoinMapper.xml
  51. 36 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/StandardInfoMapper.java
  52. 193 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/StandardInfoMapper.xml
  53. 28 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/StandardInfoPrivateJoinMapper.java
  54. 33 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/StandardInfoPrivateJoinMapper.xml
  55. 23 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/PrivateStandardService.java
  56. 13 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/StandardFileService.java
  57. 10 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/StandardInfoJoinService.java
  58. 10 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/StandardInfoPrivateJoinService.java
  59. 46 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/StandardInfoService.java
  60. 2 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/InformationQueryServiceImpl.java
  61. 212 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/PrivateStandardServiceImpl.java
  62. 22 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/StandardFileServiceImpl.java
  63. 14 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/StandardInfoJoinServiceImpl.java
  64. 36 8
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialMaterialMobilizationServiceImpl.java
  65. 14 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/UStandardInfoPrivateJoinServiceImpl.java
  66. 270 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/UStandardInfoServiceImpl.java
  67. 8 1
      blade-service/blade-e-visa/src/main/java/org/springblade/evisa/service/impl/EVDataServiceImpl.java
  68. 34 8
      blade-service/blade-e-visa/src/main/java/org/springblade/evisa/utils/PDFUtils.java
  69. 12 10
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java
  70. 178 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/SignConfigController.java
  71. 1 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/TableFileController.java
  72. 17 2
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/TextdictInfoController.java
  73. 147 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreeSynchronousRecordController.java
  74. 4 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/feign/ArchiveTreeContractImpl.java
  75. 2 2
      blade-service/blade-manager/src/main/java/org/springblade/manager/feign/TableFileClientImpl.java
  76. 7 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/feign/WbsParamClientImpl.java
  77. 2 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ArchiveTreeContractMapper.java
  78. 15 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ArchiveTreeContractMapper.xml
  79. 44 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/SignConfigMapper.java
  80. 90 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/SignConfigMapper.xml
  81. 35 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/SignConfigRelationMapper.java
  82. 21 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/SignConfigRelationMapper.xml
  83. 6 2
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/TextdictInfoMapper.xml
  84. 7 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsFormElementMapper.java
  85. 12 2
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsFormElementMapper.xml
  86. 3 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreeContractMapper.java
  87. 7 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreeContractMapper.xml
  88. 2 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreePrivateMapper.java
  89. 5 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreePrivateMapper.xml
  90. 21 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreeSynchronousRecordMapper.java
  91. 30 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreeSynchronousRecordMapper.xml
  92. 12 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/ISignConfigRelationService.java
  93. 34 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/ISignConfigService.java
  94. 7 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/ITextdictInfoService.java
  95. 0 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IWbsTreePrivateService.java
  96. 25 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/WbsTreeSynchronousRecordService.java
  97. 33 7
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ArchiveTreeContractSyncImpl.java
  98. 26 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/FormulaServiceImpl.java
  99. 38 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/SignConfigRelationServiceImpl.java
  100. 381 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/SignConfigServiceImpl.java

+ 1 - 0
blade-common/src/main/java/org/springblade/common/utils/FileUtils.java

@@ -54,6 +54,7 @@ public class FileUtils {
                     Double fileLength = Double.parseDouble(contentLength + "");
                     file.setFileSize(Math.ceil(fileLength / 1024));
                 } catch (IOException e) {
+                    System.out.println("getOssFileSize errurl " + fileUrl);
                     e.printStackTrace();
                 }
                 reData.add(file);

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

@@ -28,7 +28,7 @@ public interface NewIOSSClient {
     @PostMapping(value = UPLOAD_FILE_INFO_INPUT_STREAM, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
     BladeFile uploadFileByInputStream(MultipartFile file);
 
-    @PostMapping(value = UPLOAD_FILE_INFO_INPUT_STREAM2)
+    @PostMapping(value = UPLOAD_FILE_INFO_INPUT_STREAM2,  consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE)
     BladeFile uploadFileByInputStream2(@RequestParam String OriginalFilename,@RequestParam InputStream inputStream);
 
     @PostMapping(UPLOAD_FILE_INFO)

+ 5 - 0
blade-ops/blade-resource/src/main/java/org/springblade/resource/builder/oss/BladeOssRuleRe.java

@@ -19,6 +19,11 @@ class BladeOssRuleRe implements OssRule {
     }
 
     public String fileName(String originalFilename) {
+        //试验-规范管理
+        if(originalFilename.contains("standard")){
+            String[] split = originalFilename.split("\\|");
+            return "upload/" + split[0] + "/" + DateUtil.today() + "/" + FileUtil.getNameWithoutExtension(split[1]) + "." + FileUtil.getFileExtension(split[1]);
+        }
         return "upload/" + DateUtil.today() + "/" + FileUtil.getNameWithoutExtension(originalFilename) + "." + FileUtil.getFileExtension(originalFilename);
     }
 

+ 6 - 0
blade-service-api/blade-archive-api/src/main/java/org/springblade/archive/entity/ArchivesAuto.java

@@ -261,10 +261,16 @@ public class ArchivesAuto extends BaseEntity {
             this.setSecretLevel("4");
         }
 
+        //排序
+        if (autoVo.getOrderNum()!= null) {
+            this.setAutoFileSort(autoVo.getOrderNum());
+        }
 
         // 4. 设置默认值(根据业务需求)
         this.setIsAutoFile(0);
         this.setIsArchive(1);
         this.setIsDeleted(0);
     }
+
+    
 }

+ 22 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/PrivateStandardDTO.java

@@ -0,0 +1,22 @@
+package org.springblade.business.dto;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.business.entity.PrivateStandard;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+/**
+ * @author LHB
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@ApiModel(description = "规范文件夹及规范文件对象")
+public class PrivateStandardDTO extends PrivateStandard {
+    /**
+     * 文件
+     */
+    private MultipartFile[] files;
+}

+ 25 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/StandardInfoDTO.java

@@ -0,0 +1,25 @@
+package org.springblade.business.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.business.entity.StandardInfo;
+
+import java.util.List;
+
+/**
+ * 试验规范信息DTO
+ *
+ * @author LHB
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@ApiModel(description = "试验规范信息DTO")
+public class StandardInfoDTO extends StandardInfo {
+    /**
+     * 基础信息
+     */
+    @ApiModelProperty(value = "基础信息", required = true)
+    private List<StandardInfo> info;
+}

+ 32 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/StandardInfoJoinDTO.java

@@ -0,0 +1,32 @@
+package org.springblade.business.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * 条件设置
+ *
+ * @author LHB
+ */
+@Data
+@ApiModel(description = "新增对象")
+public class StandardInfoJoinDTO {
+    /**
+     * 主关联id
+     */
+    @ApiModelProperty(value = "主关联id", required = true)
+    @NotNull(message = "主关联id不能为空")
+    private Long leftId;
+
+    /**
+     * 副连接id
+     */
+    @ApiModelProperty(value = "副连接id集合", required = true)
+    @NotEmpty(message = "副连接id不能为空")
+    private List<Long> rightIds;
+}

+ 31 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/StandardInfoPrivateJoinDTO.java

@@ -0,0 +1,31 @@
+package org.springblade.business.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springblade.business.entity.StandardInfoPrivateJoin;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * 与表单的关联对象
+ * @author LHB
+ */
+@Data
+@ApiModel(description = "新增对象")
+public class StandardInfoPrivateJoinDTO {
+    /**
+     * 主关联id
+     */
+    @NotNull(message = "主关联id不能为空")
+    @ApiModelProperty(value = "主关联id")
+    private Long leftId;
+    /**
+     * 副连接id
+     */
+    @NotEmpty(message = "副连接信息不能为空")
+    @ApiModelProperty(value = "副连接信息集合")
+    private List<StandardInfoPrivateJoin> rightIds;
+}

+ 121 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/PrivateStandard.java

@@ -0,0 +1,121 @@
+package org.springblade.business.entity;
+
+import cn.hutool.core.date.DateTime;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import java.time.LocalDateTime;
+import java.util.Date;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 规范文件夹及规范文件表
+ *
+ * @author LHB
+ * @TableName u_wbs_private_standard
+ */
+@TableName(value = "u_wbs_private_standard")
+@Data
+@ApiModel(description = "规范文件夹及规范文件对象")
+public class PrivateStandard {
+    /**
+     *
+     */
+    @TableId
+    @ApiModelProperty(value = "主键", required = true)
+    private Long id;
+
+    /**
+     * 名称(规范文件夹名称及规范名称)
+     */
+    @NotBlank(message = "名称不能为空")
+    @ApiModelProperty(value = "名称", required = true)
+    private String name;
+
+    /**
+     * 父级节点id
+     * type = 2 必传
+     */
+    @ApiModelProperty(value = "父级节点id(type = 2 必传)")
+    private Long parentId;
+
+    /**
+     * 项目试验节点id
+     * type = 1 必传
+     */
+    @ApiModelProperty(value = "项目试验节点id(type = 1 必传)")
+    private Long privateId;
+
+    /**
+     * 类型(1-规范文件夹,2-规范文件)
+     */
+    @ApiModelProperty(value = "类型(1-规范文件夹,2-规范文件)", required = true)
+    @NotNull(message = "类型不能为空")
+    private Integer type;
+
+    /**
+     * 下达日期(年月日)
+     * type = 2 必传
+     */
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    @ApiModelProperty(value = "下达日期(年月日)(type = 2 必传)")
+    private Date issueDate;
+
+    /**
+     * 实施日期(年月日)
+     * type = 2 必传
+     */
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    @ApiModelProperty(value = "实施日期(年月日)(type = 2 必传)")
+    private Date actualizeDate;
+
+    /**
+     * 是否删除(0-正常,1-已删除)
+     */
+    @ApiModelProperty(value = "是否删除(0-正常,1-已删除)")
+    private Integer isDeleted = 0;
+    /**
+     * 状态(1-正常,2-过期)
+     */
+    @ApiModelProperty(value = "状态(1-正常,2-过期)")
+    private Integer status;
+
+    /**
+     * 创建时间
+     */
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "创建时间", hidden = true)
+    private LocalDateTime createTime;
+
+    /**
+     * 创建人
+     */
+    @ApiModelProperty(value = "创建人", hidden = true)
+    private Long createUser;
+
+    /**
+     * 修改时间
+     */
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "修改时间", hidden = true)
+    private LocalDateTime updateTime;
+
+    /**
+     * 修改人
+     */
+    @ApiModelProperty(value = "修改人", hidden = true)
+    private Long updateUser;
+}

+ 118 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/StandardFile.java

@@ -0,0 +1,118 @@
+package org.springblade.business.entity;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * 规范文件表
+ * @TableName u_standard_file
+ */
+@TableName(value ="u_standard_file")
+@Data
+public class StandardFile {
+    /**
+     * 
+     */
+    @TableId
+    private Long id;
+
+    /**
+     * 规范id
+     */
+    private Long standardId;
+
+    /**
+     * 文件名称
+     */
+    private String fileName;
+
+    /**
+     * 规范文件路径
+     */
+    private String standardFileUrl;
+
+    /**
+     *  是否删除(0-正常,1-已删除)
+     */
+    private Integer isDeleted;
+
+    /**
+     *  创建时间
+     */
+    private Date createTime;
+
+    /**
+     *  创建人
+     */
+    private Long createUser;
+
+    /**
+     *  修改时间
+     */
+    private Date updateTime;
+
+    /**
+     *  修改人
+     */
+    private Long updateUser;
+
+    @Override
+    public boolean equals(Object that) {
+        if (this == that) {
+            return true;
+        }
+        if (that == null) {
+            return false;
+        }
+        if (getClass() != that.getClass()) {
+            return false;
+        }
+        StandardFile other = (StandardFile) that;
+        return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))
+            && (this.getStandardId() == null ? other.getStandardId() == null : this.getStandardId().equals(other.getStandardId()))
+            && (this.getFileName() == null ? other.getFileName() == null : this.getFileName().equals(other.getFileName()))
+            && (this.getStandardFileUrl() == null ? other.getStandardFileUrl() == null : this.getStandardFileUrl().equals(other.getStandardFileUrl()))
+            && (this.getIsDeleted() == null ? other.getIsDeleted() == null : this.getIsDeleted().equals(other.getIsDeleted()))
+            && (this.getCreateTime() == null ? other.getCreateTime() == null : this.getCreateTime().equals(other.getCreateTime()))
+            && (this.getCreateUser() == null ? other.getCreateUser() == null : this.getCreateUser().equals(other.getCreateUser()))
+            && (this.getUpdateTime() == null ? other.getUpdateTime() == null : this.getUpdateTime().equals(other.getUpdateTime()))
+            && (this.getUpdateUser() == null ? other.getUpdateUser() == null : this.getUpdateUser().equals(other.getUpdateUser()));
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
+        result = prime * result + ((getStandardId() == null) ? 0 : getStandardId().hashCode());
+        result = prime * result + ((getFileName() == null) ? 0 : getFileName().hashCode());
+        result = prime * result + ((getStandardFileUrl() == null) ? 0 : getStandardFileUrl().hashCode());
+        result = prime * result + ((getIsDeleted() == null) ? 0 : getIsDeleted().hashCode());
+        result = prime * result + ((getCreateTime() == null) ? 0 : getCreateTime().hashCode());
+        result = prime * result + ((getCreateUser() == null) ? 0 : getCreateUser().hashCode());
+        result = prime * result + ((getUpdateTime() == null) ? 0 : getUpdateTime().hashCode());
+        result = prime * result + ((getUpdateUser() == null) ? 0 : getUpdateUser().hashCode());
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getClass().getSimpleName());
+        sb.append(" [");
+        sb.append("Hash = ").append(hashCode());
+        sb.append(", id=").append(id);
+        sb.append(", standardId=").append(standardId);
+        sb.append(", fileName=").append(fileName);
+        sb.append(", standardFileUrl=").append(standardFileUrl);
+        sb.append(", isDeleted=").append(isDeleted);
+        sb.append(", createTime=").append(createTime);
+        sb.append(", createUser=").append(createUser);
+        sb.append(", updateTime=").append(updateTime);
+        sb.append(", updateUser=").append(updateUser);
+        sb.append("]");
+        return sb.toString();
+    }
+}

+ 107 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/StandardInfo.java

@@ -0,0 +1,107 @@
+package org.springblade.business.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import java.util.Date;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.hibernate.validator.constraints.Range;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 规范参数管理-基础信息
+ *
+ * @author LHB
+ * @TableName u_standard_info
+ */
+@TableName(value = "u_standard_info")
+@Data
+@ApiModel(description = "规范参数管理-基础信息")
+public class StandardInfo {
+    /**
+     *
+     */
+    @TableId
+    @ApiModelProperty(value = "主键")
+    private Long id;
+
+    /**
+     * 名称(样品信息名称)
+     */
+    @NotBlank(message = "名称不能为空")
+    @ApiModelProperty(value = "名称(样品信息名称)")
+    private String name;
+    /**
+     * 符号
+     */
+    @ApiModelProperty(value = "符号")
+    private String symbol;
+
+    /**
+     * 父级节点id
+     */
+    @ApiModelProperty(value = "父级节点id")
+    private Long parentId;
+
+    /**
+     * 规范文件id
+     */
+    @ApiModelProperty(value = "规范文件id")
+    private Long standardId;
+
+    /**
+     * 类型(1-样品信息,2-技术指标)
+     */
+    @ApiModelProperty(value = "类型(1-样品信息,2-技术指标)")
+    @NotNull(message = "类型不能为空")
+    @Range(min = 1, max = 2, message = "类型只能为1或2")
+    private Integer type;
+
+    /**
+     * 是否删除(0-正常,1-已删除)
+     */
+    @ApiModelProperty(value = "是否删除(0-正常,1-已删除)")
+    private Integer isDeleted;
+
+    /**
+     * 创建时间
+     */
+    @ApiModelProperty(value = "创建时间", hidden = true)
+    private Date createTime;
+
+    /**
+     * 创建人
+     */
+    @ApiModelProperty(value = "创建人", hidden = true)
+    private Long createUser;
+
+    /**
+     * 修改时间
+     */
+    @ApiModelProperty(value = "修改时间", hidden = true)
+    private Date updateTime;
+
+    /**
+     * 修改人
+     */
+    @ApiModelProperty(value = "修改人", hidden = true)
+    private Long updateUser;
+
+    /**
+     * 符号名称
+     */
+    @TableField(exist = false)
+    private String symbolName;
+
+    /**
+     * 父级名称
+     */
+    @TableField(exist = false)
+    private String parentName;
+}

+ 58 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/StandardInfoJoin.java

@@ -0,0 +1,58 @@
+package org.springblade.business.entity;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * 样品信息关联表
+ * @author LHB
+ * @TableName u_standard_info_join
+ */
+@TableName(value ="u_standard_info_join")
+@Data
+public class StandardInfoJoin {
+    /**
+     * 
+     */
+    @TableId
+    private Long id;
+
+    /**
+     * 规范基础信息关联主id
+     */
+    private Long standardInfoLeftId;
+
+    /**
+     * 规范基础信息关联副id
+     */
+    private Long standardInfoRightId;
+
+    /**
+     *  是否删除(0-正常,1-已删除)
+     */
+    private Integer isDeleted;
+
+    /**
+     *  创建时间
+     */
+    private Date createTime;
+
+    /**
+     *  创建人
+     */
+    private Long createUser;
+
+    /**
+     *  修改时间
+     */
+    private Date updateTime;
+
+    /**
+     *  修改人
+     */
+    private Long updateUser;
+
+
+}

+ 98 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/StandardInfoPrivateJoin.java

@@ -0,0 +1,98 @@
+package org.springblade.business.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.util.Date;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 样品信息与试验表 关联表
+ * @author LHB
+ * @TableName u_standard_info_private_join
+ */
+@TableName(value ="u_standard_info_private_join")
+@Data
+
+@ApiModel(description = "副连接信息集合")
+public class StandardInfoPrivateJoin {
+    /**
+     * 
+     */
+    @TableId
+    @ApiModelProperty(value = "主键", required = true)
+    private Long id;
+
+    /**
+     * 规范基础信息关联主id
+     */
+    @NotNull(message = "规范基础信息关联主id不能为空")
+    @ApiModelProperty(value = "规范基础信息关联主id", hidden = true)
+    private Long standardInfoId;
+
+    /**
+     * 试验wbs表单id
+     */
+    @NotNull(message = "试验wbs表单id不能为空")
+    @ApiModelProperty(value = "试验wbs表单id", required = true)
+    private Long privateId;
+
+    /**
+     * 元素key
+     */
+    @NotBlank(message = "元素key不能为空")
+    @ApiModelProperty(value = "元素key", required = true)
+    private String colKey;
+
+    /**
+     * 元素名称
+     */
+    @NotBlank(message = "元素名称不能为空")
+    @ApiModelProperty(value = "元素名称", required = true)
+    private String colName;
+
+    /**
+     *  是否删除(0-正常,1-已删除)
+     */
+    @ApiModelProperty(value = "是否删除(0-正常,1-已删除)")
+    private Integer isDeleted;
+
+    /**
+     *  创建时间
+     */
+    @ApiModelProperty(value = "创建时间", hidden = true)
+    private Date createTime;
+
+    /**
+     *  创建人
+     */
+    @ApiModelProperty(value = "创建人", hidden = true)
+    private Long createUser;
+
+    /**
+     *  修改时间
+     */
+    @ApiModelProperty(value = "修改时间", hidden = true)
+    private Date updateTime;
+
+    /**
+     *  修改人
+     */
+    @ApiModelProperty(value = "修改人", hidden = true)
+    private Long updateUser;
+
+
+    /**
+     * 表单名称(展示用)
+     */
+    @ApiModelProperty(value = "表单名称(展示用)")
+    @TableField(exist = false)
+    private String privateName;
+
+}

+ 21 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/TrialMaterialMobilization.java

@@ -125,6 +125,13 @@ public class TrialMaterialMobilization extends BaseEntity {
     @Length(max = 255, message = "生产合格证最大长度255个字符")
     private String productionCertificate;
 
+    /**
+     * 生产合格证pdf url
+     */
+    @ApiModelProperty(value = "生产合格证 pdf url")
+    @Length(max = 255, message = "生产合格证pdf url最大长度255个字符")
+    private String productionCertificatePdfUrl;
+
     /**
      * 厂家质检报告
      */
@@ -132,6 +139,13 @@ public class TrialMaterialMobilization extends BaseEntity {
     @Length(max = 255, message = "厂家质检报告最大长度255个字符")
     private String qualityInspectionReport;
 
+    /**
+     * 厂家质检报告 pdf url
+     */
+    @ApiModelProperty(value = "厂家质检报告 pdf url")
+    @Length(max = 255, message = "厂家质检报告 pdf url最大长度255个字符")
+    private String qualityInspectionReportPdfUrl;
+
     /**
      * 其他附件
      */
@@ -139,6 +153,13 @@ public class TrialMaterialMobilization extends BaseEntity {
     @Length(max = 255, message = "其他附件最大长度255个字符")
     private String otherAccessories;
 
+    /**
+     * 其他附件 pdf url
+     */
+    @ApiModelProperty(value = "其他附件 pdf url")
+    @Length(max = 255, message = "其他附件 pdf url最大长度255个字符")
+    private String otherAccessoriesPdfUrl;
+
     /**
      * 排序
      */

+ 17 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/StandardInfoDtoVo.java

@@ -0,0 +1,17 @@
+package org.springblade.business.vo;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.business.dto.StandardInfoDTO;
+
+/**
+ * @author LHB
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class StandardInfoDtoVo extends StandardInfoDTO {
+    /**
+     * 符号拼接名称
+     */
+    private String symbolName;
+}

+ 22 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/StandardInfoPrivateJoinVO.java

@@ -0,0 +1,22 @@
+package org.springblade.business.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.business.entity.StandardInfo;
+import org.springblade.business.entity.StandardInfoPrivateJoin;
+
+import java.util.List;
+
+/**
+ * @author LHB
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@ApiModel(description = "关联元素对象-视图")
+public class StandardInfoPrivateJoinVO extends StandardInfo {
+
+    @ApiModelProperty(value = "关联元素副元素集合")
+    private List<StandardInfoPrivateJoin> privateJoins;
+}

+ 23 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/StandardInfoVO.java

@@ -0,0 +1,23 @@
+package org.springblade.business.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.business.entity.StandardInfo;
+
+import java.util.List;
+
+/**
+ * @author LHB
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@ApiModel(description = "条件设置对象")
+public class StandardInfoVO extends StandardInfo {
+    /**
+     * 副连接对象
+     */
+    @ApiModelProperty(value = "副连接对象集合")
+    private List<StandardInfo> standardInfos;
+}

+ 54 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/dto/SignConfigDTO.java

@@ -0,0 +1,54 @@
+/*
+ *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *  Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the dreamlu.net developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: Chill 庄骞 (smallchill@163.com)
+ */
+package org.springblade.manager.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.manager.entity.SignConfig;
+import org.springblade.manager.entity.TableInfo;
+
+import java.util.List;
+
+/**
+ * 实体主表信息数据传输对象实体类
+ *
+ * @author BladeX
+ * @since 2022-11-30
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class SignConfigDTO extends SignConfig {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 电签元素id
+     */
+    @ApiModelProperty(value = "电签元素id")
+    private String elementId;
+    /**
+     * 元素表ids
+     */
+    @ApiModelProperty(value = "元素表ids")
+    private List<String> tableIds;
+    /**
+     * 角色ids
+     */
+    @ApiModelProperty(value = "角色ids")
+    private List<String> roleIds;
+
+}

+ 81 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/SignConfig.java

@@ -0,0 +1,81 @@
+/*
+ *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *  Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the dreamlu.net developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: Chill 庄骞 (smallchill@163.com)
+ */
+package org.springblade.manager.entity;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.core.mp.base.BaseEntity;
+
+/**
+ * 电签配置表实体类
+ *
+ * @author BladeX
+ * @since 2022-05-18
+ */
+@Data
+@TableName("m_sign_config")
+@EqualsAndHashCode(callSuper = true)
+public class SignConfig extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 电签元素名称
+     */
+    @ApiModelProperty(value = "电签元素名称")
+    @JsonProperty("eName")
+    private String eName;
+
+    /**
+     * 电签元素id
+     */
+    @ApiModelProperty(value = "电签元素id")
+    private Long eId;
+
+
+    /**
+     * 电签元素key
+     */
+    @ApiModelProperty(value = "电签元素key")
+    @JsonProperty("eKey")
+    private String eKey;
+
+    /**
+     * 元素类型,1:字符串、2:整数、3:小数、4:日期、5:数值、6:签名、7:文件、0:其他
+     */
+    @ApiModelProperty(value = "元素类型,1:字符串、2:整数、3:小数、4:日期、5:数值、6:签名、7:文件、0:其他")
+    private Integer elementType;
+
+    /**
+     * 租户ID
+     */
+    @ApiModelProperty(value = "租户ID")
+    private String tenantId;
+
+
+    /**
+     * 元素表类型,0:所有、1:部分
+     */
+    @ApiModelProperty(value = "元素表类型,0:所有、1:部分")
+    private Integer tableType;
+
+
+}

+ 66 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/SignConfigRelation.java

@@ -0,0 +1,66 @@
+/*
+ *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *  Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the dreamlu.net developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: Chill 庄骞 (smallchill@163.com)
+ */
+package org.springblade.manager.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.core.mp.base.BaseEntity;
+
+/**
+ * 电签配置关联表实体类
+ *
+ * @author BladeX
+ * @since 2022-05-18
+ */
+@Data
+@TableName("m_sign_config_relation")
+@EqualsAndHashCode(callSuper = true)
+public class SignConfigRelation extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 电签配置id
+     */
+    @ApiModelProperty(value = "电签配置id")
+    private Long confId;
+    /**
+     * 关联的岗位/角色 id
+     */
+    @ApiModelProperty(value = "关联的岗位/角色 id")
+    private Long relationId;
+    /**
+     * 关联类型,0:元素表、1:角色
+     */
+    @ApiModelProperty(value = "关联类型,0:元素表、1:角色")
+    private Integer type;
+
+    /**
+     * 关联类型,0:元素表、1:角色
+     */
+    @ApiModelProperty(value = "关联的元素表、角色类型")
+    private Integer relationType;
+
+    /**
+     * 岗位/角色 名称
+     */
+    @ApiModelProperty(value = "关联的岗位/角色名称")
+    private String relationName;
+
+}

+ 7 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/WbsTreeContract.java

@@ -1,5 +1,8 @@
 package org.springblade.manager.entity;
 
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModelProperty;
@@ -23,8 +26,12 @@ public class WbsTreeContract extends BaseEntity {
      * 主键id
      */
     @ApiModelProperty(value = "主键id")
+    @TableId(value = "p_key_id", type = IdType.INPUT)
     private Long pKeyId;
 
+    @TableField
+    private Long id;
+
 
     @ApiModelProperty(value = "新节点Id")
     private Long pId;

+ 7 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/WbsTreePrivate.java

@@ -1,5 +1,8 @@
 package org.springblade.manager.entity;
 
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModelProperty;
@@ -20,9 +23,13 @@ public class WbsTreePrivate extends BaseEntity {
     /**
      * 主键
      */
+    @TableId(value = "p_key_id", type = IdType.INPUT)
     @JsonProperty(value = "pKeyId")
     private Long pKeyId;
 
+    @TableField
+    private Long id;
+
     @ApiModelProperty(value = "pid")
     private Long pId;
 

+ 142 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/WbsTreeSynchronousRecord.java

@@ -0,0 +1,142 @@
+package org.springblade.manager.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * WBS同步记录表
+ *
+ * @author LHB
+ * @TableName m_wbs_tree_synchronous_record
+ */
+@TableName(value = "m_wbs_tree_synchronous_record")
+@Data
+public class WbsTreeSynchronousRecord {
+    /**
+     * id111
+     */
+    @TableId
+    private Long id;
+
+    /**
+     * 项目id
+     */
+    private Long projectId;
+
+    /**
+     * 项目名称
+     */
+    private String projectName;
+
+
+    @TableField("`range`")
+    private Integer range;
+    /**
+     * 同步范围名称
+     */
+    private String rangeName;
+    /**
+     * 合同段范围 逗号拼接的编号 101.未填报 102.已填报-未上报 103.未上报 104.待审批 105.已审批
+     */
+    private String contractRange;
+    /**
+     * 合同段范围名称
+     */
+    private String contractRangeName;
+
+    /**
+     * 同步源Id
+     */
+    private Long templateId;
+
+    /**
+     * 同步源名称
+     */
+    private String templateName;
+
+    /**
+     * 同步类型 逗号拼接的编号 1.新增表单 2.清表配置 3.元素配置 4.电签配置 5.公式配置 6.默认值配置 7.表单排序
+     */
+    private String type;
+
+    /**
+     * 同步类型名称
+     */
+    private String typeName;
+
+    /**
+     * 同步节点id 多个节点
+     */
+    private String nodeId;
+
+    /**
+     * 同步节点名称
+     */
+    private String nodeName;
+    /**
+     * 表单Ids     range = 4 强制同步时  当前数据为同步源
+     */
+    private String formIds;
+    /**
+     * 同步节点数量
+     */
+    private Integer nodeNum;
+    /**
+     * 已同步数量
+     */
+    private Integer nodeNumEnd;
+
+    /**
+     * 是否删除(0-未删除,1-删除)
+     */
+    private Integer isDeleted;
+
+    /**
+     * 状态(0-未同步,1-正在同步,2-已同步,3-同步失败)
+     */
+    private Integer status;
+    /**
+     * 状态(0-未同步,1-正在同步,2-已同步,3-同步失败)
+     */
+    @TableField(exist = false)
+    private String statusName;
+    /**
+     * 错误信息
+     */
+    @TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+    private String errorMsg;
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 创建人
+     */
+    private String createUser;
+
+    /**
+     * 创建人id
+     */
+    private Long createUserId;
+
+    /**
+     * 修改时间
+     */
+    private Date updateTime;
+
+    /**
+     * 修改人
+     */
+    private String updateUser;
+
+    /**
+     * 修改人id
+     */
+    private Long updateUserId;
+}

+ 55 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/enums/WbsSyncTypeEnum.java

@@ -0,0 +1,55 @@
+package org.springblade.manager.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.springblade.core.tool.utils.ObjectUtil;
+
+/**
+ * @author LHB
+ */
+@Getter
+@AllArgsConstructor
+public enum WbsSyncTypeEnum {
+    UNKNOWN(-1, ""),
+    INSERT_FORM(1, "新增表单"),
+    CLEAR_TABLE_CONFIG(2, "清表配置"),
+    ELEMENT_CONFIG(3, "元素配置"),
+    E_VISA_CONFIG(4, "电签配置"),
+    FORMULA_CONFIG(5, "公式配置"),
+    DEFAULT_VALUE_CONFIG(6, "默认值配置"),
+    FORM_SORT(7, "表单排序"),
+    /**
+     * 合同段同步范围
+     */
+    NOT_FILLED_IN(101, "未填报"),
+    ALREADY_FILLED_IN_NOT_REPORTED(102, "已填报-未上报"),
+    NOT_REPORTED(103, "未上报"),
+    PENDING_APPROVAL(104, "待审批"),
+    APPROVED(105, "已审批"),
+    ;
+
+    /**
+     * 编码
+     */
+    public Integer code;
+
+    /**
+     * 描述
+     */
+    private String desc;
+
+    /**
+     * 根据编码获取枚举描述
+     */
+    public static String getByCode(int code) {
+        // 判断code
+        if(ObjectUtil.isNotEmpty(code)){
+            for (StorageTypeEnum storageTypeEnum : StorageTypeEnum.values()) {
+                if (storageTypeEnum.getCode() == code) {
+                    return storageTypeEnum.getDesc();
+                }
+            }
+        }
+        return WbsSyncTypeEnum.UNKNOWN.getDesc();
+    }
+}

+ 3 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/feign/ArchiveTreeContractClient.java

@@ -27,6 +27,9 @@ public interface ArchiveTreeContractClient {
     @PostMapping(API_PREFIX + "/getHavedFileNodeByProjectID")
     List<ArchiveTreeContract> getHavedFileNodeByProjectID(@RequestParam Long projectId);
 
+    @PostMapping(API_PREFIX + "/getTopAutoTypeNodeByProjectID")
+    List<ArchiveTreeContract> getTopAutoTypeNodeByProjectID(@RequestParam Long projectId);
+
     /**
      * 根据项目id获取所有数据
      */

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

@@ -29,7 +29,7 @@ public interface TableFileClient {
     @PostMapping(API_PREFIX + "/saveBatch")
     boolean saveBatch(@RequestBody List<TableFile> newFiles);
 
-    @GetMapping(API_PREFIX + "/getTabFilesByTabIds")
-    List<TableFile> getTabFilesByTabIds(@RequestParam String tabFileIds);
+    @PostMapping(API_PREFIX + "/getTabFilesByTabIds")
+    List<TableFile> getTabFilesByTabIds(@RequestBody List<String> tabFileIds);
 
 }

+ 4 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/feign/WbsParamClient.java

@@ -9,6 +9,8 @@ import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestParam;
 
+import java.util.List;
+
 import static org.springblade.core.launch.constant.AppConstant.APPLICATION_NAME_PREFIX;
 
 @FeignClient(value = APPLICATION_NAME_PREFIX + "manager")
@@ -24,6 +26,8 @@ public interface WbsParamClient {
     @GetMapping(API_PREFIX + "/getWbsParam")
     WbsParam getWbsParam(@RequestParam Long nodeId);
 
+    @PostMapping(API_PREFIX + "/saveWbsParams")
+    void saveWbsParams(@RequestBody List<WbsParam> wbsParamList);
     @PostMapping(API_PREFIX + "/createFileTitle")
     String createFileTitle(@RequestBody WbsTreeContract contract);
 }

+ 53 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/SignConfigRelationVO.java

@@ -0,0 +1,53 @@
+package org.springblade.manager.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.manager.entity.SignConfig;
+import org.springblade.manager.entity.SignConfigRelation;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Data
+public class SignConfigRelationVO  implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "id")
+    private Long id;
+
+    @ApiModelProperty(value = "名称")
+    private String name;
+
+    @ApiModelProperty(value = "类型")
+    private String type;
+
+    public static SignConfigRelationVO build(SignConfigRelation entity) {
+        SignConfigRelationVO vo = new SignConfigRelationVO();
+        vo.setId(entity.getRelationId());
+        vo.setName(entity.getRelationName());
+        if (entity.getType() == 1 &&  entity.getRelationType() != null) {
+            if (entity.getRelationType() == 1) {
+                vo.setType("施工方");
+            } else if (entity.getRelationType() == 2) {
+                vo.setType("监理方");
+            } else if (entity.getRelationType() == 3) {
+                vo.setType("业主方");
+            } else {
+                vo.setType("");
+            }
+        } else {
+            vo.setType(entity.getRelationType() + "");
+        }
+        return vo;
+    }
+    public static List<SignConfigRelationVO> build(List<SignConfigRelation> entityList) {
+        if (entityList == null) {
+            return new ArrayList<>();
+        }
+        return entityList.stream().map(SignConfigRelationVO::build).collect(Collectors.toList());
+    }
+}

+ 34 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/SignConfigVO.java

@@ -0,0 +1,34 @@
+package org.springblade.manager.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.core.tool.node.INode;
+import org.springblade.manager.entity.ArchiveTree;
+import org.springblade.manager.entity.SignConfig;
+import org.springblade.manager.entity.SignConfigRelation;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class SignConfigVO extends SignConfig implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "元素类型名称")
+    private String elementTypeName;
+
+    @ApiModelProperty(value = "岗位ids")
+    private List<String> roleIds;
+
+    @ApiModelProperty(value = "元素表ids")
+    private List<String> tableIds;
+
+    private List<SignConfigRelation> relations;
+}

+ 4 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/TextdictInfoVO.java

@@ -16,6 +16,7 @@
  */
 package org.springblade.manager.vo;
 
+import io.swagger.annotations.ApiModelProperty;
 import org.springblade.manager.entity.TextdictInfo;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
@@ -34,4 +35,7 @@ public class TextdictInfoVO extends TextdictInfo {
     private String parentRoleId;
     //1.电签配置 2.系统识别
     private Integer showType;
+
+    @ApiModelProperty("是否引用系统级电签配置,1 系统级,0 项目级")
+    private Integer isSystem = 0;
 }

+ 25 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/WbsFormElementVO3.java

@@ -0,0 +1,25 @@
+package org.springblade.manager.vo;
+
+import lombok.Data;
+import org.springblade.manager.entity.WbsFormElement;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class WbsFormElementVO3 implements Serializable {
+
+    /**
+     * 主键
+     */
+    private Long id;
+
+    /**
+     * 实体表名
+     */
+    private String eName;
+
+    private Integer eType;
+
+    private String eTypeName;
+}

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

@@ -133,4 +133,6 @@ public class WbsTreeContractLazyVO implements Serializable {
     @ApiModelProperty(value = "关联后管节点ID")
     private Long isTypePrivatePid;
 
+
+
 }

+ 27 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/WbsTreeSynchronousRecordVo.java

@@ -0,0 +1,27 @@
+package org.springblade.manager.vo;
+
+import lombok.Data;
+
+/**
+ *
+ * @author LHB
+ */
+@Data
+public class WbsTreeSynchronousRecordVo {
+    /**
+     * id
+     */
+    private Long id;
+    /**
+     * 项目名称
+     */
+    private String name;
+    /**
+     * wbsId
+     */
+    private String wbsId;
+    /**
+     * type = 1 公共  type = 2 私有
+     */
+    private Integer type;
+}

+ 370 - 142
blade-service/blade-archive/src/main/java/org/springblade/archive/external/utils/TransUtil.java

@@ -19,208 +19,431 @@ public class TransUtil {
     public static final Map<String, Long> EXTERNAL_TO_INTERNAL_NODE_ID_MAP = new LinkedHashMap<String, Long>() {{
         // 初始化默认映射关系(可按需添加)
 
-        //=================建设单位
+        //=================建设单位】====
         //军教工验收文件
-        put("3b843c05e00c4b65a1e666db80cf", 1892759789381877760L);
+//        put("3b843c05e00c4b65a1e666db80cf", 1892759789381877760L);
+//
+//        //征地拆迁
+//        put("ced7daa78cc040d1b731dfedd51f", 1892759789381877780L);
+//
+//        //工程文件
+//        put("e18bd5c3b1f7489b87d27594dee9", 1892759789381877794L);
+//
+//        //决算和审计文件
+//        put("442e7e595dce411abd984da1866d", 1892759789381877811L);
+
+        //====建设单位数字化扫描档案(第一部分 综合文件)
+        //三、征地拆迁资料
+        put("8d69b1589c8d47bcac6ee0579f21", 1927614316916244487L);
+
+        //=======建设单位数字化扫描档案(第二部分 决算和审计文件)
+        //一、支付报表及计算单
+        put("c3073682882249cb83fb87ef83d4", 1927614316916244492L);
 
-        //征地拆迁
-        put("ced7daa78cc040d1b731dfedd51f", 1892759789381877780L);
+        //====监理
+        //====================【第一总监】
 
-        //工程文件
-        put("e18bd5c3b1f7489b87d27594dee9", 1892759789381877794L);
+        //监理抽检资料
+        put("5d17cfbfcc134319b3bc2251d1cf", 1927992314584629254L);
+
+        //交工验收工程质量评定资料
+        put("e6189ff32e8c4b07ab2f89453a6a", 1927992314584629271L);
+
+        //NoJL1合同段数字化扫描档案
+        //一、监理管理文件
+        put("dfe39a7134c34aea833b51ecd889", 1927992314584629252L);
+        //一、监理管理文件
+        //(一)质量控制措施、规定
+        put("55fe4f6011294050b65210d814e0", 1927992314584629250L);
+        //(二)质量控制往来文件
+        put("f72d6d2c24564e01a456c8f49593", 1927992314584629253L);
+        //(三)监理独立抽检资料(试验)
+        put("972d06c557924952abaa8257dc71", 1927992314584629272L);
+        //(四)监理独立抽检报告
+        put("535f2dca3d4a4c6f84d3b154e961", 1927992314584629255L);
+        //三、工程进度计划管理文件
+        put("487c6416e2f34158838588773454", 1927992314584629286L);
+        //五、其它文件
+        put("5491ddc563e74ad4bbb4baddcb9f", 1927992314584629288L);
+        //六、其它资料
+        put("1817a9c924fc4a9686ab5b02e077", 1927992314584629296L);
+
+//        //印章启用文件、监理人员变更的函和批复文件
+//        put("465c2ebad85e44e9b4217d7ae415", 1892759789402849282L);
+//        //工程监理月报(2022年1月至2023年2月)
+//        put("ffce00c9bd7443d9b3d6ef63f885", 1902189729003851778L);
+//        //监理日志(张换丽)
+//        put("6e7ad41e5cd542f893a69ec7cebd", 1902189935200030722L);
+//        //监理日志(钟兆革)
+//        put("8d818ccbf39247cbb1f49ed3c7b0", 1902190429066743809L);
+//
+//        //原材料、设备及构件试验报告、记录 1902201113984880642
+//        put("89aaa0372cc24d14b3efdd788141", 1902200995105722370L);
+//
+//
+//        //试验检测汇总表
+//        put("0b023c2125664791a0511fc587f8", 1902205006567428097L);
+//        //原材料、半成品、成品报告
+//        put("bbc75d54e5d14b1f8368ce6fb51f", 1902206555712638977L);
+//        //机械连接、焊接报告
+//        put("402d59509f78443b88923f9c6876", 1902206715393986562L);
+//        //土工、配合比
+//        put("3650e321d07845e3b1a0a38bc1c2", 1902206873229840386L);
+//
+//
+//
+//        //就安全生产印发的实施方案
+//        put("eadf2038639446dcb40c4fe198c8", 1902198126172426241L);
+//        //2020年至2023年业主就安全生产检查的通报及整改回复
+//        put("9067f2889fbe42d0917f80d20978", 1902198303939612673L);
+
+
+        //=========【第二总监】======================
+
+        //监理抽检资料
+        put("216663852e784ba1a96a2980d663", 1927992314593017861L);
+
+        //交工验收工程质量评定资料
+        put("60c2a98a533842e09625ef74f728", 1927992314593017878L);
+
+        //原材料、设备及构件试验报告、记录
+        //put("6dec0a4c4a8e42a0a2b138e6e4ff", 1902200181465272322L);
+
+        //NoJL2合同段数字化扫描档案
+        //一、监理管理文件
+
+        //一、监理管理文件
+        //(一)质量控制措施、规定
+
+        //(二)质量控制往来文件
+
+        //(三)监理独立抽检资料(试验)
+
+        //(四)监理独立抽检报告
+
+        //三、工程进度计划管理文件
+        put("a341cabc10834e42836424489eb9", 1927992314593017893L);
+        //五、其它文件
+        put("1f452f1671cb4e188b3623924927", 1927992314593017895L);
+        //六、其它资料
+        put("8005d637346d4523b7af12fbaaaf", 1927992314593017903L);
 
-        //决算和审计文件
-        put("442e7e595dce411abd984da1866d", 1892759789381877811L);
 
-        //====监理
-        //=========第一总监
-        //印章启用文件、监理人员变更的函和批复文件
-        put("465c2ebad85e44e9b4217d7ae415", 1892759789402849282L);
-        //工程监理月报(2022年1月至2023年2月)
-        put("ffce00c9bd7443d9b3d6ef63f885", 1902189729003851778L);
-        //监理日志(张换丽)
-        put("6e7ad41e5cd542f893a69ec7cebd", 1902189935200030722L);
-        //监理日志(钟兆革)
-        put("8d818ccbf39247cbb1f49ed3c7b0", 1902190429066743809L);
-
-        //原材料、设备及构件试验报告、记录 1902201113984880642
-        put("89aaa0372cc24d14b3efdd788141", 1902200995105722370L);
-
-
-        //试验检测汇总表
-        put("0b023c2125664791a0511fc587f8", 1902205006567428097L);
-        //原材料、半成品、成品报告
-        put("bbc75d54e5d14b1f8368ce6fb51f", 1902206555712638977L);
-        //机械连接、焊接报告
-        put("402d59509f78443b88923f9c6876", 1902206715393986562L);
-        //土工、配合比
-        put("3650e321d07845e3b1a0a38bc1c2", 1902206873229840386L);
 
+        //=========【第三总监】
         //监理抽检资料
-        put("5d17cfbfcc134319b3bc2251d1cf", 1892759789402849302L);
+        put("91aee6c9b92e4a10806266fa9513", 1927992314593017914L);
+
+        //交工验收工程质量评定资料
+        put("a1029e86a1994ca0b7d6c4d5dbda", 1927992314593017931L);
+//        put("05ac2ef4857f468483924d51f90a", 1902638005113028610L);
+
+        //NoJL3合同段数字化扫描档案
+        //一、监理管理文件
+        put("26314b7d11c44533bea9ad8e277b", 1927992314593017910L);
+
+        //二、工程质量控制文件
+        //(一)质量控制措施、规定
+        put("02bcd9bcbdb044d1ba974bc5f24a", 1927992314593017912L);
+        //(二)质量控制往来文件
+        put("a749afe440a746e1b88594b8bb0b", 1927992314593017913L);
+        //(三)监理独立抽检资料(试验)
+        put("f1ed755800004c4cb46440bc7ecb", 1927992314593017932L);
+        //(四)监理独立抽检报告
+        put("7bb1ceb7d69941e5a22a3343c266", 1927992314593017915L);
+        //三、工程进度计划管理文件
+        put("0d73872e37a14328a667510da2b7", 1927992314593017946L);
+        //五、其它文件
+        put("633076005a33419b935261445a39", 1927992314593017948L);
+        //六、其它资料
+        put("863f42ce1acd4d60b157f6184ee2", 1927992314593017956L);
 
-        //就安全生产印发的实施方案
-        put("eadf2038639446dcb40c4fe198c8", 1902198126172426241L);
-        //2020年至2023年业主就安全生产检查的通报及整改回复
-        put("9067f2889fbe42d0917f80d20978", 1902198303939612673L);
 
 
-        //=========第二总监
 
-        //原材料、设备及构件试验报告、记录
-        put("6dec0a4c4a8e42a0a2b138e6e4ff", 1902200181465272322L);
 
+        //=========【第四总监】
+        //监理抽检资料
+        put("ad7896d5c0b74d988a02c342928c", 1927992314597212165L);
+
+        //交工验收质量评定
+        put("0679ddcea354420e893a00586737", 1927992314597212182L);
 
-        put("216663852e784ba1a96a2980d663", 1892759789407043606L);
 
-        //=========第三总监
-        put("05ac2ef4857f468483924d51f90a", 1902638005113028610L);
 
+        //NoJL4合同段数字化扫描档案
+        //一、监理管理文件
+        put("c46141f9c8dd4116b056a7db6a2d", 1927992314597212161L);
 
-        put("91aee6c9b92e4a10806266fa9513", 1892759789407043641L);
+        //二、工程质量控制文件
+        //(一)质量控制措施、规定
+        put("2dafbff0d0ae43bfa6bb64f35cab", 1927992314597212163L);
+        //(二)质量控制往来文件
+        put("67107bea233a4047a886bfd48014", 1927992314597212164L);
+        //(三)监理独立抽检资料(试验)
+        put("d1d5d934f6eb45eebb1616816cd5", 1927992314597212183L);
+        //(四)监理独立抽检报告
+        put("3a31de201c604f97a66c02836669", 1927992314597212166L);
+        //三、工程进度计划管理文件
+        put("ae9523597eac403ca8d7eb096840", 1927992314597212197L);
+        //五、其它文件
+        put("2ae858ae006443258446ebe892b9", 1927992314597212199L);
+        //六、其它资料
+        put("8c6913b1dacc45fe966a56d2ff56", 1927992314597212207L);
 
-        //=========第四总监
-        put("ad7896d5c0b74d988a02c342928c", 1892759789407043676L);
+
+
+        //=========【机电标总监】
+        //监理抽检资料
+        put("5b8da50309334dcbb8a02b3339bc", 1927992314597212218L);
 
         //交工验收质量评定
-        put("0679ddcea354420e893a00586737", 1892759789407043678L);
+        put("5831fc73d47a4f35b7df75e862df", 1927992314597212235L);
 
-        //管理文件
-        put("c46141f9c8dd4116b056a7db6a2d", 1892759789407043655L);
-        //计划文件
-        put("ae9523597eac403ca8d7eb096840", 1892759789407043679L);
 
 
-        //质量控制措施
-        put("2dafbff0d0ae43bfa6bb64f35cab", 1892759789407043671L);
-        //监理独立抽检
-        put("d1d5d934f6eb45eebb1616816cd5", 1892759789407043672L);
-        //监理独立报告
-        put("3a31de201c604f97a66c02836669", 1892759789407043673L);
+        //===========施工单位归档资料
 
-        //其他文件
-        put("2ae858ae006443258446ebe892b9", 1892759789407043686L);
 
-        //其他资料
-        put("8c6913b1dacc45fe966a56d2ff56", 1915963769346564097L);
 
 
-        //=========机电标总监
-        put("5b8da50309334dcbb8a02b3339bc", 1892759789407043711L);
 
 
 
 
+        //=====================【第一合同段】=======================================================
 
-        //===========施工单位归档资料
-        //=========第四合同段
-          //二工程管理文件
-            //施工准备文件 -1.施工项目部组建、印章启用、人员任命文件,进场人员资质报审文件,施工设备仪器进场报审文件、设备仪器校验、率定文件
-            put("0b0ac82851d7484bba414bb1ccbd", 1892759789415432263L);
-
-            //施工准备文件 -5.工地试验室备案申请表及交通质监部门备案通知书、工地实验室成立、资质、授权
-            put("9144353d740c428ea46ca4228d22", 1892759789415432267L);
-         //三 施工质量控制文件
-            //原材
-            put("54dc995fc9814ecd81f6f25dc936", 1892759789415432282L);
-            //配合比
-             put("5f07af9ef5d14a2781cef179ef7c", 1892759789415432284L);
-            //试验报告
-             put("ffe1d44383ed4f438d29b73b7dbb", 1892759789415432285L);
-             //施工工序资料
-             put("075d3e8a3d48418f959283c55616", 1892759789415432286L);
-         //五 进度控制文件
-          //1 进度计划
-             put("31bc6b0a55cb4c408e292ee0fcdb", 1892759789415432296L);
-
-             //============================
-
-        //=========第三合同段
-            //二工程管理文件
-            //施工准备文件 -1.施工项目部组建、印章启用、人员任命文件,进场人员资质报审文件,施工设备仪器进场报审文件、设备仪器校验、率定文件
-            //put("0b0ac82851d7484bba414bb1ccbd", 1892759789415432263L);
-
-            //三 施工质量控制文件
-            //原材
-            put("da9434c6a86147c0979ef09624dd", 1892759789415432221L);
-            //配合比
-            put("3080795a07544c2c972cc938da1f", 1892759789415432223L);
-            //试验报告
-            //put("ffe1d44383ed4f438d29b73b7dbb", 1892759789415432285L);
-            //施工工序资料
-            put("a1a4ea5ea88549c09c57b6da8e9e", 1892759789415432225L);
-            //五 进度控制文件
-            //1 进度计划
-            //put("31bc6b0a55cb4c408e292ee0fcdb", 1892759789415432296L);
-
-
-        //=========机电标
-        //二工程管理文件
-        //施工准备文件 -1.施工项目部组建、印章启用、人员任命文件,进场人员资质报审文件,施工设备仪器进场报审文件、设备仪器校验、率定文件
-        //put("0b0ac82851d7484bba414bb1ccbd", 1892759789415432263L);
+        //评定
+        put("1984907813174e698cb7d473911d", 1927992893465690119L);
+        //施工工序资料
+        put("a22abc54ff8446e59760309263f7", 1927992893465690135L);
 
-        //三 施工质量控制文
+
+        //【No1合同段数字化扫描档案】
+        //二、工程管理文件
+        put("3f84d392080e4375b0f3a6467b22", 1927992893465690115L);
+
+        //三、施工质量控制文件   (一)工程质量管理文件
+        put("2f1c3a407b64441a83416def6c97", 1927992893465690118L);
+
+        //三、施工质量控制文件 (二)工地试验室成立
+        put("f363c765bab44c6082731d529f7f", 1927992893465690136L);
+
+        //三、施工质量控制文件 (四)仪器校准证书
+        put("4ec32cc441394a48a608571a361f", 1927992893465690137L);
+
+        //三、施工质量控制文件 (五)材料及标准试验
+        put("d5b62eb13097434fab99879ed98a", 1927992893465690120L);
+
+        //三、施工质量控制文件 (六)现场抽检试验检测报告
+        put("426db97ebf1a4de9b28153335342", 1927992893465690138L);
+
+        //四、安全文明施工文件
+        put("ff0f6b6962494df7b7b3f03539b2", 1927992893465690146L);
+
+        //五、进度控制文件
+        put("4fbcf1973adb481a89a36d8b9898", 1927992893465690147L);
+
+        //七、变更文件
+        put("2e203ab2574640c2895ac5196204", 1927992893465690162L);
+        //八、施工原始记录
+        put("f50cb7a3288848a88f99ee87e800", 1927992893465690149L);
+
+        //三 施工质量控制文件
+
+
+        //原材
+//        put("4620774da89544e7b8d815d65c01", 1892759789411237917L);
+//        //各种试验报告
+//        put("1929194d06794a6a940a761561f9", 1892759789411237920L);
+//        //配合比
+//        put("c05b1ab104f44875b264c52e81eb", 1892759789411237919L);
         //试验报告
         //put("ffe1d44383ed4f438d29b73b7dbb", 1892759789415432285L);
+
+
+
+        //=======================【第二合同段】=======================================
+
+        //评定
+        put("f6fb614a515440cb95676d99ce41", 1927992893469884422L);
+
         //施工工序资料
-        put("8a0aa647278548fa9edba59b78c4", 1892759789419626529L);
+        put("4707eb84188443b481398a15e8cf", 1927992893469884438L);
 
 
-        //=========第一合同段
         //二工程管理文件
-        put("3f84d392080e4375b0f3a6467b22", 1892759789411237894L);
 
-        //施工质量文件
-        put("2f1c3a407b64441a83416def6c97", 1892759789411237906L);
 
-        //工地
-        put("f363c765bab44c6082731d529f7f", 1892759789411237916L);
 
-        //仪器
-        put("4ec32cc441394a48a608571a361f", 1892759789411237922L);
 
-        //材料标准试验
-        put("d5b62eb13097434fab99879ed98a", 1915971643921637377L);
+        //三 施工质量控制文件
+        //原材
+        //put("87edcc42ba2b4859a1aec5191080", 1892759789411237978L);
+
+
 
-        //现场抽检
-        put("426db97ebf1a4de9b28153335342", 1915971747701301249L);
+        //【No2合同段数字化扫描档案】
+        //二、工程管理文件
+        put("c2ff86882ea5461084650afc89f4", 1927992893469884418L);
 
-        //安全文明
-        put("ff0f6b6962494df7b7b3f03539b2", 1892759789411237923L);
+        //三、施工质量控制文件   (一)工程质量管理文件
+        put("3b12c00d0fbc4cfbb73804aec5f2", 1927992893469884421L);
 
-        //进度管理文件
-        put("4fbcf1973adb481a89a36d8b9898", 1915965348099366914L);
+        //三、施工质量控制文件 (二)工地试验室成立
+        put("fdbd69cb41f94775b619bdaa3c6e", 1927992893469884439L);
 
-        //变更文件
-        put("2e203ab2574640c2895ac5196204", 1915965498528079873L);
-        //施工原始记录
-        put("f50cb7a3288848a88f99ee87e800", 1915965617583398913L);
+        //三、施工质量控制文件 (四)仪器校准证书
+        put("5501ee640af0481ab4c447dfe201", 1927992893469884440L);
 
-        //三 施工质量控制文件
+        //三、施工质量控制文件 (五)材料及标准试验
+        put("f6fff76903254aeab4511376fed5", 1927992893469884423L);
+
+        //三、施工质量控制文件 (六)现场抽检试验检测报告
+        put("020567726035400a971f95f5a585", 1927992893469884441L);
+
+        //四、安全文明施工文件
+        put("e8e2af76849d4fe392fbfec50156", 1927992893469884449L);
+
+        //五、进度控制文件
+        put("9f7b03959db646f791a1b2581ed2", 1927992893469884450L);
+
+        //七、变更文件
+        put("e04b9db2c50749629bf8a01bf6f3", 1927992893469884465L);
+        //八、施工原始记录
+        put("44c6ef4bacb144d18f06742a2c27", 1927992893469884452L);
+
+        //=========第三合同段================================================
 
         //评定
-        put("1984907813174e698cb7d473911d", 1892759789411237907L);
+        put("0372bb19089347e7aca7683fdd37", 1927992893469884472L);
+
+        //施工工序资料
+        put("a1a4ea5ea88549c09c57b6da8e9e", 1927992893469884488L);
+
+
+        //二工程管理文件
+        //施工准备文件 -1.施工项目部组建、印章启用、人员任命文件,进场人员资质报审文件,施工设备仪器进场报审文件、设备仪器校验、率定文件
+        //put("0b0ac82851d7484bba414bb1ccbd", 1892759789415432263L);
+
+        //三 施工质量控制文件
         //原材
-        put("4620774da89544e7b8d815d65c01", 1892759789411237917L);
-        //各种试验报告
-        put("1929194d06794a6a940a761561f9", 1892759789411237920L);
+        put("da9434c6a86147c0979ef09624dd", 1892759789415432221L);
         //配合比
-        put("c05b1ab104f44875b264c52e81eb", 1892759789411237919L);
+        put("3080795a07544c2c972cc938da1f", 1892759789415432223L);
+
+
+        //No3合同段数字化扫描档案
+        //二、工程管理文件
+        put("a6f86360805e494dbd048f0ade6c", 1927992893469884468L);
+
+        //三、施工质量控制文件   (一)工程质量管理文件
+        put("b3fcf7f41c8c475c951bc9dcca9d", 1927992893469884471L);
+
+        //三、施工质量控制文件 (二)工地试验室成立
+        put("fa8b6b2292df4663b7520e69acc8", 1927992893469884489L);
+
+        //三、施工质量控制文件 (四)仪器校准证书
+        put("837670159d8e46eb997c0bdc786a", 1927992893469884490L);
+
+        //三、施工质量控制文件 (五)材料及标准试验
+        put("cfdf96cdaf474f01924861db5828", 1927992893469884473L);
+
+        //三、施工质量控制文件 (六)现场抽检试验检测报告
+        put("70dda230cbca40a4b34004aa03f5", 1927992893469884491L);
+
+        //四、安全文明施工文件
+        put("a5f598023ed4402ba1859ff8d1fa", 1927992893469884499L);
+
+        //五、进度控制文件
+        put("9f3d46f37d194604925ab6bf1f30", 1927992893469884500L);
+
+        //七、变更文件
+        put("7eccf837cfb649c69086427ef9e3", 1927992893469884515L);
+        //八、施工原始记录
+        put("9706a2a21284470eb9625a0417ce", 1927992893469884502L);
+
         //试验报告
         //put("ffe1d44383ed4f438d29b73b7dbb", 1892759789415432285L);
+
+        //五 进度控制文件
+        //1 进度计划
+        //put("31bc6b0a55cb4c408e292ee0fcdb", 1892759789415432296L);
+
+        //================================【第四合同段】=======================================
+
+        //评定
+        put("ea82c02057f64424948c02a1144f", 1927992893474078726L);
+
         //施工工序资料
-        put("a22abc54ff8446e59760309263f7", 1892759789411237921L);
+        put("075d3e8a3d48418f959283c55616", 1927992893474078742L);
+
+        //No4合同段数字化扫描档案
+        //二工程管理文件
+        put("f0ed754f4068424b9f86a6450674", 1927992893474078722L);
+
+        //二、工程管理文件
+        //(一)工程质量管理文件
+        put("d6862df110b84c18b68c69c84903", 1927992893474078725L);
+
+        //(二)工地试验成立
+        put("30d615fc781244f68f19d2e7c2d3", 1927992893474078743L);
+
+        //(四)仪器校准证书
+        put("2f3bb1a2d7684fae81261f1c68be", 1927992893474078744L);
+
+        //(五)材料及标准试验
+        put("4d5b3a8cb22e422cbc9e89c85a7a", 1927992893474078727L);
+
+        //(六)现场抽检试验检测报告
+        put("d37d15a6893d4f26b7fa326cab98", 1927992893474078745L);
+
+        //四、安全文明施工文件
+        put("eecc8d374650469b87b04af099c3", 1927992893474078753L);
+        //五、进度控制文件
+        put("74a3f78dff114518b3ebd1800562", 1927992893474078754L);
+        //七、变更文件
+        put("c37db7bb196b411ca59b99fad259", 1927992893474078769L);
+        //八、施工原始记录
+        put("04f0816131814923bd4e7d2d2e20", 1927992893474078756L);
 
 
-        //=========第二合同段
         //二工程管理文件
+        //施工准备文件 -1.施工项目部组建、印章启用、人员任命文件,进场人员资质报审文件,施工设备仪器进场报审文件、设备仪器校验、率定文件
+//        put("0b0ac82851d7484bba414bb1ccbd", 1892759789415432263L);
+//
+//        //施工准备文件 -5.工地试验室备案申请表及交通质监部门备案通知书、工地实验室成立、资质、授权
+//        put("9144353d740c428ea46ca4228d22", 1892759789415432267L);
+//        //三 施工质量控制文件
+//        //原材
+//        put("54dc995fc9814ecd81f6f25dc936", 1892759789415432282L);
+//        //配合比
+//        put("5f07af9ef5d14a2781cef179ef7c", 1892759789415432284L);
+//        //试验报告
+//        put("ffe1d44383ed4f438d29b73b7dbb", 1892759789415432285L);
+//
+//        //五 进度控制文件
+//        //1 进度计划
+//        put("31bc6b0a55cb4c408e292ee0fcdb", 1892759789415432296L);
+
+
+        //============================
+
+        //======================【机电标】==============================================
 
-        //三 施工质量控制文件
-        //原材
-        put("87edcc42ba2b4859a1aec5191080", 1892759789411237978L);
+        //评定
+        put("1cb9ca589d2840cba3ce49b18494", 1927992893474078776L);
 
         //施工工序资料
-        put("4707eb84188443b481398a15e8cf", 1892759789411237982L);
+        put("8a0aa647278548fa9edba59b78c4", 1927992893474078792L);
+        //二工程管理文件
+        //施工准备文件 -1.施工项目部组建、印章启用、人员任命文件,进场人员资质报审文件,施工设备仪器进场报审文件、设备仪器校验、率定文件
+        //put("0b0ac82851d7484bba414bb1ccbd", 1892759789415432263L);
+
+        //三 施工质量控制文
+        //试验报告
+        //put("ffe1d44383ed4f438d29b73b7dbb", 1892759789415432285L);
+
 
     }};
 
@@ -310,6 +533,11 @@ public class TransUtil {
         put("relation_typestr", "关系类型");
         put("relationstr", "关系");
         put("relationstrids", "相关实体标识");
+
+        put("fill_user", "创建用户");
+        put("fill_time", "创建时间");
+        put("fill_user1", "修改用户");
+        put("fill_time1", "修改时间");
     }};
 
 

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

@@ -559,7 +559,7 @@
         select uaa.*
         from m_archive_tree_contract 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 and uaa.is_archive = 1
+        where uaa.is_deleted = 0  and matc.is_deleted = 0 and uaa.is_archive = 1
             and matc.project_id = #{vo.projectId}
         <if test="vo.contractId != null and vo.contractId != ''">
             and uaa.contract_id = #{vo.contractId} and matc.contract_id = #{vo.contractId}
@@ -607,7 +607,7 @@
     <select id="pageByArchivesAuto11" resultMap="archivesAutoResultMap">
         select uaa.*
         from m_archive_tree_contract matc left join u_archives_auto uaa on matc.id = uaa.node_id
-        where uaa.is_deleted = 0 and uaa.is_archive = 1
+        where uaa.is_deleted = 0 and matc.is_deleted = 0 and uaa.is_archive = 1
         <if test="vo.queryValue != null and vo.queryValue != ''">
             and (uaa.name like concat('%',#{vo.queryValue},'%') or uaa.file_number like concat('%',#{vo.queryValue},'%'))
         </if>
@@ -1370,7 +1370,7 @@
     <select id="getMetadaFileByFileIds" resultType="java.util.Map">
         SELECT id,file_id
         FROM u_metadata_file
-        WHERE file_id IN
+        WHERE  is_deleted=0 and file_id IN
         <foreach collection="fileIds" item="fileId" open="(" close=")" separator=",">
             #{fileId}
         </foreach>

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

@@ -73,10 +73,10 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
 //        URL_MAP.put("r_Archives_spare", "https://bladex-chongqing-info.oss-cn-hangzhou.aliyuncs.com//upload/20230414/3798f8c3db6f94c8fce63eec8c716d6c.xlsx");
 //        URL_MAP.put("r_Archives_back", "https://bladex-chongqing-info.oss-cn-hangzhou.aliyuncs.com//upload/20230413/31081917b41e12b9b0359f6a9c1755bd.xlsx");
 
-        URL_MAP.put("r_Archives_front", "https://blade-oss-chongqing.oss-cn-shenzhen.aliyuncs.com//upload/20230413/306c87ffc640699aa92d53a5f4e6d632.xlsx");
-        URL_MAP.put("r_Archives_catalog", "https://blade-oss-chongqing.oss-cn-shenzhen.aliyuncs.com//upload/20230413/f2a083fca685c646e4a47daaaa46f04b.xlsx");
-        URL_MAP.put("r_Archives_spare", "https://blade-oss-chongqing.oss-cn-shenzhen.aliyuncs.com//upload/20230414/3798f8c3db6f94c8fce63eec8c716d6c.xlsx");
-        URL_MAP.put("r_Archives_back", "https://blade-oss-chongqing.oss-cn-shenzhen.aliyuncs.com//upload/20230413/31081917b41e12b9b0359f6a9c1755bd.xlsx");
+        URL_MAP.put("r_Archives_front", "https://xinan1.zos.ctyun.cn/blade-oss-chongqing/upload/20230413/306c87ffc640699aa92d53a5f4e6d632.xlsx");
+        URL_MAP.put("r_Archives_catalog", "https://xinan1.zos.ctyun.cn/blade-oss-chongqing/upload/20230413/f2a083fca685c646e4a47daaaa46f04b.xlsx");
+        URL_MAP.put("r_Archives_spare", "https://xinan1.zos.ctyun.cn/blade-oss-chongqing/upload/20230414/3798f8c3db6f94c8fce63eec8c716d6c.xlsx");
+        URL_MAP.put("r_Archives_back", "https://xinan1.zos.ctyun.cn/blade-oss-chongqing/upload/20230413/31081917b41e12b9b0359f6a9c1755bd.xlsx");
 
         NAME_MAP.put("r_Archives_front", "封面");
         NAME_MAP.put("r_Archives_catalog", "卷内目录");
@@ -551,6 +551,18 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
             }
         }
 
+        if ("Archive['secretLevel']".equals(formula)){
+            if (object!= null ) {
+                String strObject = object.toString();
+                if (strObject.contains("null")) {
+                    strObject = strObject.replace("null", "");
+                    object =  strObject;
+                }
+            }else {
+                object = "";
+            }
+        }
+
         dataInfo.put(key, object);
     }
 
@@ -626,7 +638,7 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
                     String myData = DataInfo.get(val) + "";
 
 
-                    if (myData.indexOf("http") >= 0 && (myData.indexOf("aliyuncs") >= 0 ||myData.indexOf("183.247.216.148") >= 0)) {
+                    if (myData.indexOf("http") >= 0 && (myData.indexOf("ctyun") >= 0 ||myData.indexOf("183.247.216.148") >= 0)) {
 
                         InputStream imageIn = CommonUtil.getOSSInputStream(myData);
                         byte[] bytes = IOUtils.toByteArray(imageIn);

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

@@ -729,6 +729,8 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		//步list = {ArrayList@18238}  size = 19骤二:查询归档树节点。存在未归档文件的节点。
 		List<ArchiveTreeContract> list = archiveTreeContractClient.getHavedFileNodeByProjectID(projectId);
 
+		List<ArchiveTreeContract> listTop = archiveTreeContractClient.getTopAutoTypeNodeByProjectID(projectId);
+
 
 		if (nodeId != null) {
 			ArchiveTreeContract node = archiveTreeContractClient.getArchiveTreeContractById(nodeId);
@@ -772,7 +774,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		archiveAutoMethod3(list3, boxMap, boxFileMap, traceId);//单独组卷
 		//设置完成度30%
 		projectClient.updateIsArchivesAutoById(projectId, 30);
-		archiveAutoMethod2(list2, projectId, boxMap, boxFileMap, traceId);//分类组卷
+		archiveAutoMethod2_new(list2, listTop,projectId, boxMap, boxFileMap, traceId);//分类组卷
 		//设置完成度50%
 		projectClient.updateIsArchivesAutoById(projectId, 50);
 		archiveAutoMethod1(list1, boxMap, boxFileMap, traceId);//默认组卷
@@ -1523,13 +1525,117 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		}
 	}
 
+	private void archiveAutoMethod3(List<ArchiveTreeContract> list, Map<String, List<ArchiveFile>> boxMap,
+									Map<Long, String> boxFileMap, Long traceId) {
+		// 步骤1:遍历节点集合
+		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.getListByNodeID(node.getId().toString());
+			if (archiveFiles == null || archiveFiles.isEmpty()) {
+				continue;
+			}
+
+			// 记录节点文件数量日志
+			String completeMsg = "[自动组卷] 单独组卷:" + "-traceId:" + traceId + "节点:" + node.getNodeName() + " 文件数量:" + archiveFiles.size();
+			iTraceLogService.saveLog(traceId, completeMsg);
+
+			// 步骤4:遍历未归档文件
+			List<ArchiveFile> waitArchiveFiles = new ArrayList<>();  // 待组卷文件集合
+			int archivesSize = 0;  // 待组卷文件总页数
+			int archiveFilesSize = 0;
+
+			for (ArchiveFile file : archiveFiles) {
+				archiveFilesSize++;
+
+				// 步骤5:判断文件是否存在分盒设置
+				if (file.getBoxNumber() != null && file.getBoxNumber() != -1) {
+					// 添加到分盒文件集合
+					addBoxMap(file, boxMap, boxFileMap);
+
+					// 如果是最后一个文件且有待组卷文件,则组卷
+					if (archiveFilesSize == archiveFiles.size() && !waitArchiveFiles.isEmpty()) {
+						createArchive3(waitArchiveFiles, node, archivesSize);
+						waitArchiveFiles.clear();
+						archivesSize = 0;
+					}
+				} else {
+					// 非分盒文件处理
+					Integer filePage = file.getFilePage() != null ? file.getFilePage() : 0;
+
+					// 步骤6:检查规格状态
+					int tempTotalSize = archivesSize + filePage;
+					int checkStatus = checkSpecificationSize(specificationSize, tempTotalSize);
+
+					// 6.1 未到规格
+					if (checkStatus == 0) {
+						waitArchiveFiles.add(file);
+						archivesSize = tempTotalSize;
+
+						// 最后一个文件直接组卷
+						if (archiveFilesSize == archiveFiles.size()) {
+							createArchive3(waitArchiveFiles, node, archivesSize);
+							waitArchiveFiles.clear();
+							archivesSize = 0;
+						}
+					}
+					// 6.2 达到规格
+					else if (checkStatus == 1) {
+						waitArchiveFiles.add(file);
+						archivesSize = tempTotalSize;
+						createArchive3(waitArchiveFiles, node, archivesSize);
+
+						// 重置待组卷集合
+						waitArchiveFiles.clear();
+						archivesSize = 0;
+					}
+					// 6.3 超出规格
+					else if (checkStatus == -1) {
+						if (!waitArchiveFiles.isEmpty()) {
+							// 先将现有集合组卷(不含当前文件)
+							createArchive3(waitArchiveFiles, node, archivesSize);
+
+							// 新建集合存放当前文件
+							waitArchiveFiles.clear();
+							waitArchiveFiles.add(file);
+							archivesSize = filePage;
+
+							// 最后一个文件直接组卷
+							if (archiveFilesSize == archiveFiles.size()) {
+								createArchive3(waitArchiveFiles, node, archivesSize);
+								waitArchiveFiles.clear();
+								archivesSize = 0;
+							}
+						} else {
+							// 当前文件单独成卷
+							waitArchiveFiles.add(file);
+							archivesSize = filePage;
+							createArchive3(waitArchiveFiles, node, archivesSize);
+
+							// 重置集合
+							waitArchiveFiles.clear();
+							archivesSize = 0;
+						}
+					}
+				}
+			}
+		}
+	}
+
 	/**
-	 * 单租组卷流程  20230628 SBD又说单独组卷规则节点下只组一卷,不用满规格新组。这辈子没见过这样的人。
+	 * 单租组卷流程  20230628 SBD又说单独组卷规则节点下只组一卷,不用满规格新组。
 	 *
 	 * @param list
 	 * @param boxMap
 	 */
-	private void archiveAutoMethod3(List<ArchiveTreeContract> list, Map<String, List<ArchiveFile>> boxMap, Map<Long, String> boxFileMap, Long traceId) {
+	private void archiveAutoMethod3_1(List<ArchiveTreeContract> list, Map<String, List<ArchiveFile>> boxMap, Map<Long, String> boxFileMap, Long traceId) {
 		//步骤1:遍历节点集合
 		for (ArchiveTreeContract node : list) {
 			//步骤2:查询节点下的未组卷文件
@@ -1623,11 +1729,177 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 			Long archiveAutoGroupId = entry.getKey();
 			List<ArchiveFile> archiveFiles = entry.getValue();
 			//一个archiveAutoGroupId组成一个案卷  案卷归属同个key的归档树节点select=1的第一个groupId2NodeIdMap
-			createArchive2(archiveFiles, archiveAutoGroupId, projectId);
+			//createArchive2(archiveFiles, archiveAutoGroupId, projectId);
+
+			archiveAutoMethodGroup(archiveFiles, archiveAutoGroupId, projectId);
 		}
 
 	}
 
+
+	private void archiveAutoMethod2_new(List<ArchiveTreeContract> list, List<ArchiveTreeContract> topList, Long projectId,
+										Map<String, List<ArchiveFile>> boxMap, Map<Long, String> boxFileMap, Long traceId) {
+
+		// 分类并卷集合<groupId, List<文件>>
+		Map<Long, List<ArchiveFile>> archiveMap = new LinkedHashMap<>();
+		// 记录同个分组id对应的第一个节点ID(案卷归属节点)
+		Map<Long, Long> groupId2NodeIdMap = new HashMap<>();
+
+		// 当前处理的顶层节点ID
+		Long curTopId = null;
+		// 当前顶层节点对应的分组ID
+		Long currArchiveAutoGroupId = null;
+
+		// 步骤1:遍历节点集合
+		for (ArchiveTreeContract node : list) {
+			// 初始化当前节点的分组ID和顶层节点ID
+			Long archiveAutoGroupId = node.getArchiveAutoGroupId();
+			Long nodeTopId = 0L;
+
+			// 步骤2:查找当前节点的顶层节点ID
+			for (ArchiveTreeContract topNode : topList) {
+				Long topId = topNode.getId();
+				// 检查当前节点是否属于此顶层节点
+				if (node.getAncestors() != null &&
+						node.getAncestors().contains(topId.toString())) {
+					nodeTopId = topId;
+					break;
+				}
+			}
+
+			// 步骤3:确定当前节点的分组ID
+			if (curTopId != null && curTopId.equals(nodeTopId) && nodeTopId != 0) {
+				// 如果属于同一个非零顶层节点,使用之前的分组ID
+				archiveAutoGroupId = currArchiveAutoGroupId;
+			} else {
+				// 新顶层节点或没有顶层节点,更新当前分组信息
+				curTopId = nodeTopId;
+				currArchiveAutoGroupId = archiveAutoGroupId;
+			}
+
+			// 步骤4:查询节点下的未归档文件
+			List<ArchiveFile> archiveFiles = archiveFileClient.getListByNodeID(node.getId().toString());
+
+			if (archiveFiles != null && !archiveFiles.isEmpty()) {
+				// 记录日志(每个节点只记录一次)
+				String completeMsg = "[自动组卷] 分类组卷:" + "-traceId:" + traceId + "节点:" + node.getNodeName() + " 文件数量:" + archiveFiles.size();
+				iTraceLogService.saveLog(traceId, completeMsg);
+
+				// 步骤5:遍历未归档文件
+				for (ArchiveFile file : archiveFiles) {
+					// 步骤6:判断文件是否存在分盒设置
+					if (file.getBoxNumber() != null && file.getBoxNumber() != -1) {
+						// 添加到分盒文件集合
+						addBoxMap(file, boxMap, boxFileMap);
+					} else {
+						// 分类并卷流程
+						// 步骤7:将文件按照<groupId,List<文件>>放入集合
+						if (archiveMap.containsKey(archiveAutoGroupId)) {
+							List<ArchiveFile> groupList = archiveMap.get(archiveAutoGroupId);
+							groupList.add(file);
+						} else {
+							List<ArchiveFile> groupList = new ArrayList<>();
+							groupList.add(file);
+							archiveMap.put(archiveAutoGroupId, groupList);
+							groupId2NodeIdMap.put(archiveAutoGroupId, node.getId());
+						}
+					}
+				}
+			}
+		}
+
+		// 步骤8:按集合创建案卷
+		for (Map.Entry<Long, List<ArchiveFile>> entry : archiveMap.entrySet()) {
+			Long archiveAutoGroupId = entry.getKey();
+			List<ArchiveFile> archiveFiles = entry.getValue();
+
+			// 同一个分组ID下的文件分组组卷
+			archiveAutoMethodGroup(archiveFiles, archiveAutoGroupId, projectId);
+		}
+	}
+
+	private void archiveAutoMethodGroup(List<ArchiveFile> archiveFiles, Long archiveAutoGroupId, Long projectId) {
+		if (archiveFiles.size()==0) {
+			return;
+		}
+
+		// 获取分组规格(取第一个文件的节点规格作为分组规格)
+		int specificationSize = 300; // 默认规格(300页)
+		if (archiveFiles.get(0).getNodeId() != null) {
+			// 查询文件所在节点的规格
+			Long nodeId = Long.parseLong(archiveFiles.get(0).getNodeId());
+			ArchiveTreeContract node = archiveTreeContractClient.getArchiveTreeContractById(nodeId);
+			//ArchiveTreeContract node = archiveTreeClient.getNodeById(archiveFiles.get(0).getNodeId());
+			if (node != null && !StringUtils.isEmpty(node.getSpecification())) {
+				try {
+					specificationSize = Integer.parseInt(node.getSpecification()) * 10;
+				} catch (NumberFormatException e) {
+					// 规格格式错误时使用默认值
+					log.error("规格格式错误: {}", node.getSpecification(), e);
+				}
+			}
+		}
+
+		// 待组卷文件集合
+		List<ArchiveFile> waitArchiveFiles = new ArrayList<>();
+		// 待组卷文件总页数
+		int archivesSize = 0;
+
+		// 遍历文件列表
+		int fileIndex = 0;
+		int totalFiles = archiveFiles.size();
+
+		for (ArchiveFile file : archiveFiles) {
+			fileIndex++;
+			// 获取文件页数,处理null值
+			int filePage = file.getFilePage() != null ? file.getFilePage() : 0;
+
+			// 计算临时总页数
+			int tempTotalSize = archivesSize + filePage;
+
+			// 检查规格状态
+			int checkStatus = checkSpecificationSize(specificationSize, tempTotalSize);
+
+			// 处理不同检查状态
+			switch (checkStatus) {
+				case 0: // 未到规格
+					waitArchiveFiles.add(file);
+					archivesSize = tempTotalSize;
+					if (fileIndex == totalFiles) { // 是最后一个文件
+						createArchive2(waitArchiveFiles, archiveAutoGroupId, projectId);
+					}
+					break;
+
+				case 1: // 达到规格
+					waitArchiveFiles.add(file);
+					createArchive2(waitArchiveFiles, archiveAutoGroupId, projectId);
+					waitArchiveFiles = new ArrayList<>();
+					archivesSize = 0;
+					break;
+
+				case -1: // 超出规格
+					if (waitArchiveFiles.isEmpty()) {
+						// 当前文件单独成卷
+						createArchive2(Collections.singletonList(file), archiveAutoGroupId, projectId);
+					} else {
+						// 先将现有文件组卷
+						createArchive2(waitArchiveFiles, archiveAutoGroupId, projectId);
+
+						// 创建新的待组卷集合
+						waitArchiveFiles = new ArrayList<>();
+						waitArchiveFiles.add(file);
+						archivesSize = filePage;
+
+						if (fileIndex == totalFiles) { // 是最后一个文件
+							createArchive2(waitArchiveFiles, archiveAutoGroupId, projectId);
+						}
+					}
+					break;
+			}
+		}
+	}
+
+
 	/**
 	 * 默认组卷流程 文件可以跨节点组卷,受最高并卷节点限制范围,跨节点文件组卷时,案卷规格按照第一个文件所在的节点规格 组卷。
 	 */
@@ -2414,7 +2686,44 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 	 * @param nodeId               筛选条件:节点编号
 	 * @return 符合条件的档案列表
 	 */
+
 	public List<ArchiveTreeContract> archiveTreeContractFilterNum(List<ArchiveTreeContract> archiveTreeContracts, String treeCode, String nodeId, Long contractId) {
+		if (contractId == null) {
+			return archiveTreeContracts;
+		}
+
+		List<ArchiveTreeContract> result = new ArrayList<>();
+		for (ArchiveTreeContract contract : archiveTreeContracts) {
+			// 核心逻辑:nodeId不为空时必须满足祖先/ID条件
+			if (StringUtils.isNotEmpty(nodeId)) {
+				boolean matchesNode = (StringUtils.isNotEmpty(contract.getAncestors()) && contract.getAncestors().contains(nodeId))
+						|| contract.getId().toString().equals(nodeId);
+				if (!matchesNode) {
+					continue; // 不满足node条件直接跳过
+				}
+			}
+
+			// 根据treeCode决定额外条件
+			boolean isOwnerContract = StringUtils.isEmpty(treeCode); // 业主合同段标识
+			boolean passesOwnerCheck = contractId.toString().equals(contract.getTreeCode())
+					|| contractId.equals(contract.getContractId())
+					|| StringUtils.isEmpty(contract.getTreeCode());
+
+			if (isOwnerContract) {
+				// 业主合同段:仅需额外检查(nodeId为空时)
+				if (passesOwnerCheck) {
+					result.add(contract);
+				}
+			} else {
+				// 非业主合同段:treeCode匹配或额外检查
+				if (treeCode.equals(contract.getTreeCode()) || passesOwnerCheck) {
+					result.add(contract);
+				}
+			}
+		}
+		return result;
+	}
+	public List<ArchiveTreeContract> archiveTreeContractFilterNum1(List<ArchiveTreeContract> archiveTreeContracts, String treeCode, String nodeId, Long contractId) {
 		List<ArchiveTreeContract> result = new ArrayList<>();
 
 		if (contractId == null) {

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

@@ -293,7 +293,7 @@ public class FileUtils {
 
             for (String urlStr : urlList) {
                 try {
-                    if (urlStr.indexOf("https") >= 0 && urlStr.indexOf("aliyuncs") >= 0) {
+                    if (urlStr.indexOf("https") >= 0 && urlStr.indexOf("ctyun") >= 0) {
                         int lastIndexOf = urlStr.lastIndexOf("/");
                         String prefix = urlStr.substring(0, lastIndexOf + 1);
                         String suffix = urlStr.substring(lastIndexOf + 1);
@@ -516,7 +516,7 @@ public class FileUtils {
 
                     String fileNameWithoutExtension = fileNameWithExtension.substring(0, fileNameWithExtension.lastIndexOf("."));
 
-                    if (url.indexOf("https") >= 0 && url.indexOf("aliyuncs") >= 0) {
+                    if (url.indexOf("https") >= 0 && url.indexOf("ctyun") >= 0) {
                         int lastIndexOf = url.lastIndexOf("/");
                         String prefix = url.substring(0, lastIndexOf + 1);
                         String suffix = url.substring(lastIndexOf + 1);
@@ -661,7 +661,7 @@ public class FileUtils {
 
                     String fileNameWithoutExtension = fileNameWithExtension.substring(0, fileNameWithExtension.lastIndexOf("."));
 
-                    if (url.indexOf("https") >= 0 && url.indexOf("aliyuncs") >= 0) {
+                    if (url.indexOf("https") >= 0 && url.indexOf("ctyun") >= 0) {
                         int lastIndexOf = url.lastIndexOf("/");
                         String prefix = url.substring(0, lastIndexOf + 1);
                         String suffix = url.substring(lastIndexOf + 1);

+ 224 - 81
blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java

@@ -1784,6 +1784,7 @@ public R<Boolean> copyContractTreeNode(@RequestBody CopyContractTreeNodeVO vo) {
 
             /*获取元素表数据*/
             Map<Long, Map<String, Object>> colMaps = new HashMap<>();
+            Map<Long, String> colMap = new HashMap<>();
             //是否需要复制数据
             if (vo.getIsCopyData() == 1) {
                 //表名集合
@@ -1794,7 +1795,7 @@ public R<Boolean> copyContractTreeNode(@RequestBody CopyContractTreeNodeVO vo) {
                         .collect(Collectors.toList());
                 //表名集合转逗号拼接的字符串
                 String inClausePlaceholders = String.join(",", Collections.nCopies(tabNames.size(), "?"));
-                String sql = "SELECT table_name AS queryType, GROUP_CONCAT(COLUMN_name) AS ancestors " +
+                String sql = "SELECT table_name AS queryType, GROUP_CONCAT(distinct COLUMN_name) AS ancestors " +
                         "FROM information_schema.COLUMNS WHERE table_name IN (" + inClausePlaceholders + ") " +
                         "GROUP BY table_name";
                 Object[] params = tabNames.toArray();
@@ -1823,21 +1824,23 @@ public R<Boolean> copyContractTreeNode(@RequestBody CopyContractTreeNodeVO vo) {
                     List<WbsTreeContract> tabs = tabsGroup.get(tabName);
                     for (WbsTreeContract tab : tabs) {
                         //根据字段
-                        String dataSql = "SELECT " + keys + " FROM " + tabName + " WHERE p_key_id = " + tab.getPKeyId() + " LIMIT 1;";
-                        try {
-                            //查询指定表指定表节点的数据
-                            Map<String, Object> resultMap = jdbcTemplate.queryForMap(dataSql);
-                            //删除空值
-                            resultMap.values().removeIf(value -> value == null || (value instanceof String && ObjectUtil.isEmpty(value)));
-                            colMaps.put(tab.getPKeyId(), resultMap);
-                        } catch (EmptyResultDataAccessException e) {
-                            continuePkeyIds.add(tab.getPKeyId());
-                        }
+//                        String dataSql = "SELECT " + keys + " FROM " + tabName + " WHERE p_key_id = " + tab.getPKeyId() + " LIMIT 1;";
+//                        try {
+//                            //查询指定表指定表节点的数据
+//                            Map<String, Object> resultMap = jdbcTemplate.queryForMap(dataSql);
+//                            //删除空值
+//                            resultMap.values().removeIf(value -> value == null || (value instanceof String && ObjectUtil.isEmpty(value)));
+//                            colMaps.put(tab.getPKeyId(), resultMap);
+//                        } catch (EmptyResultDataAccessException e) {
+//                            continuePkeyIds.add(tab.getPKeyId());
+//                        }
+                        colMap.put(tab.getPKeyId(), keys);
                     }
                 }
                 logger.info("以下元素表没有获取到对应实体表数据,已跳过 ===> 表pKeyId:[{}]", StringUtils.join(continuePkeyIds, ","));
             }
             // 节点+表节点
+            List<WbsTreeContract> wbsParamAndLedgerList = new ArrayList<>();
             for (WbsTreeContract nodeOld : nodeChildAll) {
                 //新节点
                 WbsTreeContract newData = new WbsTreeContract();
@@ -1848,15 +1851,18 @@ public R<Boolean> copyContractTreeNode(@RequestBody CopyContractTreeNodeVO vo) {
                 if (nodeOld.getNodeType() != null && nodeOld.getNodeType() == 6) {
                     //新旧节点关联关系
                     peerMap.put(newData.getPKeyId(), nodeOld.getPKeyId());
-                    //复制节点命名配置
-                    //查询节点绑定的公共配置 文件提名信息
-                    WbsParam wbsParam = wbsParamClient.getWbsParam(Long.parseLong(vo.getNeedCopyPrimaryKeyId()));
-                    if(wbsParam!=null){
-                        wbsParam.setId(SnowFlakeUtil.getId());
-                        wbsParam.setNodeId(newData.getPKeyId());
-                        //给复制的节点绑定的公共配置
-                        wbsParamClient.saveWbsParam(wbsParam);
-                    }
+//                    //复制节点命名配置
+//                    //查询节点绑定的公共配置 文件提名信息
+//                    WbsParam wbsParam = wbsParamClient.getWbsParam(Long.parseLong(vo.getNeedCopyPrimaryKeyId()));
+//                    if(wbsParam!=null){
+//                        wbsParam.setId(SnowFlakeUtil.getId());
+//                        wbsParam.setNodeId(newData.getPKeyId());
+//                        //给复制的节点绑定的公共配置
+//                        wbsParamClient.saveWbsParam(wbsParam);
+//                    }
+//                    /*生成工序节点施工日志*/
+//                    this.createLedger(newData, saveLedger, nodeMap, null);
+                    wbsParamAndLedgerList.add(newData);
                 }
                 //源节点是否为复制节点 如果是则设置源节点的源节点 如何不是设置源节点id
                 if (StringUtils.isNotEmpty(nodeOld.getOldId())) {
@@ -1901,9 +1907,9 @@ public R<Boolean> copyContractTreeNode(@RequestBody CopyContractTreeNodeVO vo) {
                 saveList.add(newData);
 
                 /*生成工序节点施工日志*/
-                if (new Integer("6").equals(nodeOld.getNodeType())) {
-                    this.createLedger(newData, saveLedger, nodeMap, null);
-                }
+//                if (new Integer("6").equals(nodeOld.getNodeType())) {
+//                    this.createLedger(newData, saveLedger, nodeMap, null);
+//                }
 
                 /*处理复制表数据*/
                 if (nodeOld.getType() == 2 && vo.getIsCopyData() == 1
@@ -1911,64 +1917,101 @@ public R<Boolean> copyContractTreeNode(@RequestBody CopyContractTreeNodeVO vo) {
                         && tabOwner.contains(nodeOld.getTableOwner())) {
 
                     /*获取表对应的实体数据*/
-                    Map<String, Object> resultMap = colMaps.getOrDefault(nodeOld.getPKeyId(), null);
-                    if (resultMap == null) {
+//                    Map<String, Object> resultMap = colMaps.getOrDefault(nodeOld.getPKeyId(), null);
+//                    if (resultMap == null) {
+//                        continue;
+//                    }
+                    String keys = colMap.getOrDefault(nodeOld.getPKeyId(), null);
+                    if (keys == null || keys.isEmpty()) {
                         continue;
                     }
-
                     /*重置*/
-                    Map<String, String> eMap = reviseValue(nodeOld, null, ekvMap);
+//                    Map<String, String> eMap = reviseValue(nodeOld, null, ekvMap);
 
                     /*构造复制表数据*/
-                    StringBuilder newString = new StringBuilder();
-                    List<String> keySet = new LinkedList<>();
-                    for (Map.Entry<String, Object> entry : resultMap.entrySet()) {
-                        keySet.add(entry.getKey());
-                        Object value = reviseValue(eMap, entry.getKey(), entry.getValue());
-                        if (value != null) {
-                            if (value.toString().contains("\n")) {
-                                value = value.toString().replace("\n", "\\n");
-                            }
-                            newString.append("'").append(value).append("',");
-                        }
-                    }
-                    if (newString.length() > 0) {
-                        newString.insert(0, ',');
-                        if (newString.charAt(newString.length() - 1) == ',') {
-                            newString.deleteCharAt(newString.length() - 1);
-                        }
-                    }
-                    String keysHaveValue = StringUtils.join(keySet, ",");
-                    if (keysHaveValue.length() > 0) {
-                        keysHaveValue = "," + keysHaveValue;
-                    }
+//                    StringBuilder newString = new StringBuilder();
+//                    List<String> keySet = new LinkedList<>();
+//                    for (Map.Entry<String, Object> entry : resultMap.entrySet()) {
+//                        keySet.add(entry.getKey());
+//                        Object value = reviseValue(eMap, entry.getKey(), entry.getValue());
+//                        if (value != null) {
+//                            if (value.toString().contains("\n")) {
+//                                value = value.toString().replace("\n", "\\n");
+//                            }
+//                            newString.append("'").append(value).append("',");
+//                        }
+//                    }
+//                    if (newString.length() > 0) {
+//                        newString.insert(0, ',');
+//                        if (newString.charAt(newString.length() - 1) == ',') {
+//                            newString.deleteCharAt(newString.length() - 1);
+//                        }
+//                    }
+//                    String keysHaveValue = StringUtils.join(keySet, ",");
+//                    if (keysHaveValue.length() > 0) {
+//                        keysHaveValue = "," + keysHaveValue;
+//                    }
                     //delete SQL (先删除旧数据,再新增)
                     String delSql = "DELETE FROM " + newData.getInitTableName() + " WHERE p_key_id = " + newData.getPKeyId() + " ; ";
                     //insert SQL
+//                    copySql.append(delSql)
+//                            .append("INSERT INTO ")
+//                            .append(newData.getInitTableName())
+//                            .append(" (id,p_key_id,group_id")
+//                            .append(keysHaveValue)
+//                            .append(") VALUES (")
+//                            .append(SnowFlakeUtil.getId()).append(",")
+//                            .append(newData.getPKeyId()).append(",null")
+//                            .append(newString)
+//                            .append(");");
                     copySql.append(delSql)
                             .append("INSERT INTO ")
                             .append(newData.getInitTableName())
-                            .append(" (id,p_key_id,group_id")
-                            .append(keysHaveValue)
-                            .append(") VALUES (")
+                            .append(" (id,p_key_id,group_id,")
+                            .append(keys).append(") select ")
                             .append(SnowFlakeUtil.getId()).append(",")
-                            .append(newData.getPKeyId()).append(",null")
-                            .append(newString)
-                            .append(");");
+                            .append(newData.getPKeyId()).append(",null, ")
+                            .append(keys).append(" from ").append(newData.getInitTableName()).append(" where p_key_id =").append(nodeOld.getPKeyId()).append(" LIMIT 1;");
                 }
 
 
 
+            }
+            if (!wbsParamAndLedgerList.isEmpty()) {
+                //复制节点命名配置
+                //查询节点绑定的公共配置 文件提名信息
+                WbsParam wbsParam = wbsParamClient.getWbsParam(Long.parseLong(vo.getNeedCopyPrimaryKeyId()));
+                List<WbsParam> wbsParamList = new ArrayList<>();
+                wbsParamAndLedgerList.forEach(newData -> {
+                    if(wbsParam!=null){
+                        WbsParam wbsParam1 = new WbsParam();
+                        BeanUtil.copy(wbsParam, wbsParam1);
+                        wbsParam1.setId(SnowFlakeUtil.getId());
+                        wbsParam1.setNodeId(newData.getPKeyId());
+                        //给复制的节点绑定的公共配置
+                        wbsParamList.add(wbsParam1);
+                    }
+                    /*生成工序节点施工日志*/
+                    this.createLedger(newData, saveLedger, nodeMap, null);
+                });
+                wbsParamClient.saveWbsParams(wbsParamList);
             }
 
             //TODO 20250414-lhb-新增 添加祖级字段 ancestorsPId
-            List<WbsTreeContract> contractWbsTreeByContractId = wbsTreeContractClient.getContractWbsTreeByContractId(Long.valueOf(needCopyNode.getContractId()));
-            contractWbsTreeByContractId.addAll(saveList);
-            Map<Long, WbsTreeContract> collect = contractWbsTreeByContractId.stream().collect(Collectors.toMap(WbsTreeContract::getPKeyId, Function.identity()));
-            saveList.forEach(node -> {
-                String correctAncestors = createAncestorsPId(node,collect);;
-                node.setAncestorsPId(correctAncestors);
-            });
+            //因为复制选中节点,所以要查询出选中节点的父节点信息 来组装祖级节点
+            if(needCopyNode != null){
+                Long parentPKeyId = null;
+                String ancestorsPId = null;
+                if(needCopyNode.getPId() == 0L){
+                    ancestorsPId = "0";
+                    parentPKeyId = 0L;
+                }else{
+                    WbsTreeContract parentNode = this.wbsTreeContractClient.getContractNodeByPrimaryKeyId(String.valueOf(needCopyNode.getPId()));
+                    ancestorsPId = parentNode.getAncestorsPId();
+                    parentPKeyId = parentNode.getPKeyId();
+                }
+                attachNodesToTarget(saveList,parentPKeyId,ancestorsPId);
+            }
         }
         needCopyNode.setNodeName(vo.getNeedCopyNodeName());
 
@@ -2136,6 +2179,26 @@ public R<Boolean> copyContractTreeNode(@RequestBody CopyContractTreeNodeVO vo) {
                                     this.addCopyTabData(needCopyNode, toCopyNode, tabOwner, resultTablesData, addTabList, vo.getIsCopyData(), addNewFileTabs);
                                 }
                             }
+
+
+                            /*重构祖级id*/
+                            List<WbsTreeContract> resultAll = new ArrayList<>();
+                            resultAll.addAll(addNodeList);
+                            resultAll.addAll(addTabList);
+                            //因为复制选中节点,所以要查询出选中节点的父节点信息 来组装祖级节点
+                            if(needCopyNode != null && CollectionUtil.isNotEmpty(resultAll)){
+                                Long parentPKeyId = null;
+                                String ancestorsPId = null;
+                                if(needCopyNode.getPId() == 0L){
+                                    ancestorsPId = "0";
+                                    parentPKeyId = 0L;
+                                }else{
+                                    WbsTreeContract parentNode = this.wbsTreeContractClient.getContractNodeByPrimaryKeyId(String.valueOf(toCopyVO.getPrimaryKeyId()));
+                                    ancestorsPId = parentNode.getAncestorsPId();
+                                    parentPKeyId = parentNode.getPKeyId();
+                                }
+                                attachNodesToTarget(resultAll,parentPKeyId,ancestorsPId);
+                            }
                         }
                     }
                 }
@@ -2145,14 +2208,6 @@ public R<Boolean> copyContractTreeNode(@RequestBody CopyContractTreeNodeVO vo) {
                 resultAll.addAll(addNodeList);
                 resultAll.addAll(addTabList);
 
-                //TODO 20250414-lhb-新增
-                List<WbsTreeContract> contractWbsTreeByContractId = wbsTreeContractClient.getContractWbsTreeByContractId(Long.valueOf(contractId));
-                contractWbsTreeByContractId.addAll(resultAll);
-                Map<Long, WbsTreeContract> collect = contractWbsTreeByContractId.stream().collect(Collectors.toMap(WbsTreeContract::getPKeyId, Function.identity()));
-                resultAll.forEach(node -> {
-                    String correctAncestors = createAncestorsPId(node,collect);;
-                    node.setAncestorsPId(correctAncestors);
-                });
 
                 List<WbsTreeContract> allData = this.reBuildAncestors(resultAll);
                 List<WbsTreeContract> nodes = allData.stream().filter(f -> f.getType().equals(1)).collect(Collectors.toList());
@@ -2287,7 +2342,7 @@ private Map<String, String> reviseValue(WbsTreeContract wtc, WbsTreeContract par
             if (!ekvMap.containsKey(tableName)) {
                 Map<String, String> map = ekvMap.computeIfAbsent(wtc.getInitTableName(), K -> new HashMap<>());
                 if (parent == null) {
-                    parent = this.wbsTreeContractClient.getContractWbsTreeByContractIdAndId(wtc.getParentId(), Long.parseLong(wtc.getContractId()));
+                    parent = this.wbsTreeContractClient.getContractWbsTreeByPrimaryKeyId(wtc.getPId());
                 }
                 /*凡是关联了节点参数公式的元素都不复制数据*/
                 List<Map<String, Object>> paramKey = this.jdbcTemplate.queryForList("select DISTINCT b.e_key ek from m_table_info a  join m_wbs_form_element b on a.id=b.f_id  join m_element_formula_mapping c on b.id = c.element_id where a.tab_en_name='" + tableName + "' and b.is_deleted=0 and c.scope=35 and c.is_deleted=0");
@@ -2445,8 +2500,8 @@ private List<WbsTreeContract> reBuildAncestors(List<WbsTreeContract> list) {
 public void addCopyTabFile(Set<WbsTreeContract> addChildNodesTables,
                            Set<WbsTreeContract> addChildNodesTablesOld) {
     //获取所有数据源附件文件
-    List<Long> tabFileIds = addChildNodesTablesOld.stream().distinct().map(WbsTreeContract::getPKeyId).collect(Collectors.toList());
-    Map<String, List<TableFile>> tableFileOldMap = tableFileClient.getTabFilesByTabIds(StringUtils.join(tabFileIds, ",")).stream().collect(Collectors.groupingBy(TableFile::getTabId));
+    List<String> tabFileIds = addChildNodesTablesOld.stream().distinct().map(item -> item.getPKeyId() + "").collect(Collectors.toList());
+    Map<String, List<TableFile>> tableFileOldMap = tableFileClient.getTabFilesByTabIds(tabFileIds).stream().collect(Collectors.groupingBy(TableFile::getTabId));
     if (tableFileOldMap != null && tableFileOldMap.size() > 0) {
         List<TableFile> resultFileData = new ArrayList<>();
         Set<Long> updatePKeyIds = new HashSet<>();
@@ -2738,7 +2793,7 @@ private void addCopyNodesAndTabsBuildData(List<WbsTreeContract> addNodeList, Lis
         List<String> initTabNames = needTabs.stream().map(WbsTreeContract::getInitTableName).distinct().filter(ObjectUtil::isNotEmpty).collect(Collectors.toList());
         String joined = StringUtils.join(initTabNames, ",");
         joined = "'" + joined.replaceAll(",", "','") + "'";
-        Map<String, QueryProcessDataVO> tabColsAllByTabNameMaps = jdbcTemplate.query("SELECT table_name as queryType, GROUP_CONCAT(COLUMN_name) as ancestors from information_schema.COLUMNS where table_name in (" + joined + ") GROUP BY table_name", new BeanPropertyRowMapper<>(QueryProcessDataVO.class)).stream().collect(Collectors.toMap(QueryProcessDataVO::getQueryType, Function.identity()));
+        Map<String, QueryProcessDataVO> tabColsAllByTabNameMaps = jdbcTemplate.query("SELECT table_name as queryType, GROUP_CONCAT(DISTINCT COLUMN_name) as ancestors from information_schema.COLUMNS where table_name in (" + joined + ") GROUP BY table_name", new BeanPropertyRowMapper<>(QueryProcessDataVO.class)).stream().collect(Collectors.toMap(QueryProcessDataVO::getQueryType, Function.identity()));
         for (WbsTreeContract node : needNodes) {
             Long oldId = node.getId();
             //新节点
@@ -3887,13 +3942,7 @@ public R<Boolean> saveContractTreeNode(@RequestBody AddContractTreeNodeVO vo) {
             }
         }
         //TODO 20250414-lhb-新增 添加ancestorsPId字段
-        List<WbsTreeContract> contractWbsTreeByContractId = wbsTreeContractClient.getContractWbsTreeByContractId(Long.valueOf(treeContract.getContractId()));
-        contractWbsTreeByContractId.addAll(saveList);
-        Map<Long, WbsTreeContract> collect = contractWbsTreeByContractId.stream().collect(Collectors.toMap(WbsTreeContract::getPKeyId, Function.identity()));
-        saveList.forEach(node -> {
-            String correctAncestors = createAncestorsPId(node,collect);;
-            node.setAncestorsPId(correctAncestors);
-        });
+        attachNodesToTarget(saveList,treeContract.getPKeyId(),treeContract.getAncestorsPId());
 
         R<Boolean> booleanR = this.saveOrCopyNodeTree(saveList, saveLedger, 2, treeContract);
 
@@ -4803,4 +4852,98 @@ public R<Object> customAddContractNode(@RequestBody CustomAddContractNodeDTO dto
         }
     }
 
+    public void attachNodesToTarget(List<WbsTreeContract> newNodes, Long targetId, String targetAncestors) {
+        // 1. 找到新数据中的顶层节点(新树的根节点)
+        WbsTreeContract newRoot = findRootNode(newNodes);
+
+        // 2. 将新树的根节点绑定到目标节点
+        newRoot.setPId(targetId);
+        newRoot.setAncestorsPId(calculateAncestors(targetAncestors, targetId));
+
+        // 3. 构建映射关系
+        Map<Long, WbsTreeContract> nodeMap = new HashMap<>();
+        Map<Long, List<WbsTreeContract>> childrenMap = new HashMap<>();
+
+        for (WbsTreeContract node : newNodes) {
+            nodeMap.put(node.getPKeyId(), node);
+            childrenMap.computeIfAbsent(node.getPId(), k -> new ArrayList<>()).add(node);
+        }
+
+        // 4. 安全层序遍历(带循环检测)
+        safeBfsTraversal(newRoot, childrenMap, newNodes.size());
+    }
+
+    private void safeBfsTraversal(WbsTreeContract root,
+                                  Map<Long, List<WbsTreeContract>> childrenMap,
+                                  int totalNodes) {
+        Queue<WbsTreeContract> queue = new LinkedList<>();
+        Set<Long> visited = new HashSet<>();  // 已访问节点集合
+        queue.add(root);
+        visited.add(root.getPKeyId());
+
+        int processedCount = 0;  // 已处理节点计数器
+        final int MAX_DEPTH = 100;  // 最大深度保护
+
+        while (!queue.isEmpty()) {
+            WbsTreeContract parent = queue.poll();
+            processedCount++;
+
+            // 安全检测1:防止循环引用导致无限循环
+            if (processedCount > totalNodes * 2) {
+                throw new IllegalStateException("处理节点数超过预期,可能存在循环引用。已处理: "
+                        + processedCount + ",总节点: " + totalNodes);
+            }
+
+            // 安全检测2:防止路径过长
+            if (parent.getAncestorsPId().split(",").length > MAX_DEPTH) {
+                throw new IllegalStateException("祖级路径超过最大深度限制: " + MAX_DEPTH);
+            }
+
+            List<WbsTreeContract> children = childrenMap.get(parent.getPKeyId());
+            if (children == null) continue;
+
+            for (WbsTreeContract child : children) {
+                // 安全检测3:检查循环引用
+                if (visited.contains(child.getPKeyId())) {
+                    throw new IllegalStateException("检测到循环引用: 节点" + child.getPKeyId()
+                            + " -> 节点" + parent.getPKeyId());
+                }
+
+                // 更新祖级路径 = 父路径 + 父ID
+                child.setAncestorsPId(calculateAncestors(parent.getAncestorsPId(), parent.getPKeyId()));
+
+                queue.add(child);
+                visited.add(child.getPKeyId());
+            }
+        }
+
+        // 验证是否处理了所有节点
+        if (processedCount < totalNodes) {
+            throw new IllegalStateException("存在未处理的节点,可能是不连通的子树。已处理: "
+                    + processedCount + ",总节点: " + totalNodes);
+        }
+    }
+
+    private String calculateAncestors(String parentAncestors, Long parentId) {
+        if (parentAncestors == null || parentAncestors.isEmpty()) {
+            return parentId.toString();
+        }
+        return parentAncestors + "," + parentId;
+    }
+
+    private WbsTreeContract findRootNode(List<WbsTreeContract> nodes) {
+        Set<Long> nodeIds = new HashSet<>();
+        for (WbsTreeContract node : nodes) {
+            nodeIds.add(node.getPKeyId());
+        }
+
+        for (WbsTreeContract node : nodes) {
+            Long parentId = node.getPId();
+            // 父节点为空 或 父节点不在当前新数据列表中 → 视为根节点
+            if (parentId == null || !nodeIds.contains(parentId)) {
+                return node;
+            }
+        }
+        throw new IllegalArgumentException("新数据中未找到根节点");
+    }
 }

+ 152 - 0
blade-service/blade-business/src/main/java/org/springblade/business/controller/PrivateStandardController.java

@@ -0,0 +1,152 @@
+package org.springblade.business.controller;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiOperation;
+import org.springblade.business.dto.PrivateStandardDTO;
+import org.springblade.business.entity.PrivateStandard;
+import org.springblade.business.service.PrivateStandardService;
+import org.springblade.common.utils.SnowFlakeUtil;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.secure.BladeUser;
+import org.springblade.core.secure.utils.SecureUtil;
+import org.springblade.core.tool.api.R;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 规范文件夹及规范文件表(UWbsPrivateStandard)表控制层
+ *
+ * @author makejava
+ * @since 2025-06-10 11:09:22
+ */
+@RestController
+@RequestMapping("PrivateStandard")
+@Api(tags = "试验-规范管理-规范文件夹及规范文件接口")
+public class PrivateStandardController {
+    /**
+     * 服务对象
+     */
+    @Resource
+    private PrivateStandardService privateStandardService;
+
+    /**
+     * 分页查询所有数据
+     *
+     * @param query               分页对象
+     * @param privateStandard 查询实体
+     * @return 所有数据
+     */
+    @GetMapping("page")
+    @ApiOperation(value = "分页查询所有数据", notes = "传入分页对象和高级查询对象")
+    public R<IPage<PrivateStandard>> selectAll(Query query, PrivateStandard privateStandard) {
+        try {
+            Page page = new Page(query.getCurrent(), query.getSize());
+            IPage<PrivateStandard> resultPage = this.privateStandardService.page(page, new QueryWrapper<>(privateStandard));
+            return R.data(resultPage);
+        } catch (Exception e) {
+            // 可根据实际需求记录日志或返回特定错误信息
+            return R.fail("查询失败");
+        }
+    }
+
+
+    /**
+     * 通过主键查询单条数据
+     *
+     * @param id 主键
+     * @return 单条数据
+     */
+    @ApiOperation(value = "通过主键查询单条数据", notes = "传入主键Id")
+    @ApiImplicitParam(name = "id", value = "主键id", required = true)
+    @GetMapping("/getById")
+    public R<PrivateStandard> selectOne(Long id) {
+        PrivateStandard byId = this.privateStandardService.getById(id);
+        return R.data(byId);
+    }
+
+    /**
+     * 新增数据
+     *
+     * @param privateStandard 实体对象
+     * @return 新增结果
+     */
+    @PostMapping("add")
+    @ApiOperation(value = "新增数据", notes = "privateStandard")
+    @ApiImplicitParam(name = "privateStandard", value = "实体对象", required = true)
+    public R<Boolean> insert(@RequestPart("data") @Validated PrivateStandardDTO privateStandard,@RequestPart("files") MultipartFile[] files) {
+        privateStandard.setId(SnowFlakeUtil.getId());
+        privateStandard.setFiles(files);
+        if (privateStandard.getType() != 1 && privateStandard.getType() != 2) {
+            return R.fail("类型错误");
+        }
+        if (privateStandard.getType() == 1) {
+            privateStandard.setParentId(0L);
+            if (privateStandard.getPrivateId() == null) {
+                return R.fail("节点不能为空");
+            }
+        } else {
+            if (privateStandard.getParentId() == null) {
+                return R.fail("父级节点不能为空");
+            }
+            if (privateStandard.getIssueDate() == null) {
+                return R.fail("下达日期不能为空");
+            }
+            if (privateStandard.getActualizeDate() == null) {
+                return R.fail("实施日期不能为空");
+            }
+        }
+        boolean save = this.privateStandardService.insert(privateStandard);
+        return R.data(save);
+    }
+
+    /**
+     * 修改数据
+     *
+     * @param privateStandards 实体对象
+     * @return 修改结果
+     */
+    @ApiOperation(value = "修改数据")
+    @PostMapping("edit")
+    @ApiImplicitParam(name = "privateStandards", value = "实体对象", required = true)
+    public R<Boolean> update(@RequestBody @Validated List<PrivateStandardDTO> privateStandards) {
+        BladeUser user = SecureUtil.getUser();
+        privateStandards.forEach(f -> f.setUpdateUser(user.getUserId()));
+        boolean b = this.privateStandardService.update(privateStandards);
+        return R.data(b);
+    }
+
+    /**
+     * 删除数据
+     *
+     * @param id 主键
+     * @return 删除结果
+     */
+    @ApiOperation(value = "删除数据")
+    @GetMapping("/delete")
+    @ApiImplicitParam(name = "id", value = "主键id", required = true)
+    public R<Boolean> delete(Long id) {
+        boolean b = this.privateStandardService.delete(id);
+        return R.data(b);
+    }
+
+    /**
+     * 删除文件
+     */
+    @ApiOperation(value = "删除文件")
+    @GetMapping("/deleteFile")
+    @ApiImplicitParam(name = "id", value = "文件Id", required = true)
+    public R<Boolean> deleteFile(Long id) {
+        boolean b = this.privateStandardService.deleteFile(id);
+        return R.data(b);
+    }
+}
+

+ 199 - 0
blade-service/blade-business/src/main/java/org/springblade/business/controller/StandardInfoController.java

@@ -0,0 +1,199 @@
+package org.springblade.business.controller;
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiOperation;
+import org.springblade.business.dto.StandardInfoDTO;
+import org.springblade.business.dto.StandardInfoJoinDTO;
+import org.springblade.business.dto.StandardInfoPrivateJoinDTO;
+import org.springblade.business.entity.StandardInfo;
+import org.springblade.business.service.StandardInfoService;
+import org.springblade.business.vo.StandardInfoDtoVo;
+import org.springblade.business.vo.StandardInfoPrivateJoinVO;
+import org.springblade.business.vo.StandardInfoVO;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.tool.api.R;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 规范参数管理-基础信息(UStandardInfo)表控制层
+ *
+ * @author makejava
+ * @since 2025-06-11 10:03:01
+ */
+@RestController
+@RequestMapping("uStandardInfo")
+@Api(tags = "试验-规范管理-基础信息接口")
+public class StandardInfoController {
+    /**
+     * 服务对象
+     */
+    @Resource
+    private StandardInfoService uStandardInfoService;
+
+    /**
+     * 分页查询所有数据
+     *
+     * @param query         分页对象
+     * @param standardInfo 查询实体
+     * @return 所有数据
+     */
+    @GetMapping("page")
+    @ApiOperation(value = "分页查询所有数据", notes = "传入分页对象和高级查询对象")
+    public R<IPage<StandardInfoDtoVo>> selectAll(Query query, StandardInfo standardInfo) {
+        IPage<StandardInfoDtoVo> page = this.uStandardInfoService.selectMyPage(query, standardInfo);
+        return R.data(page);
+    }
+
+    /**
+     * 通过主键查询单条数据
+     *
+     * @param id 主键
+     * @return 单条数据
+     */
+    @GetMapping("/getById")
+    @ApiOperation(value = "通过主键查询单条数据", notes = "传入主键Id")
+    @ApiImplicitParam(name = "id", value = "主键", required = true)
+    public R<StandardInfoDTO> selectOne(Long id) {
+        StandardInfoDTO dto = this.uStandardInfoService.selectOne(id);
+        return R.data(dto);
+    }
+
+    /**
+     * 新增数据
+     *
+     * @param standardInfo 实体对象
+     * @return 新增结果
+     */
+    @PostMapping("add")
+    @ApiOperation(value = "新增数据")
+    public R<Boolean> insert(@RequestBody @Validated StandardInfoDTO standardInfo) {
+        Boolean b = this.uStandardInfoService.insert(standardInfo);
+        return R.data(b);
+    }
+
+    /**
+     * 修改数据
+     *
+     * @param standardInfo 实体对象
+     * @return 修改结果
+     */
+    @PostMapping("edit")
+    @ApiOperation(value = "修改数据")
+    public R<Boolean> update(@RequestBody @Validated StandardInfoDTO standardInfo) {
+        Boolean b = this.uStandardInfoService.edit(standardInfo);
+        return R.data(b);
+    }
+
+    /**
+     * 删除数据
+     *
+     * @param id 主键
+     * @return 删除结果
+     */
+    @ApiOperation(value = "删除数据")
+    @ApiImplicitParam(name = "id", value = "主键", required = true)
+    @GetMapping("/delete")
+    public R<Boolean> delete(Long id) {
+        Boolean b = this.uStandardInfoService.delete(id);
+        return R.data(b);
+    }
+
+
+    /**
+     * 条件设置
+     *
+     * @param standardInfoJoins 条件设置对象
+     * @return 结果
+     */
+    @ApiOperation(value = "条件设置")
+    @PostMapping("saveConditionSet")
+    public R<Boolean> setCondition(@RequestBody @Validated List<StandardInfoJoinDTO> standardInfoJoins) {
+        Boolean b = this.uStandardInfoService.setCondition(standardInfoJoins);
+        return R.data(b);
+    }
+
+    /**
+     * 关联元素
+     *
+     * @param standardInfoPrivateJoins 关联元素对象
+     * @return 结果
+     */
+    @ApiOperation(value = "关联元素")
+    @PostMapping("saveElementJoin")
+    public R<Boolean> setElementJoin(@RequestBody @Validated List<StandardInfoPrivateJoinDTO> standardInfoPrivateJoins) {
+        Boolean b = this.uStandardInfoService.setElementJoin(standardInfoPrivateJoins);
+        return R.data(b);
+    }
+
+    /**
+     * 删除条件设置
+     * @param leftId 主关联id
+     * @return 删除结果
+     */
+    @ApiOperation(value = "删除条件设置")
+    @ApiImplicitParam(name = "leftId", value = "主关联id", required = true)
+    @GetMapping("deleteConditionSet")
+    public R<Boolean> deleteConditionSet(Long leftId) {
+        Boolean b = this.uStandardInfoService.deleteConditionSet(leftId);
+        return R.data(b);
+    }
+
+    /**
+     * 删除关联元素
+     * @param leftId 主关联id
+     * @return 删除结果
+     */
+    @ApiOperation(value = "删除关联元素")
+    @ApiImplicitParam(name = "leftId", value = "主关联id", required = true)
+    @GetMapping("deleteElementJoin")
+    public R<Boolean> deleteElementJoin(Long leftId) {
+        Boolean b = this.uStandardInfoService.deleteElementJoin(leftId);
+        return R.data(b);
+    }
+
+    /**
+     * 查询条件设置
+     * @param id 规范文件id
+     */
+    @ApiOperation(value = "查询条件设置")
+    @ApiImplicitParam(name = "id", value = "规范文件id", required = true)
+    @GetMapping("getConditionSet")
+    public R<List<StandardInfoVO>> getConditionSet(Long id) {
+        List<StandardInfoVO> list = this.uStandardInfoService.getConditionSet(id);
+        return R.data(list);
+    }
+
+    /**
+     * 查询关联元素
+     * @param id 规范文件id
+     */
+    @ApiOperation(value = "查询关联元素")
+    @ApiImplicitParam(name = "id", value = "规范文件id", required = true)
+    @GetMapping("getElementJoin")
+    public R<List<StandardInfoPrivateJoinVO>> getElementJoin(Long id) {
+        List<StandardInfoPrivateJoinVO> list = this.uStandardInfoService.getElementJoin(id);
+        return R.data(list);
+    }
+
+    /**
+     * 效果预览
+     * @param ids standardInfo type=1的子级id集合
+     */
+    @ApiOperation(value = "效果预览")
+    @ApiImplicitParam(name = "ids", value = "standardInfo type=2的id集合", required = true)
+    @GetMapping("effectPreview")
+    public R<List<StandardInfoPrivateJoinVO>> effectPreview(String ids) {
+        List<StandardInfoPrivateJoinVO> list = this.uStandardInfoService.effectPreview(ids);
+        return R.data(list);
+    }
+
+
+}
+

+ 20 - 7
blade-service/blade-business/src/main/java/org/springblade/business/controller/TaskController.java

@@ -329,11 +329,16 @@ public class TaskController extends BladeController {
             }
 
             //校验当前项目是否为垂直审批
-            List<Task> taskList = taskService.getBaseMapper().selectList(Wrappers.<Task>lambdaQuery().select(Task::getProjectId, Task::getTaskName, Task::getProcessInstanceId, Task::getContractId, Task::getFormDataId).in(Task::getId, Arrays.asList(taskIdArray)));
+            List<String> taskIdList = new ArrayList<>();
+            List<Task> taskList = taskService.getBaseMapper().selectList(Wrappers.<Task>lambdaQuery().select(Task::getId,Task::getProjectId, Task::getTaskName, Task::getProcessInstanceId, Task::getContractId, Task::getFormDataId, Task::getStatus).in(Task::getId, Arrays.asList(taskIdArray)));
             for (Task task : taskList) {
                 if (ObjectUtil.isEmpty(task.getProjectId())) {
                     throw new ServiceException("未获取到任务【" + task.getTaskName() + "】对应的项目信息");
                 }
+                if (task.getStatus() != null && task.getStatus() == 3) {
+                    taskIdList.add(task.getId() + "");
+                    continue;
+                }
                 ProjectInfo projectInfo = jdbcTemplate.query("select approval_type from m_project_info where id = " + task.getProjectId(), new BeanPropertyRowMapper<>(ProjectInfo.class)).stream().findAny().orElse(null);
                 //如果是垂直审批,那么检查当前用户是否符合当前顺序
                 if (projectInfo != null && projectInfo.getApprovalType() != null && new Integer(1).equals(projectInfo.getApprovalType())) {
@@ -369,6 +374,9 @@ public class TaskController extends BladeController {
             List<TaskApprovalVO> taskApprovalVOS = new ArrayList<>();
 
             for (int i = 0, l = taskIdArray.length; i < l; i++) {
+                if (taskIdList.contains(taskIdArray[i])) {
+                    continue;
+                }
                 TaskApprovalVO approvalVO = new TaskApprovalVO();
                 approvalVO.setTaskId(taskIdArray[i]);
                 approvalVO.setParallelProcessInstanceId(parallelProcessInstanceIdArray[i]);
@@ -384,7 +392,7 @@ public class TaskController extends BladeController {
             this.taskService.batchCompleteApprovalTask(taskApprovalVOS);
             Map<String, TaskApprovalVO> taskApprovalVOMap = taskApprovalVOS.stream().collect(Collectors.toMap(TaskApprovalVO::getTaskId, taskApprovalVO -> taskApprovalVO, (o1, o2) -> o1));
             for (Task task : taskList) {
-                if (batchTaskVO.getFlag().equals("NO")) {
+                if (batchTaskVO.getFlag().equals("NO") && task.getStatus() != null && task.getStatus() != 3) {
                     JSONObject json = new JSONObject();
                     json.put("operationObjIds", Func.toStrList(task.getFormDataId()));
                     json.put("operationObjName", "批量废除");
@@ -1233,9 +1241,12 @@ public class TaskController extends BladeController {
         //生成等待批次,任务完成后删除
         List<TaskApprovalVO> taskApprovalVOS = new ArrayList<>();
         taskApprovalVOS.add(taskApprovalVO);
+        Task task = taskService.getOne(Wrappers.<Task>lambdaQuery().eq(Task::getId, taskApprovalVO.getTaskId()));
+        if (task == null || (task.getStatus() != null && task.getStatus() == 3)) {
+            return R.fail("任务已被撤回或者驳回");
+        }
         this.taskService.batchCompleteApprovalTask(taskApprovalVOS);
         if (!taskApprovalVO.isPass()) {
-            Task task = taskService.getBaseMapper().selectOne(Wrappers.<Task>lambdaQuery().select(Task::getProjectId, Task::getContractId, Task::getFormDataId).eq(Task::getId, taskApprovalVO.getTaskId()));
             JSONObject json = new JSONObject();
             json.put("operationObjIds", Func.toStrList(task.getFormDataId()));
             json.put("operationObjName", "批量废除");
@@ -1539,23 +1550,25 @@ public class TaskController extends BladeController {
                             .min(Comparator.comparing(t -> t.getCreateTime().getTime() - createTime.getTime()));
                     if (min.isPresent()){
                         OperationLog operationLog = min.get();
+                        String createUserName = operationLog.getCreateUserName();
+                        String date = DateUtil.formatDateTime(operationLog.getCreateTime());
                         if (operationLog.getOperationType() != null && operationLog.getOperationType() == 61) {
-                            businessTaskPageVO.setEVisaStatus("驳回成功:"+operationLog.getCreateUserName()+"-"+operationLog.getCreateTime());
+                            businessTaskPageVO.setEVisaStatus("驳回成功:"+ createUserName +"-"+ date);
                             String saveData = operationLog.getSaveData();
                             if (saveData != null && !saveData.isEmpty()) {
                                 try  {
                                     JSONObject data = JSONObject.parseObject(saveData);
                                     if (data != null && data.containsKey("comment")) {
-                                        businessTaskPageVO.setEVisaStatus("驳回成功:"+operationLog.getCreateUserName()+"-"+operationLog.getCreateTime() + ";驳回原因:"+data.getString("comment"));
+                                        businessTaskPageVO.setEVisaStatus("驳回成功:"+ createUserName +"-"+ date + ";驳回原因:"+data.getString("comment"));
                                     }
                                 } catch (Exception e) {
                                     e.printStackTrace();
                                 }
                             }
                         } else if (operationLog.getOperationType() != null && operationLog.getOperationType() == 62) {
-                            businessTaskPageVO.setEVisaStatus("撤回成功:"+operationLog.getCreateUserName()+"-"+operationLog.getCreateTime());
+                            businessTaskPageVO.setEVisaStatus("撤回成功:"+ createUserName +"-"+ date);
                         } else {
-                            businessTaskPageVO.setEVisaStatus(businessTaskPageVO.getEVisaStatus()+":"+operationLog.getCreateUserName()+"-"+operationLog.getCreateTime());
+                            businessTaskPageVO.setEVisaStatus(businessTaskPageVO.getEVisaStatus()+":"+ createUserName +"-"+ date);
                         }
                     }
                 }

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

@@ -452,7 +452,7 @@
                 LEFT JOIN m_archive_tree_contract ar on u.node_id = ar.id
         where 	u.contract_id = #{contractId} and u.classify = #{classify}
           AND u.is_deleted = 0
-          AND u.source_type = 1 and ar.is_deleted = 0;
+          AND u.source_type = 1 and ar.is_deleted = 0  order by u.sort,u.sort_num,u.create_time
     </select>
 
     <select id="getListByContractId1" resultType="org.springblade.business.entity.ArchiveFile">

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

@@ -923,7 +923,7 @@
 
     <!--获取当前节点下,所有表单的字段数据-->
     <select id="getNodeChildTabColsAllByTabName" resultMap="queryProcessDataMap">
-        SELECT table_name as queryType, GROUP_CONCAT(COLUMN_name) as ancestors
+        SELECT table_name as queryType, GROUP_CONCAT(distinct COLUMN_name) as ancestors
         from information_schema.COLUMNS
         where table_name
                   in (#{tabName})

+ 20 - 0
blade-service/blade-business/src/main/java/org/springblade/business/mapper/PrivateStandardMapper.java

@@ -0,0 +1,20 @@
+package org.springblade.business.mapper;
+
+import org.apache.ibatis.annotations.Param;
+import org.springblade.business.entity.PrivateStandard;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+* @author LHB
+* @description 针对表【u_wbs_private_standard(规范文件夹及规范文件表)】的数据库操作Mapper
+* @createDate 2025-06-10 10:48:37
+* @Entity generator.domain.UWbsPrivateStandard
+*/
+public interface PrivateStandardMapper extends BaseMapper<PrivateStandard> {
+
+    void updateStatus(@Param("parentId") Long parentId);
+}
+
+
+
+

+ 35 - 0
blade-service/blade-business/src/main/java/org/springblade/business/mapper/PrivateStandardMapper.xml

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.business.mapper.PrivateStandardMapper">
+
+    <resultMap id="BaseResultMap" type="org.springblade.business.entity.PrivateStandard">
+            <id property="id" column="id" />
+            <result property="name" column="name" />
+            <result property="parentId" column="parent_id" />
+            <result property="privateId" column="private_id" />
+            <result property="type" column="type" />
+            <result property="issueDate" column="issue_date" />
+            <result property="actualizeDate" column="actualize_date" />
+            <result property="isDeleted" column="is_deleted" />
+            <result property="createTime" column="create_time" />
+            <result property="createUser" column="create_user" />
+            <result property="updateTime" column="update_time" />
+            <result property="updateUser" column="update_user" />
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,name,parent_id,private_id,type,issue_date,
+        actualize_date,is_deleted,create_time,create_user,
+        update_time,update_user
+    </sql>
+    <update id="updateStatus">
+        UPDATE u_wbs_private_standard
+        SET `status` = 2,
+            `name` = concat( NAME, '-已过期' )
+        WHERE
+            parent_id = #{parentId}
+          AND STATUS = 1
+    </update>
+</mapper>

+ 18 - 0
blade-service/blade-business/src/main/java/org/springblade/business/mapper/StandardFileMapper.java

@@ -0,0 +1,18 @@
+package org.springblade.business.mapper;
+
+import org.springblade.business.entity.StandardFile;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+* @author LHB
+* @description 针对表【u_standard_file(规范文件表)】的数据库操作Mapper
+* @createDate 2025-06-13 09:24:14
+* @Entity generator.domain.UStandardFile
+*/
+public interface StandardFileMapper extends BaseMapper<StandardFile> {
+
+}
+
+
+
+

+ 23 - 0
blade-service/blade-business/src/main/java/org/springblade/business/mapper/StandardFileMapper.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.business.mapper.StandardFileMapper">
+
+    <resultMap id="BaseResultMap" type="org.springblade.business.entity.StandardFile">
+            <id property="id" column="id" />
+            <result property="standardId" column="standard_id" />
+            <result property="fileName" column="file_name" />
+            <result property="standardFileUrl" column="standard_file_url" />
+            <result property="isDeleted" column="is_deleted" />
+            <result property="createTime" column="create_time" />
+            <result property="createUser" column="create_user" />
+            <result property="updateTime" column="update_time" />
+            <result property="updateUser" column="update_user" />
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,standard_id,file_name,standard_file_url,is_deleted,create_time,
+        create_user,update_time,update_user
+    </sql>
+</mapper>

+ 28 - 0
blade-service/blade-business/src/main/java/org/springblade/business/mapper/StandardInfoJoinMapper.java

@@ -0,0 +1,28 @@
+package org.springblade.business.mapper;
+
+import org.apache.ibatis.annotations.Param;
+import org.springblade.business.entity.StandardInfoJoin;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+* @author LHB
+* @description 针对表【u_standard_info_join(样品信息关联表)】的数据库操作Mapper
+* @createDate 2025-06-11 09:57:39
+* @Entity org.springblade.business.entity.UStandardInfoJoin
+*/
+public interface StandardInfoJoinMapper extends BaseMapper<StandardInfoJoin> {
+
+    /**
+     * 软删除
+     * @param userId 用户 id
+     * @param isDeleted 删除状态
+     * @param standardId 规范文件id
+     */
+    void updateJoin(@Param("userId") Long userId,
+                    @Param("isDeleted") int isDeleted,
+                    @Param("standardId") Long standardId);
+}
+
+
+
+

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

@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.business.mapper.StandardInfoJoinMapper">
+
+    <resultMap id="BaseResultMap" type="org.springblade.business.entity.StandardInfoJoin">
+            <id property="id" column="id" />
+            <result property="standardInfoLeftId" column="standard_info_left_id" />
+            <result property="standardInfoRightId" column="standard_info_right_id" />
+            <result property="isDeleted" column="is_deleted" />
+            <result property="createTime" column="create_time" />
+            <result property="createUser" column="create_user" />
+            <result property="updateTime" column="update_time" />
+            <result property="updateUser" column="update_user" />
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,standard_info_left_id,standard_info_right_id,is_deleted,create_time,create_user,
+        update_time,update_user
+    </sql>
+    <update id="updateJoin">
+        UPDATE u_standard_info_join a
+            INNER JOIN u_standard_info b ON a.standard_info_left_id = b.id
+        SET a.is_deleted = #{isDeleted},
+            a.update_user = #{userId}
+        WHERE
+            b.is_deleted = 0
+          AND b.standard_id = #{standardId}
+    </update>
+</mapper>

+ 36 - 0
blade-service/blade-business/src/main/java/org/springblade/business/mapper/StandardInfoMapper.java

@@ -0,0 +1,36 @@
+package org.springblade.business.mapper;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import org.springblade.business.dto.StandardInfoDTO;
+import org.springblade.business.entity.StandardInfo;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springblade.business.vo.StandardInfoDtoVo;
+import org.springblade.business.vo.StandardInfoPrivateJoinVO;
+import org.springblade.business.vo.StandardInfoVO;
+
+import java.util.List;
+
+/**
+* @author LHB
+* @description 针对表【u_standard_info(规范参数管理-基础信息)】的数据库操作Mapper
+* @createDate 2025-06-11 09:57:39
+* @Entity org.springblade.business.entity.UStandardInfo
+*/
+public interface StandardInfoMapper extends BaseMapper<StandardInfo> {
+
+    IPage<StandardInfoDtoVo> selectMyPage(Page<StandardInfoDtoVo> page, @Param("query") StandardInfo standardInfo);
+
+    StandardInfoDTO selectMyOne(@Param("id") Long id);
+
+    List<StandardInfoVO> getConditionSet(@Param("id") Long id);
+
+    List<StandardInfoPrivateJoinVO> getElementJoin(@Param("id") Long id);
+
+    List<StandardInfoPrivateJoinVO> effectPreview(@Param("rightIds") List<Long> rightIds);
+}
+
+
+
+

+ 193 - 0
blade-service/blade-business/src/main/java/org/springblade/business/mapper/StandardInfoMapper.xml

@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.business.mapper.StandardInfoMapper">
+
+    <resultMap id="BaseResultMap" type="org.springblade.business.entity.StandardInfo">
+        <id property="id" column="id"/>
+        <result property="name" column="name"/>
+        <result property="symbol" column="symbol"/>
+        <result property="parentId" column="parent_id"/>
+        <result property="type" column="type"/>
+        <result property="isDeleted" column="is_deleted"/>
+        <result property="createTime" column="create_time"/>
+        <result property="createUser" column="create_user"/>
+        <result property="updateTime" column="update_time"/>
+        <result property="updateUser" column="update_user"/>
+    </resultMap>
+    <resultMap id="BaseResultPageMap" type="org.springblade.business.vo.StandardInfoDtoVo">
+        <id property="id" column="id"/>
+        <result property="name" column="name"/>
+        <result property="symbol" column="symbol"/>
+        <result property="parentId" column="parent_id"/>
+        <result property="standardId" column="standard_id"/>
+        <result property="type" column="type"/>
+        <result property="isDeleted" column="is_deleted"/>
+        <result property="createTime" column="create_time"/>
+        <result property="createUser" column="create_user"/>
+        <result property="updateTime" column="update_time"/>
+        <result property="updateUser" column="update_user"/>
+        <result property="symbolName" column="symbolName"/>
+        <collection property="info" ofType="org.springblade.business.entity.StandardInfo" select="findByParentId" column="{parentId=id}">
+        </collection>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id
+        ,name,symbol,parent_id,standard_id,type,is_deleted,create_time,
+        create_user,update_time,update_user
+    </sql>
+    <select id="selectMyPage" resultMap="BaseResultPageMap">
+        SELECT
+            <include refid="Base_Column_List"/>,concat(symbol,name) symbolName
+        FROM
+            u_standard_info
+        <where>
+            is_deleted = 0
+            <if test="query.type != null">
+                AND type = #{query.type}
+            </if>
+            <choose>
+                <when test="query.parentId != null">
+                    AND parent_id = #{query.parentId}
+                </when>
+                <otherwise>
+                    AND parent_id = 0
+                </otherwise>
+            </choose>
+            <if test="query.standardId != null">
+                AND standard_id =  #{query.standardId}
+            </if>
+        </where>
+    </select>
+    <select id="selectMyOne" resultMap="BaseResultPageMap">
+        SELECT
+            <include refid="Base_Column_List"/>,concat(symbol,name) symbolName
+        FROM
+            u_standard_info
+        WHERE
+            is_deleted = 0 AND
+            id = #{id}
+    </select>
+    <select id="findByParentId" resultType="org.springblade.business.entity.StandardInfo">
+        select
+            <include refid="Base_Column_List"/>,concat(symbol,name) symbolName
+        FROM
+            u_standard_info
+        WHERE
+            is_deleted = 0
+            AND parent_id = #{parentId}
+    </select>
+
+
+
+
+    <!-- ``````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` -->
+
+    <resultMap id="BaseResultConditionSet" type="org.springblade.business.vo.StandardInfoVO">
+        <id property="id" column="id"/>
+        <result property="name" column="name"/>
+        <result property="parentId" column="parent_id"/>
+        <result property="type" column="type"/>
+        <collection property="standardInfos" ofType="org.springblade.business.entity.StandardInfo" select="findByJoinLeftId" column="{leftId=id}">
+        </collection>
+    </resultMap>
+    <sql id="Base_Column_Join_List">
+        a.id,
+        a.`name`,
+        a.parent_id,
+        a.standard_id,
+        a.`type`,
+        a.is_deleted,
+        a.create_time,
+        a.create_user,
+        a.update_time,
+        a.update_user
+    </sql>
+
+    <select id="getConditionSet" resultMap="BaseResultConditionSet">
+        select
+            <include refid="Base_Column_Join_List"/>
+        from
+            u_standard_info a
+            INNER JOIN u_standard_info_join b on a.id = b.standard_info_left_id and a.is_deleted = b.is_deleted
+        where
+            a.standard_id = #{id} and a.is_deleted = 0
+        GROUP BY
+            b.standard_info_left_id
+    </select>
+    <select id="findByJoinLeftId" resultType="org.springblade.business.entity.StandardInfo">
+        SELECT
+            <include refid="Base_Column_Join_List"/>, c.name parentName
+        FROM
+            u_standard_info a
+            INNER JOIN u_standard_info_join b ON a.id = b.standard_info_right_id AND a.is_deleted = b.is_deleted
+            INNER JOIN u_standard_info c ON a.parent_id = c.id AND a.is_deleted = c.is_deleted
+        WHERE
+            b.standard_info_left_id = #{leftId} and a.is_deleted = 0
+    </select>
+
+    <!-- ``````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` -->
+
+    <resultMap id="BaseResultElementJoin" type="org.springblade.business.vo.StandardInfoPrivateJoinVO">
+        <id property="id" column="id"/>
+        <result property="name" column="name"/>
+        <result property="parentId" column="parent_id"/>
+        <result property="type" column="type"/>
+        <collection property="privateJoins" ofType="org.springblade.business.entity.StandardInfoPrivateJoin" select="findByPrivateJoinLeftId" column="{leftId=id}">
+        </collection>
+    </resultMap>
+
+    <sql id="Base_Private_Column_List">
+        a.id,
+        a.standard_info_id,
+        a.private_id,
+        a.col_key,
+        a.col_name,
+        a.is_deleted,
+        a.create_time,
+        a.create_user,
+        a.update_time,
+        a.update_user
+    </sql>
+    <select id="getElementJoin" resultMap="BaseResultElementJoin">
+        select
+            <include refid="Base_Column_Join_List"/>
+        from
+            u_standard_info a
+            INNER JOIN u_standard_info_private_join b on a.id = b.standard_info_id and a.is_deleted = b.is_deleted
+        where
+            a.standard_id = #{id} and a.is_deleted = 0
+        GROUP BY
+            b.standard_info_id
+    </select>
+
+    <select id="findByPrivateJoinLeftId" resultType="org.springblade.business.entity.StandardInfoPrivateJoin">
+        SELECT
+            <include refid="Base_Private_Column_List"/>,
+            b.node_name privateName
+        FROM
+            u_standard_info_private_join a
+            INNER JOIN m_wbs_tree_private b ON a.private_id = b.p_key_id AND a.is_deleted = b.is_deleted
+        WHERE
+            a.standard_info_id = #{leftId}
+          AND a.is_deleted = 0
+    </select>
+    <select id="effectPreview" resultMap="BaseResultElementJoin">
+        SELECT
+            a.*
+        FROM
+            u_standard_info a
+                INNER JOIN u_standard_info_join b ON a.id = b.standard_info_left_id
+                AND a.is_deleted = b.is_deleted
+        WHERE
+            a.is_deleted = 0
+            AND b.standard_info_right_id in
+            <foreach item="item" collection="rightIds" separator="," open="(" close=")" index="index">
+                #{item}
+            </foreach>
+        GROUP BY
+            b.standard_info_left_id
+    </select>
+</mapper>

+ 28 - 0
blade-service/blade-business/src/main/java/org/springblade/business/mapper/StandardInfoPrivateJoinMapper.java

@@ -0,0 +1,28 @@
+package org.springblade.business.mapper;
+
+import org.apache.ibatis.annotations.Param;
+import org.springblade.business.entity.StandardInfoPrivateJoin;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+* @author LHB
+* @description 针对表【u_standard_info_private_join(样品信息与试验表 关联表)】的数据库操作Mapper
+* @createDate 2025-06-11 09:57:39
+* @Entity org.springblade.business.entity.UStandardInfoPrivateJoin
+*/
+public interface StandardInfoPrivateJoinMapper extends BaseMapper<StandardInfoPrivateJoin> {
+
+    /**
+     * 软删除
+     * @param userId 用户 id
+     * @param isDeleted 删除状态
+     * @param standardId 规范文件id
+     */
+    void updateJoin(@Param("userId") Long userId,
+                    @Param("isDeleted") int isDeleted,
+                    @Param("standardId") Long standardId);
+}
+
+
+
+

+ 33 - 0
blade-service/blade-business/src/main/java/org/springblade/business/mapper/StandardInfoPrivateJoinMapper.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.business.mapper.StandardInfoPrivateJoinMapper">
+
+    <resultMap id="BaseResultMap" type="org.springblade.business.entity.StandardInfoPrivateJoin">
+            <id property="id" column="id" />
+            <result property="standardInfoId" column="standard_info_id" />
+            <result property="privateId" column="private_id" />
+            <result property="colKey" column="col_key" />
+            <result property="colName" column="col_name" />
+            <result property="isDeleted" column="is_deleted" />
+            <result property="createTime" column="create_time" />
+            <result property="createUser" column="create_user" />
+            <result property="updateTime" column="update_time" />
+            <result property="updateUser" column="update_user" />
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,standard_info_id,private_id,col_key,col_name,is_deleted,
+        create_time,create_user,update_time,update_user
+    </sql>
+    <update id="updateJoin">
+        UPDATE u_standard_info_private_join a
+            INNER JOIN u_standard_info b ON a.standard_info_id = b.id
+        SET a.is_deleted = #{isDeleted},
+            a.update_user = #{userId}
+        WHERE
+            b.is_deleted = 0
+          AND b.standard_id = #{standardId}
+    </update>
+</mapper>

+ 23 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/PrivateStandardService.java

@@ -0,0 +1,23 @@
+package org.springblade.business.service;
+
+import org.springblade.business.dto.PrivateStandardDTO;
+import org.springblade.business.entity.PrivateStandard;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+import java.util.List;
+
+/**
+* @author LHB
+* @description 针对表【u_wbs_private_standard(规范文件夹及规范文件表)】的数据库操作Service
+* @createDate 2025-06-10 10:48:37
+*/
+public interface PrivateStandardService extends IService<PrivateStandard> {
+
+    boolean delete(Long id);
+
+    boolean insert(PrivateStandardDTO uWbsPrivateStandard);
+
+    boolean update(List<PrivateStandardDTO> privateStandards);
+
+    boolean deleteFile(Long id);
+}

+ 13 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/StandardFileService.java

@@ -0,0 +1,13 @@
+package org.springblade.business.service;
+
+import org.springblade.business.entity.StandardFile;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+* @author LHB
+* @description 针对表【u_standard_file(规范文件表)】的数据库操作Service
+* @createDate 2025-06-13 09:24:14
+*/
+public interface StandardFileService extends IService<StandardFile> {
+
+}

+ 10 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/StandardInfoJoinService.java

@@ -0,0 +1,10 @@
+package org.springblade.business.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.springblade.business.entity.StandardInfoJoin;
+
+/**
+ * @author LHB
+ */
+public interface StandardInfoJoinService extends IService<StandardInfoJoin> {
+}

+ 10 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/StandardInfoPrivateJoinService.java

@@ -0,0 +1,10 @@
+package org.springblade.business.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.springblade.business.entity.StandardInfoPrivateJoin;
+
+/**
+ * @author LHB
+ */
+public interface StandardInfoPrivateJoinService extends IService<StandardInfoPrivateJoin> {
+}

+ 46 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/StandardInfoService.java

@@ -0,0 +1,46 @@
+package org.springblade.business.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springblade.business.dto.StandardInfoJoinDTO;
+import org.springblade.business.dto.StandardInfoPrivateJoinDTO;
+import org.springblade.business.dto.StandardInfoDTO;
+import org.springblade.business.entity.StandardInfo;
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.springblade.business.vo.StandardInfoDtoVo;
+import org.springblade.business.vo.StandardInfoPrivateJoinVO;
+import org.springblade.business.vo.StandardInfoVO;
+import org.springblade.core.mp.support.Query;
+
+import java.util.List;
+
+/**
+* @author LHB
+* @description 针对表【u_standard_info(规范参数管理-基础信息)】的数据库操作Service
+* @createDate 2025-06-11 09:57:39
+*/
+public interface StandardInfoService extends IService<StandardInfo> {
+
+    IPage<StandardInfoDtoVo> selectMyPage(Query query, StandardInfo standardInfo);
+
+    StandardInfoDTO selectOne(Long id);
+
+    Boolean insert(StandardInfoDTO uStandardInfo);
+
+    Boolean edit(StandardInfoDTO uStandardInfo);
+
+    Boolean delete(Long id);
+
+    Boolean setCondition(List<StandardInfoJoinDTO> standardInfoJoins);
+
+    Boolean setElementJoin(List<StandardInfoPrivateJoinDTO> standardInfoPrivateJoins);
+
+    Boolean deleteConditionSet(Long leftId);
+
+    Boolean deleteElementJoin(Long leftId);
+
+    List<StandardInfoVO> getConditionSet(Long id);
+
+    List<StandardInfoPrivateJoinVO> getElementJoin(Long id);
+
+    List<StandardInfoPrivateJoinVO> effectPreview(String ids);
+}

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

@@ -1091,6 +1091,8 @@ public class InformationQueryServiceImpl extends BaseServiceImpl<InformationQuer
                         informationQuery.setReportNumber(null);
                         informationQuery.setAuditUserIdAndName(null);
                         informationQuery.setTaskId(null);
+                        informationQuery.setCreateTime(new Date());
+                        informationQuery.setUpdateTime(new Date());
                         this.save(informationQuery);
                     } finally {
                         DistributedRedisLock.release("informationQueryLock_" + informationQuery.getWbsId() + "_" + informationQuery.getContractId() + "_" + informationQuery.getClassify() + "_" + informationQuery.getType());

+ 212 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/PrivateStandardServiceImpl.java

@@ -0,0 +1,212 @@
+package org.springblade.business.service.impl;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springblade.business.entity.StandardFile;
+import org.springblade.business.service.StandardFileService;
+import org.springblade.business.dto.PrivateStandardDTO;
+import org.springblade.business.entity.PrivateStandard;
+import org.springblade.business.entity.StandardInfo;
+import org.springblade.business.mapper.StandardInfoJoinMapper;
+import org.springblade.business.mapper.StandardInfoMapper;
+import org.springblade.business.mapper.StandardInfoPrivateJoinMapper;
+import org.springblade.business.service.PrivateStandardService;
+import org.springblade.business.mapper.PrivateStandardMapper;
+import org.springblade.common.utils.SnowFlakeUtil;
+import org.springblade.core.log.exception.ServiceException;
+import org.springblade.core.oss.model.BladeFile;
+import org.springblade.core.secure.BladeUser;
+import org.springblade.core.secure.utils.SecureUtil;
+import org.springblade.core.tool.utils.BeanUtil;
+import org.springblade.resource.feign.NewIOSSClient;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author LHB
+ * @description 针对表【u_wbs_private_standard(规范文件夹及规范文件表)】的数据库操作Service实现
+ * @createDate 2025-06-10 10:48:37
+ */
+@Service
+public class PrivateStandardServiceImpl extends ServiceImpl<PrivateStandardMapper, PrivateStandard>
+        implements PrivateStandardService {
+    @Resource
+    private StandardInfoMapper standardInfoMapper;
+    @Resource
+    private StandardInfoJoinMapper standardInfoJoinMapper;
+    @Resource
+    private StandardInfoPrivateJoinMapper standardInfoPrivateJoinMapper;
+
+    @Resource
+    private StandardFileService standardFileService;
+
+    /**
+     * 对象存储构建类
+     */
+    @Resource
+    private NewIOSSClient newIOSSClient;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean insert(PrivateStandardDTO uWbsPrivateStandard) {
+        BladeUser user = SecureUtil.getUser();
+        uWbsPrivateStandard.setCreateUser(user.getUserId());
+        Boolean isUploadFile = false;
+        if (uWbsPrivateStandard.getType() == 2 && uWbsPrivateStandard.getFiles().length > 0) {
+            isUploadFile = true;
+        }
+
+        //先上传文件,上传成功在执行添加
+        if (isUploadFile) {
+            List<StandardFile> standardFiles = new ArrayList<>();
+            MultipartFile[] files = uWbsPrivateStandard.getFiles();
+
+            try {
+                for (MultipartFile file : files) {
+                    StandardFile standardFile = new StandardFile();
+                    standardFile.setId(SnowFlakeUtil.getId());
+                    standardFile.setStandardId(uWbsPrivateStandard.getId());
+                    standardFile.setCreateUser(user.getUserId());
+
+
+                    String originalFilename = file.getOriginalFilename();
+                    standardFile.setFileName(originalFilename);
+                    originalFilename = "standard/" + uWbsPrivateStandard.getId() + "|" + originalFilename;
+
+
+
+                    //Oss上传 传特殊文件名 在oss中做特殊路径处理
+                    BladeFile bladeFile = this.newIOSSClient.uploadFileByInputStream2(file.getOriginalFilename(), file.getInputStream());
+
+                    standardFile.setStandardFileUrl(bladeFile.getLink());
+                    standardFiles.add(standardFile);
+                }
+            } catch (Exception e) {
+                //删除之前上传的文件
+                for (StandardFile standardFile : standardFiles) {
+                    this.newIOSSClient.removeFile(standardFile.getStandardFileUrl());
+                }
+                e.printStackTrace();
+                throw new ServiceException("文件上传失败!请检查Oss");
+            }
+            standardFileService.saveBatch(standardFiles);
+        }
+
+        if (uWbsPrivateStandard.getType() == 2) {
+            //修改之前的规则为过期
+            baseMapper.updateStatus(uWbsPrivateStandard.getParentId());
+        }
+        return baseMapper.insert(uWbsPrivateStandard) > 0;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean update(List<PrivateStandardDTO> privateStandards) {
+        BladeUser user = SecureUtil.getUser();
+
+        List<PrivateStandard> privateStandards1 = new ArrayList<>();
+
+        for (PrivateStandardDTO privateStandard : privateStandards) {
+            List<StandardFile> standardFiles = new ArrayList<>();
+            MultipartFile[] files = privateStandard.getFiles();
+
+            try {
+                for (MultipartFile file : files) {
+                    StandardFile standardFile = new StandardFile();
+                    standardFile.setId(SnowFlakeUtil.getId());
+                    standardFile.setStandardId(privateStandard.getId());
+                    standardFile.setCreateUser(user.getUserId());
+
+
+                    String originalFilename = file.getOriginalFilename();
+                    standardFile.setFileName(originalFilename);
+                    originalFilename = "standard/" + privateStandard.getId() + "|" + originalFilename;
+
+                    //Oss上传 传特殊文件名 在oss中做特殊路径处理
+                    BladeFile bladeFile = this.newIOSSClient.uploadFileByInputStream2(originalFilename, file.getInputStream());
+
+                    standardFile.setStandardFileUrl(bladeFile.getLink());
+                    standardFiles.add(standardFile);
+                }
+            } catch (Exception e) {
+                //删除之前上传的文件
+                for (StandardFile standardFile : standardFiles) {
+                    this.newIOSSClient.removeFile(standardFile.getStandardFileUrl());
+                }
+                e.printStackTrace();
+                throw new ServiceException("文件上传失败!请检查Oss");
+            }
+
+            standardFileService.saveBatch(standardFiles);
+
+
+            PrivateStandard privateStandard1 = BeanUtil.copyProperties(privateStandard, PrivateStandard.class);
+            privateStandards1.add(privateStandard1);
+        }
+
+        this.updateBatchById(privateStandards1);
+
+        return false;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean delete(Long id) {
+
+        try {
+            //获取当前用户
+            BladeUser user = SecureUtil.getUser();
+            int update = baseMapper.update(null, Wrappers.<PrivateStandard>lambdaUpdate()
+                    .set(PrivateStandard::getIsDeleted, 1)
+                    .set(PrivateStandard::getUpdateUser, user.getUserId())
+                    .eq(PrivateStandard::getId, id)
+                    .or()
+                    .eq(PrivateStandard::getParentId, id)
+            );
+            //TODO 后续还要删除规范详细信息
+
+
+            int update1 = standardInfoMapper.update(null, Wrappers.<StandardInfo>lambdaUpdate()
+                    .set(StandardInfo::getIsDeleted, 1)
+                    .set(StandardInfo::getUpdateUser, user.getUserId())
+                    .eq(StandardInfo::getStandardId, id));
+            //TODO 还要删除关联信息
+            standardInfoJoinMapper.updateJoin(user.getUserId(), 1, id);
+            //TODo 还要删除与表单的关联信息
+            standardInfoPrivateJoinMapper.updateJoin(user.getUserId(), 1, id);
+            return update > 0;
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new ServiceException("删除失败");
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean deleteFile(Long id) {
+        StandardFile byId = standardFileService.getById(id);
+        if (byId != null) {
+            try {
+                this.newIOSSClient.removeFile(byId.getStandardFileUrl());
+            } catch (Exception e) {
+                e.printStackTrace();
+                throw new ServiceException("文件删除失败,Oss异常");
+            }
+            standardFileService.update(Wrappers.<StandardFile>lambdaUpdate()
+                    .set(StandardFile::getIsDeleted, 1)
+                    .set(StandardFile::getUpdateUser, SecureUtil.getUser().getUserId())
+                    .eq(StandardFile::getId, id));
+            return true;
+        }
+        return false;
+    }
+}
+
+
+
+

+ 22 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/StandardFileServiceImpl.java

@@ -0,0 +1,22 @@
+package org.springblade.business.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springblade.business.entity.StandardFile;
+import org.springblade.business.service.StandardFileService;
+import org.springblade.business.mapper.StandardFileMapper;
+import org.springframework.stereotype.Service;
+
+/**
+* @author LHB
+* @description 针对表【u_standard_file(规范文件表)】的数据库操作Service实现
+* @createDate 2025-06-13 09:24:14
+*/
+@Service
+public class StandardFileServiceImpl extends ServiceImpl<StandardFileMapper, StandardFile>
+    implements StandardFileService {
+
+}
+
+
+
+

+ 14 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/StandardInfoJoinServiceImpl.java

@@ -0,0 +1,14 @@
+package org.springblade.business.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springblade.business.entity.StandardInfoJoin;
+import org.springblade.business.mapper.StandardInfoJoinMapper;
+import org.springblade.business.service.StandardInfoJoinService;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author LHB
+ */
+@Service
+public class StandardInfoJoinServiceImpl extends ServiceImpl<StandardInfoJoinMapper, StandardInfoJoin> implements StandardInfoJoinService {
+}

+ 36 - 8
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialMaterialMobilizationServiceImpl.java

@@ -15,7 +15,6 @@ import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.time.DateUtils;
 import org.springblade.business.dto.TrialMaterialMobilizationDTO;
 import org.springblade.business.entity.TrialMaterialMobilization;
-import org.springblade.business.entity.TrialNumberRule;
 import org.springblade.business.entity.TrialSampleInfo;
 import org.springblade.business.entity.TrialSamplingRecord;
 import org.springblade.business.excel.TrialMaterialMobilizationExcel;
@@ -37,24 +36,25 @@ import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.redis.cache.BladeRedis;
 import org.springblade.core.secure.utils.SecureUtil;
 import org.springblade.core.tool.api.R;
-import org.springblade.core.tool.utils.BeanUtil;
-import org.springblade.core.tool.utils.DateUtil;
-import org.springblade.core.tool.utils.Func;
-import org.springblade.core.tool.utils.ObjectUtil;
+import org.springblade.core.tool.utils.*;
 import org.springblade.resource.entity.Attach;
+import org.springblade.resource.feign.CommonFileClient;
 import org.springblade.resource.feign.NewIOSSClient;
+import org.springblade.resource.vo.NewBladeFile;
 import org.springblade.system.entity.Dict;
 import org.springblade.system.feign.IDictClient;
 import org.springblade.system.user.entity.User;
 import org.springblade.system.user.feign.IUserClient;
+import org.springframework.http.MediaType;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.mock.web.MockMultipartFile;
 import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.commons.CommonsMultipartFile;
 
 import javax.servlet.http.HttpServletResponse;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
+import java.io.*;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -68,6 +68,7 @@ public class TrialMaterialMobilizationServiceImpl extends BaseServiceImpl<TrialM
     private final TrialSamplingRecordMapper trialSamplingRecordMapper;
     private final NewIOSSClient newIOSSClient;
     private final JdbcTemplate jdbcTemplate;
+    private final CommonFileClient commonFileClient;
     private final TrialNumberRuleServiceImpl trialNumberRuleService;
     private final BladeRedis bladeRedis;
 
@@ -422,21 +423,48 @@ public class TrialMaterialMobilizationServiceImpl extends BaseServiceImpl<TrialM
 
     @Override
     public boolean uploadFile(String id, Integer type, String url) {
+        String pdfUrl = "";
+        try {
+            NewBladeFile bladeFile =  null;
+            InputStream is = CommonUtil.getOSSInputStream(url);
+            String fileName = url.substring(url.lastIndexOf("/") + 1);
+            MultipartFile files = new MockMultipartFile("file", fileName, "text/plain", org.apache.poi.util.IOUtils.toByteArray(is));
+            // 根据url后缀检测文件类型
+            String extension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
+            if (extension.equals("xlsx") || extension.equals("xls")) {
+                bladeFile = this.commonFileClient.excelToPdf(files);
+            } else if (extension.equals("jpg") || extension.equals("png") ||  extension.equals("jpeg")) {
+                bladeFile = this.commonFileClient.pngOrJpgToPdf(files);
+            } else if (extension.equals("docx") || extension.equals("doc")) {
+                bladeFile = this.commonFileClient.wordToPdf(files);
+            } else if (extension.equals("pdf")) {
+                pdfUrl = url;
+            }
+            if (bladeFile != null) {
+                pdfUrl = bladeFile.getPdfUrl();
+            }
+        } catch (IOException e) {
+            log.error("上传文件失败", e);
+        }
+
         if (type == 1) {
             this.update(Wrappers.<TrialMaterialMobilization>lambdaUpdate()
                     .set(TrialMaterialMobilization::getProductionCertificate, url)
+                    .set(TrialMaterialMobilization::getProductionCertificatePdfUrl, pdfUrl)
                     .eq(TrialMaterialMobilization::getId, id));
             return true;
         }
         if (type == 2) {
             this.update(Wrappers.<TrialMaterialMobilization>lambdaUpdate()
                     .set(TrialMaterialMobilization::getQualityInspectionReport, url)
+                    .set(TrialMaterialMobilization::getQualityInspectionReportPdfUrl, pdfUrl)
                     .eq(TrialMaterialMobilization::getId, id));
             return true;
         }
         if (type == 3) {
             this.update(Wrappers.<TrialMaterialMobilization>lambdaUpdate()
                     .set(TrialMaterialMobilization::getOtherAccessories, url)
+                    .set(TrialMaterialMobilization::getOtherAccessoriesPdfUrl, pdfUrl)
                     .eq(TrialMaterialMobilization::getId, id));
             return true;
         }

+ 14 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/UStandardInfoPrivateJoinServiceImpl.java

@@ -0,0 +1,14 @@
+package org.springblade.business.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springblade.business.entity.StandardInfoPrivateJoin;
+import org.springblade.business.mapper.StandardInfoPrivateJoinMapper;
+import org.springblade.business.service.StandardInfoPrivateJoinService;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author LHB
+ */
+@Service
+public class UStandardInfoPrivateJoinServiceImpl extends ServiceImpl<StandardInfoPrivateJoinMapper, StandardInfoPrivateJoin> implements StandardInfoPrivateJoinService {
+}

+ 270 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/UStandardInfoServiceImpl.java

@@ -0,0 +1,270 @@
+package org.springblade.business.service.impl;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springblade.business.dto.StandardInfoJoinDTO;
+import org.springblade.business.dto.StandardInfoPrivateJoinDTO;
+import org.springblade.business.dto.StandardInfoDTO;
+import org.springblade.business.entity.StandardInfo;
+import org.springblade.business.entity.StandardInfoJoin;
+import org.springblade.business.entity.StandardInfoPrivateJoin;
+import org.springblade.business.mapper.StandardInfoMapper;
+import org.springblade.business.service.StandardInfoJoinService;
+import org.springblade.business.service.StandardInfoPrivateJoinService;
+import org.springblade.business.service.StandardInfoService;
+import org.springblade.business.vo.StandardInfoDtoVo;
+import org.springblade.business.vo.StandardInfoPrivateJoinVO;
+import org.springblade.business.vo.StandardInfoVO;
+import org.springblade.common.utils.SnowFlakeUtil;
+import org.springblade.core.log.exception.ServiceException;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.secure.BladeUser;
+import org.springblade.core.secure.utils.SecureUtil;
+import org.springblade.core.tool.utils.BeanUtil;
+import org.springframework.beans.BeansException;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author LHB
+ * @description 针对表【u_standard_info(规范参数管理-基础信息)】的数据库操作Service实现
+ * @createDate 2025-06-11 09:57:39
+ */
+@Service
+public class UStandardInfoServiceImpl extends ServiceImpl<StandardInfoMapper, StandardInfo>
+        implements StandardInfoService {
+
+    /**
+     * 关联表
+     */
+    @Resource
+    private StandardInfoJoinService standardInfoJoinService;
+
+    /**
+     * 与表单的关联关系
+     */
+    @Resource
+    private StandardInfoPrivateJoinService standardInfoPrivateJoinService;
+
+
+    @Override
+    public IPage<StandardInfoDtoVo> selectMyPage(Query query, StandardInfo standardInfo) {
+        return baseMapper.selectMyPage(new Page<StandardInfoDtoVo>(query.getCurrent(), query.getSize()), standardInfo);
+    }
+
+    @Override
+    public StandardInfoDTO selectOne(Long id) {
+        return baseMapper.selectMyOne(id);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean insert(StandardInfoDTO uStandardInfo) {
+        try {
+            //获取当前用户
+            BladeUser user = SecureUtil.getUser();
+            uStandardInfo.setId(SnowFlakeUtil.getId());
+            uStandardInfo.setCreateUser(user.getUserId());
+
+            List<StandardInfo> info = uStandardInfo.getInfo();
+
+            //给集合设置id、父级id、创建人
+            info.forEach(item -> {
+                item.setId(SnowFlakeUtil.getId());
+                item.setParentId(uStandardInfo.getId());
+                item.setStandardId(uStandardInfo.getStandardId());
+                item.setCreateUser(user.getUserId());
+            });
+
+            //把父级对象转出来单独保存
+            StandardInfo parent = BeanUtil.copyProperties(uStandardInfo, StandardInfo.class);
+            baseMapper.insert(parent);
+            //通过mybatis-plus 批量新增
+            this.saveBatch(info);
+
+            return true;
+        } catch (BeansException e) {
+            e.printStackTrace();
+            throw new ServiceException("添加失败");
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean edit(StandardInfoDTO uStandardInfo) {
+        try {
+            //获取当前用户
+            BladeUser user = SecureUtil.getUser();
+            uStandardInfo.setUpdateUser(user.getUserId());
+
+            List<StandardInfo> info = uStandardInfo.getInfo();
+            info.forEach(item -> {
+                if (item.getId() == null) {
+                    //新增的子集合设置id、父级id、创建人
+                    item.setId(SnowFlakeUtil.getId());
+                    item.setParentId(uStandardInfo.getId());
+                    item.setStandardId(uStandardInfo.getStandardId());
+                    item.setCreateUser(user.getUserId());
+                } else {
+                    //更新的子集合 添加更新人
+                    item.setUpdateUser(user.getUserId());
+                }
+            });
+            //更新父级对象
+            StandardInfo parent = BeanUtil.copyProperties(uStandardInfo, StandardInfo.class);
+            baseMapper.updateById(parent);
+            //批量更新
+            this.saveOrUpdateBatch(info);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new ServiceException("更新失败");
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean delete(Long id) {
+        try {
+            //查询关联表 如果有关联关系不允许删除
+            long joinCount = standardInfoJoinService.count(Wrappers.<StandardInfoJoin>lambdaQuery()
+                    .eq(StandardInfoJoin::getStandardInfoRightId, id)
+                    .or()
+                    .eq(StandardInfoJoin::getStandardInfoLeftId, id));
+            if (joinCount > 0) {
+                throw new ServiceException("当前数据正在【条件设置】中使用,无法删除");
+            }
+            //查询与表单的关联表
+            long privateJoinCount = standardInfoPrivateJoinService.count(Wrappers.<StandardInfoPrivateJoin>lambdaQuery()
+                    .eq(StandardInfoPrivateJoin::getStandardInfoId, id));
+            if (privateJoinCount > 0) {
+                throw new ServiceException("当前数据正在【关联元素】中使用,无法删除");
+            }
+
+            int update = baseMapper.update(null, Wrappers.<StandardInfo>lambdaUpdate()
+                    .set(StandardInfo::getIsDeleted, 1)
+                    .eq(StandardInfo::getId, id)
+                    .or()
+                    .eq(StandardInfo::getParentId, id));
+            return update > 0;
+        } catch (ServiceException e) {
+            e.printStackTrace();
+            throw new ServiceException("删除失败");
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean setCondition(List<StandardInfoJoinDTO> standardInfoJoins) {
+        BladeUser user = SecureUtil.getUser();
+        List<StandardInfoJoin> saveData = new ArrayList<>();
+        try {
+            for (StandardInfoJoinDTO standardInfoJoin : standardInfoJoins) {
+                Long leftId = standardInfoJoin.getLeftId();
+                List<Long> rightIds = standardInfoJoin.getRightIds();
+                for (Long rightId : rightIds) {
+                    StandardInfoJoin uStandardInfoJoin = new StandardInfoJoin();
+                    uStandardInfoJoin.setId(SnowFlakeUtil.getId());
+                    uStandardInfoJoin.setStandardInfoLeftId(leftId);
+                    uStandardInfoJoin.setStandardInfoRightId(rightId);
+                    uStandardInfoJoin.setCreateUser(user.getUserId());
+                    saveData.add(uStandardInfoJoin);
+                }
+                //先删除之前的关联关系
+                standardInfoJoinService.remove(Wrappers.<StandardInfoJoin>lambdaQuery()
+                        .eq(StandardInfoJoin::getStandardInfoLeftId,leftId));
+            }
+            //新增
+            return standardInfoJoinService.saveBatch(saveData);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new ServiceException("条件设置失败");
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean setElementJoin(List<StandardInfoPrivateJoinDTO> standardInfoPrivateJoins) {
+        BladeUser user = SecureUtil.getUser();
+        List<StandardInfoPrivateJoin> saveData = new ArrayList<>();
+
+        try {
+            for (StandardInfoPrivateJoinDTO standardInfoPrivateJoin : standardInfoPrivateJoins) {
+                Long leftId = standardInfoPrivateJoin.getLeftId();
+                List<StandardInfoPrivateJoin> rightIds = standardInfoPrivateJoin.getRightIds();
+                rightIds.forEach(f -> {
+                    f.setId(SnowFlakeUtil.getId());
+                    f.setStandardInfoId(leftId);
+                    f.setCreateUser(user.getUserId());
+                });
+                saveData.addAll(rightIds);
+                //删除之前的关联关系
+                standardInfoPrivateJoinService.remove(Wrappers.<StandardInfoPrivateJoin>lambdaQuery()
+                        .eq(StandardInfoPrivateJoin::getStandardInfoId,leftId));
+            }
+            return standardInfoPrivateJoinService.saveBatch(saveData);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new ServiceException("元素关联失败");
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean deleteConditionSet(Long leftId) {
+        BladeUser user = SecureUtil.getUser();
+        try {
+            return standardInfoJoinService.update(Wrappers.<StandardInfoJoin>lambdaUpdate()
+                    .set(StandardInfoJoin::getIsDeleted, 1)
+                    .set(StandardInfoJoin::getUpdateUser, user.getUserId())
+                    .eq(StandardInfoJoin::getStandardInfoLeftId, leftId));
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new ServiceException("删除失败");
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean deleteElementJoin(Long leftId) {
+        BladeUser user = SecureUtil.getUser();
+        try {
+            return standardInfoPrivateJoinService.update(Wrappers.<StandardInfoPrivateJoin>lambdaUpdate()
+                    .set(StandardInfoPrivateJoin::getIsDeleted, 1)
+                    .set(StandardInfoPrivateJoin::getUpdateUser, user.getUserId())
+                    .eq(StandardInfoPrivateJoin::getStandardInfoId, leftId));
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new ServiceException("删除失败");
+        }
+    }
+
+    @Override
+    public List<StandardInfoVO> getConditionSet(Long id) {
+        return baseMapper.getConditionSet(id);
+    }
+
+    @Override
+    public List<StandardInfoPrivateJoinVO> getElementJoin(Long id) {
+        return baseMapper.getElementJoin(id);
+
+    }
+
+    @Override
+    public List<StandardInfoPrivateJoinVO> effectPreview(String ids) {
+        List<Long> collect = Arrays.stream(ids.split(",")).map(Long::parseLong).collect(Collectors.toList());
+        return baseMapper.effectPreview(collect);
+    }
+}
+
+
+
+

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

@@ -335,7 +335,7 @@ public class EVDataServiceImpl implements EVDataService {
                     if (taskApp.getSigType() == 2) {
                         this.jdbcTemplate.execute("update u_entrust_info set sample_status=2,status=" + (taskApp.getSigType() + 1) + ",entrust_e_pdf='" + taskApp.getLastFilePdfUrl() + "' where id=(SELECT wbs_id from u_information_query where id='" + taskApp.getFormDataId() + "')");
                     }
-                    updateSql = "update u_information_query set e_visa_pdf_url='" + taskApp.getLastFilePdfUrl() + "',status=" + taskApp.getSigType() + " where id='" + taskApp.getFormDataId() + "'";
+                    updateSql = "update u_information_query set e_visa_pdf_url='" + taskApp.getLastFilePdfUrl() + "',status=" + taskApp.getSigType() + ",business_time='" + taskApp.getPdfDate() + "' where id='" + taskApp.getFormDataId() + "'";
                 }
                 this.jdbcTemplate.execute(updateSql);
                 System.out.println("u_information_query修改语句:"+updateSql);
@@ -378,6 +378,13 @@ public class EVDataServiceImpl implements EVDataService {
                 String eVisaPdfUrl = map.get("e_visa_pdf_url") + ""; //签字的PDF路径
                 String pdfUrl = map.get("pdf_url") + ""; //合并后的PDF路径
                 String type = map.get("type") + ""; //资料类型,1资料填报,2试验,3首件
+                Object status = map.get("status");
+                if (status != null && status.toString().equals("3")) {
+                     this.jdbcTemplate.execute("delete from u_task_batch where id in(" + taskApp.getId()+")");
+                     RedisTemplate.delete("sign-" + taskApp.getFormDataId());
+                     taskApp.setSigState(2);
+                     return;
+                }
                 taskApp.setPdfDataType(type);
                 if (StringUtils.isNotEmpty(pdfTrialUrlPosition) || StringUtils.isNotEmpty(pdfTrialUrl) || StringUtils.isNotEmpty(eVisaPdfUrl) || StringUtils.isNotEmpty(pdfUrl)) {
                     if ("1".equals(type)) {

+ 34 - 8
blade-service/blade-e-visa/src/main/java/org/springblade/evisa/utils/PDFUtils.java

@@ -1,16 +1,17 @@
 package org.springblade.evisa.utils;
 
 import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
 import org.apache.pdfbox.text.PDFTextStripper;
 import org.springblade.business.vo.TaskSignInfoVO;
 import org.springblade.common.utils.CommonUtil;
 import org.springblade.core.tool.utils.Func;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
+import java.io.*;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
+import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
@@ -23,7 +24,9 @@ public class PDFUtils {
             PDFTextStripper stripper = new PDFTextStripper();
             String text = stripper.getText(document);
             String[] lines = text.split("[ \\n]+");
-            String regex = "^\\d{4}年\\d{2}月\\d{2}日$";
+            String lastDate = getPdfFirstPageLastDate(document);
+            taskApp.setPdfDate(lastDate);
+            Pattern pattern = Pattern.compile("(\\d{4}[年-]\\d{2}[月-]\\d{2}日?)");
 
             for(int k=0;k<lines.length;k++){
                 String textStr = lines[k];
@@ -41,10 +44,11 @@ public class PDFUtils {
                     if (txt.length() >= 15 && Func.isNumeric(txt)||(Func.isNumeric(txt)&&txt.length()==8&&txt.startsWith("123"))) {
                         eVisaConfigList.add(txt);
                     }
-
-                    Pattern pattern = Pattern.compile(regex);
-                    if(pattern.matcher(txt).matches()){
-                        taskApp.setPdfDate(txt);
+                    if (taskApp.getPdfDate() == null || taskApp.getPdfDate().isEmpty()) {
+                        Matcher matcher = pattern.matcher(txt);
+                        if(matcher.matches()){
+                            taskApp.setPdfDate(matcher.group(1));
+                        }
                     }
                 }
 
@@ -123,4 +127,26 @@ public class PDFUtils {
         }
     }
 
+    public static String getPdfFirstPageLastDate(PDDocument document) throws IOException {
+        PDFTextStripper stripper = new PDFTextStripper();
+        stripper.setStartPage(1);
+        stripper.setEndPage(1);
+        String text = stripper.getText(document);
+        Pattern pattern = Pattern.compile("(\\d{4}[-年.]\r?\n?\\d{2}[-月.]\r?\n?\\d{2}日?)");
+        Matcher matcher = pattern.matcher(text);
+        List<String> dates = new ArrayList<>();
+        while (matcher.find()) {
+            dates.add(matcher.group(1));
+        }
+        if (!dates.isEmpty()) {
+            Optional<String> max = dates.stream().map(item -> {
+                String replace = item.replace("年", "-").replace("月", "-").replace("日", "").replaceAll("\\.", "-");
+                return replace.replaceAll("[\r\n]",  "");
+            }).max(String::compareTo);
+            return max.get();
+        } else {
+            return "";
+        }
+    }
+
 }

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

@@ -597,7 +597,7 @@ public class ExcelTabController extends BladeController {
 
                     for (WbsFormElement elementInfo : elementList) {
                         String ysName = elementInfo.getEName();
-                        if (titleName.equals(ysName)) {
+                         if (titleName.equals(ysName)) {
                             lastName = elementInfo.getEName();
                             attrInfo = elementInfo.getEKey() + "__" + i + "_" + j;
 
@@ -609,7 +609,8 @@ public class ExcelTabController extends BladeController {
                             is_true = true;
                             break;
                         } else {
-                            if (MathUtil.sim(titleName, ysName) > maxScore) {
+                             List<String> list = Arrays.asList(titleName.split("_"));
+                             if (list.contains(ysName)) {
                                 attrInfo = elementInfo.getEKey() + "__" + i + "_" + j;
 
                                 filedType = WbsElementUtil.getInitTableFiledType(elementInfo.getEType());
@@ -619,6 +620,7 @@ public class ExcelTabController extends BladeController {
                                 lastName = ysName;
                                 maxScore = MathUtil.sim(titleName, ysName);
                                 is_true = true;
+                                break;
                             }
                         }
                     }
@@ -1245,10 +1247,10 @@ public class ExcelTabController extends BladeController {
                                         if (x1 - xx2 <= 1 && y1 == yy2) {
                                             inputText = name;
                                         } else {
-                                            inputText += name + "_";
+                                            inputText += name + "_" +name;
                                         }
                                     } else {
-                                        inputText += name + "_";
+                                        inputText += "_" +name;
                                     }
                                 } else {
                                     if (x1 - xx2 <= 1 && y1 == yy2) {
@@ -1267,14 +1269,14 @@ public class ExcelTabController extends BladeController {
                                 int yy1 = Integer.parseInt(top.get(k).get("y1"));
                                 int yy2 = Integer.parseInt(top.get(k).get("y2"));
                                 if (!StringUtil.isNumeric(name) && name.length() <= 20) {
-                                    inputText += name + "_";
+                                    inputText += "_" + name;
                                 }
                             }
                         }
-
-                        if (inputText != null && inputText != "" && inputText.indexOf("_") >= 0) {
-                            inputText = inputText.substring(0, inputText.lastIndexOf("_"));
-                        }
+                        //这段代码含义未知
+//                        if (inputText != null && inputText != "" && inputText.indexOf("_") >= 0) {
+//                            inputText = inputText.substring(0, inputText.lastIndexOf("_"));
+//                        }
 
                         // 质检表特殊处理匹配
 
@@ -1670,7 +1672,7 @@ public class ExcelTabController extends BladeController {
         String tabName = wbsTreeContract.getInitTableName();
         // 字段查询 并去掉公式字段
 
-        String colkeys = "SELECT GROUP_CONCAT(COLUMN_NAME) as colkeys from information_schema.COLUMNS c where c.table_name='" + tabName + "' and COLUMN_NAME not in('id','p_key_id')";
+        String colkeys = "SELECT GROUP_CONCAT(distinct COLUMN_NAME) as colkeys from information_schema.COLUMNS c where c.table_name='" + tabName + "' and COLUMN_NAME not in('id','p_key_id')";
         Map<String, Object> stringObjectMap = jdbcTemplate.queryForMap(colkeys);
         colkeys = stringObjectMap.get("colkeys") + "";
         // 复制表数据

+ 178 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/SignConfigController.java

@@ -0,0 +1,178 @@
+package org.springblade.manager.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.*;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.*;
+import org.springblade.manager.dto.SaveUserInfoByProjectDTO;
+import org.springblade.manager.dto.SignConfigDTO;
+import org.springblade.manager.entity.*;
+import org.springblade.manager.service.*;
+import org.springblade.manager.vo.*;
+import org.springblade.manager.wrapper.SignConfigWrapper;
+import org.springblade.system.entity.Dict;
+import org.springblade.system.feign.IDictClient;
+import org.springblade.system.user.entity.User;
+import org.springblade.system.vo.RoleVO;
+import org.springblade.system.vo.RoleVO2;
+import org.springframework.beans.BeanUtils;
+import org.springframework.web.bind.annotation.*;
+import javax.validation.Valid;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+
+/**
+ * 电签配置 控制器
+ *
+ * @author BladeX
+ * @since 2022-05-18
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/signConfig")
+@Api(value = "电签配置表", tags = "电签配置表接口")
+public class SignConfigController extends BladeController {
+
+    private final ISignConfigService signConfigService;
+
+    private final IDictClient dictClient;
+
+    /**
+     * 获取参建方 角色列表
+     */
+    @GetMapping("/roleList")
+    @ApiOperationSupport(order = 1)
+    @ApiOperation(value = "岗位列表")
+    public R<List<RoleVO2>> roleMenuList(@ApiParam(value = "参建方类型,1:施工,2:监理,3:业主", required = true) @RequestParam Integer type, @ApiParam(value = "岗位名称") @RequestParam(required = false) String roleName) {
+        return R.data(signConfigService.getRoleList(type, roleName));
+    }
+
+    /**
+     * 分页
+     */
+    @GetMapping("/list")
+    @ApiOperationSupport(order = 2)
+    @ApiOperation(value = "分页", notes = "传入excelTab")
+    public R<IPage<SignConfigVO>> list(@ApiParam(value = "岗位id") @RequestParam(required = false) Long roleId, @ApiParam(value = "搜索keyword") @RequestParam(required = false) String keyword, Query query, @RequestParam() Integer type) {
+        return R.data(signConfigService.selectPageByRoleId(Condition.getPage(query), roleId, keyword, type));
+    }
+
+    /**
+     * 岗位详情
+     */
+    @GetMapping("/roleDetail")
+    @ApiOperationSupport(order = 3)
+    @ApiOperation(value = "岗位详情", notes = "传入id")
+    public R<List<SignConfigRelationVO>> roleDetail(@RequestParam Long id) {
+        List<SignConfigRelation> signConfigRelationList = signConfigService.getSignConfigRelationListByConfId(id, 1);
+        return R.data(SignConfigRelationVO.build(signConfigRelationList));
+    }
+
+    /**
+     * 元素详情
+     */
+    @GetMapping("/elementDetail")
+    @ApiOperationSupport(order = 4)
+    @ApiOperation(value = "元素详情", notes = "传入id")
+    public R<List<SignConfigRelationVO>> elementDetail(@RequestParam Long id) {
+        List<SignConfigRelation> signConfigRelations = signConfigService.getSignConfigRelationListByConfId(id, 0);
+        R<List<Dict>> type = dictClient.getList("table_type");
+        List<SignConfigRelationVO> list = SignConfigRelationVO.build(signConfigRelations);
+        if (type.isSuccess() && type.getData() != null) {
+            List<Dict> data = type.getData();
+            Map<String, String> map = data.stream().collect(Collectors.toMap(Dict::getDictKey, Dict::getDictValue));
+            list.forEach(vo -> vo.setType(map.getOrDefault(vo.getType(), vo.getType())));
+        }
+        return R.data(list);
+    }
+
+    /**
+     * 元素表分类列表
+     */
+    @GetMapping("/tableType")
+    @ApiOperationSupport(order = 5)
+    @ApiOperation(value = "元素表分类列表")
+    public R<List<Dict>> tableType() {
+        return dictClient.getList("table_type");
+    }
+
+    /**
+     * 元素表列表
+     */
+    @GetMapping("/tableList")
+    @ApiOperationSupport(order = 5)
+    @ApiOperation(value = "获取元素表列表")
+    public R<List<TableInfo>> tableList(@RequestParam(required = false) Integer tableType, @RequestParam(required = false) String name) {
+        return R.data( signConfigService.tableList(tableType, name));
+    }
+
+    /**
+     * 元素列表
+     */
+    @GetMapping("/elementList")
+    @ApiOperationSupport(order = 5)
+    @ApiOperation(value = "获取所有元素列表")
+    public R<List<WbsFormElementVO3>> elementList() {
+        List<WbsFormElementVO3> elements =  signConfigService.elementList();
+        return R.data(elements);
+    }
+
+    /**
+     * 获取所有施工方、监理方、业主方的角色列表
+     */
+    @GetMapping("/queryAllRoleList")
+    @ApiOperationSupport(order = 5)
+    @ApiOperation(value = "获取所有施工方、监理方、业主方的角色列表")
+    public R<List<RoleVO>> queryAllRoleList(@ApiParam(value = "参建方类型,1:施工,2:监理,3:业主", required = true) @RequestParam Integer type, @RequestParam(required = false) String roleName) {
+        List<RoleVO> roleVOS = signConfigService.queryAllRoleList(type, roleName);
+        return R.data(roleVOS);
+    }
+
+
+
+    /**
+     * 新增或修改 清表基础数据表
+     */
+    @PostMapping("/submit")
+    @ApiOperationSupport(order = 6)
+    @ApiOperation(value = "新增或修改")
+    public R submit(@Valid @RequestBody List<SignConfigDTO> signConfigDTOs) {
+        return R.status(signConfigService.addOrEdit(signConfigDTOs));
+    }
+
+
+    /**
+     * 删除
+     */
+    @PostMapping("/remove")
+    @ApiOperationSupport(order = 7)
+    @ApiOperation(value = "逻辑删除", notes = "传入ids")
+    public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+        signConfigService.deleteLogic(Func.toLongList(ids));
+        return R.status(true);
+    }
+
+    /**
+     * 停用\启用
+     */
+    @PostMapping("/updateStatus")
+    @ApiOperationSupport(order = 8)
+    @ApiOperation(value = "停用、启用", notes = "传入ids")
+    public R updateStatus(@ApiParam(value = "主键集合", required = true) @RequestParam String ids, @ApiParam(value = "状态", required = true) @RequestParam Integer status) {
+        if (status == null || status < 0 || status > 1) {
+            return R.fail("状态错误");
+        }
+        return R.status(signConfigService.changeStatus(Func.toLongList(ids),  status));
+    }
+
+}

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

@@ -126,7 +126,7 @@ public class TableFileController extends BladeController {
             }
             excelTabService.getBussPdfs(wbsTreeContractP.getPKeyId() + "", classfy, wbsTreeContract.getContractId(), wbsTreeContract.getProjectId());
         }
-        if (tableFile.getType() == 20 || tableFile.getType() == 21||tableFile.getType() == 22) {
+        if (tableFile.getType() == 20 || tableFile.getType() == 21||tableFile.getType() == 22 || tableFile.getType() == 10 || tableFile.getType() == 11||tableFile.getType() == 12) {
             //查询当前节点 如果是数字化节点 需要删除上报信息,变成未填报
             List<TableFileVO> fileVOList = tableFileService.selectTableFileList1(Long.parseLong(tableFile.getTabId()));
             // 该文本无附件

+ 17 - 2
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/TextdictInfoController.java

@@ -113,7 +113,9 @@ public class TextdictInfoController extends BladeController {
     @ApiOperationSupport(order = 3)
     @ApiOperation(value = "分页", notes = "传入textdictInfo")
     public R<IPage<TextdictInfoVO>> page(TextdictInfoVO textdictInfo, Query query) {
-
+        if(textdictInfo.getType() == 4){
+            return R.data(textdictInfoService.analysisHtmlDefault(textdictInfo.getTabId()));
+        }
         IPage<TextdictInfoVO> pages = textdictInfoService.selectTextdictInfoPage(Condition.getPage(query), textdictInfo);
         return R.data(pages);
     }
@@ -155,7 +157,15 @@ public class TextdictInfoController extends BladeController {
     @PostMapping("/remove")
     @ApiOperationSupport(order = 7)
     @ApiOperation(value = "逻辑删除", notes = "传入ids")
-    public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids,@ApiParam(value = "wbs p_key_id", required = true) @RequestParam String tabId) throws FileNotFoundException {
+    public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids,
+                    @ApiParam(value = "wbs p_key_id", required = true) @RequestParam String tabId,
+                    String colKey,
+                    Integer type) throws FileNotFoundException {
+        if(type != null && type == 4){
+            textdictInfoService.removeHtmlDefault(tabId,colKey);
+            return R.success("删除成功");
+        }
+
         //获取节点信息
 
         WbsTreePrivate wbsTreePrivate = wbsTreePrivateMapper.getByPKeyId(Long.parseLong(tabId));
@@ -559,6 +569,11 @@ public class TextdictInfoController extends BladeController {
     @ApiOperationSupport(order = 7)
     @ApiOperation(value = "保存默认值", notes = "保存默认值")
     public R<String> saveDefaulVal(@Valid @RequestBody TextdictBy345VO textdictInfo) throws Exception {
+        if(textdictInfo.getType() == 4){
+            textdictInfoService.saveHtmlDefault(textdictInfo);
+            return R.success("操作成功");
+        }
+
 
         //当前清表信息
         WbsTreePrivate wbsTreePrivate = wbsTreePrivateMapper.getByPKeyId(textdictInfo.getTableId());

+ 147 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreeSynchronousRecordController.java

@@ -0,0 +1,147 @@
+package org.springblade.manager.controller;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.manager.entity.ProjectInfo;
+import org.springblade.manager.entity.WbsTreePrivate;
+import org.springblade.manager.entity.WbsTreeSynchronousRecord;
+import org.springblade.manager.service.WbsTreeSynchronousRecordService;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.tool.api.R;
+import org.springblade.manager.vo.WbsTreeSynchronousRecordVo;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * WBS同步记录表(MWbsTreeSynchronousRecord)表控制层
+ *
+ * @author makejava
+ * @since 2025-05-15 13:50:25
+ */
+@RestController
+@RequestMapping("/synchronousRecord")
+public class WbsTreeSynchronousRecordController {
+    /**
+     * 服务对象
+     */
+    @Resource
+    private WbsTreeSynchronousRecordService mWbsTreeSynchronousRecordService;
+
+    /**
+     * 分页查询所有数据
+     *
+     * @param record 查询对象
+     * @param query  分页对象
+     * @return 所有数据
+     */
+    @GetMapping("/page")
+    public R<IPage<WbsTreeSynchronousRecord>> selectAll(WbsTreeSynchronousRecord record, Query query) {
+        LambdaQueryWrapper<WbsTreeSynchronousRecord> lambda = new QueryWrapper().lambda();
+        lambda
+                .eq(record.getProjectId() != null, WbsTreeSynchronousRecord::getProjectId, record.getProjectId())
+                .eq(record.getStatus() != null, WbsTreeSynchronousRecord::getStatus, record.getStatus())
+                .eq(record.getRange() != null, WbsTreeSynchronousRecord::getRange, record.getRange());
+        if (!StringUtil.isBlank(record.getType())) {
+            lambda.apply("FIND_IN_SET({0},type)", record.getType());
+        }
+        IPage<WbsTreeSynchronousRecord> page = mWbsTreeSynchronousRecordService.page(Condition.getPage(query), lambda);
+        for (WbsTreeSynchronousRecord pageRecord : page.getRecords()) {
+            switch (pageRecord.getStatus()) {
+                case 0:
+                    pageRecord.setStatusName("待同步");
+                    break;
+                case 1:
+                    pageRecord.setStatusName("正在同步");
+                    break;
+                case 2:
+                    pageRecord.setStatusName("已同步");
+                    break;
+                case 3:
+                    pageRecord.setStatusName("同步失败");
+                    break;
+                default:
+                    break;
+            }
+        }
+        return R.data(page);
+    }
+
+    /**
+     * 通过主键查询单条数据
+     *
+     * @param id 主键
+     * @return 单条数据
+     */
+    @GetMapping("getById")
+    public R<WbsTreeSynchronousRecord> selectOne(@RequestParam Long id) {
+        return R.data(this.mWbsTreeSynchronousRecordService.getById(id));
+    }
+
+
+    /**
+     * 新增数据
+     *
+     * @param mWbsTreeSynchronousRecord 实体对象
+     * @return 新增结果
+     */
+    @PostMapping("add")
+    public R<WbsTreeSynchronousRecord> insert(@RequestBody WbsTreeSynchronousRecord mWbsTreeSynchronousRecord) {
+        if (StringUtil.isBlank(mWbsTreeSynchronousRecord.getNodeId())) {
+            return R.fail("节点不能为空");
+        }else{
+            String[] split = mWbsTreeSynchronousRecord.getNodeId().split(",");
+            if(split.length > 100){
+                return R.fail("节点过多,如果勾选了父节点,请勿带子节点!");
+            }
+        }
+        if (StringUtil.isBlank(mWbsTreeSynchronousRecord.getType())) {
+            return R.fail("请选择同步类型");
+        }
+        if (mWbsTreeSynchronousRecord.getRange() == null) {
+            return R.fail("请选择同步范围");
+        }
+
+        if (mWbsTreeSynchronousRecord.getRange() == 2 && StringUtil.isBlank(mWbsTreeSynchronousRecord.getContractRange())) {
+            return R.fail("请选择合同同步范围");
+        }
+        if (mWbsTreeSynchronousRecord.getProjectId() == null) {
+            return R.fail("项目Id为空");
+        }
+        if (mWbsTreeSynchronousRecord.getRange() == 1 && mWbsTreeSynchronousRecord.getTemplateId() == null) {
+            return R.fail("同步源为空");
+        }
+
+        return R.data(this.mWbsTreeSynchronousRecordService.insert(mWbsTreeSynchronousRecord));
+    }
+
+    /**
+     * 认证接口是否正在同步
+     */
+    @PostMapping("getNodeStatus")
+    public R<WbsTreeSynchronousRecord> getNodeStatus(@RequestParam Long id) {
+        return R.data(this.mWbsTreeSynchronousRecordService.getNodeStatus(id));
+    }
+
+
+    /**
+     * 获取当前项目的模板项目
+     *
+     * @param nodeIds 节点ids 逗号拼接
+     */
+    @GetMapping("getTempProject")
+    public R<List<WbsTreeSynchronousRecordVo>> getProjectTemplate(@RequestParam String nodeIds) {
+        if (StringUtil.isBlank(nodeIds)) {
+            return R.fail("参数不能为空");
+        }
+        return R.data(this.mWbsTreeSynchronousRecordService.getProjectTemplate(nodeIds));
+    }
+
+}
+

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

@@ -166,6 +166,10 @@ public class ArchiveTreeContractImpl implements ArchiveTreeContractClient {
         archiveTreeContractService.addArchiveTreeContract(archiveTreeContracts,rootId);
     }
 
+    @Override
+    public List<ArchiveTreeContract> getTopAutoTypeNodeByProjectID(@RequestParam Long projectId){
+        return archiveTreeContractMapper.getTopAutoTypeNodeByProjectID(projectId);
+    }
 
 
 }

+ 2 - 2
blade-service/blade-manager/src/main/java/org/springblade/manager/feign/TableFileClientImpl.java

@@ -36,9 +36,9 @@ public class TableFileClientImpl implements TableFileClient {
     }
 
     @Override
-    public List<TableFile> getTabFilesByTabIds(String tabFileIds) {
+    public List<TableFile> getTabFilesByTabIds(List<String> tabFileIds) {
         return tableFileService.getBaseMapper().selectList(Wrappers.<TableFile>lambdaQuery()
-                .in(TableFile::getTabId, Func.toLongList(tabFileIds))
+                .in(TableFile::getTabId, tabFileIds)
                 .ne(TableFile::getType, 1) //排除源文件
                 .isNotNull(TableFile::getTabId)
         );

+ 7 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/feign/WbsParamClientImpl.java

@@ -7,6 +7,8 @@ import org.springblade.manager.entity.WbsTreeContract;
 import org.springblade.manager.service.IWbsParamService;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.List;
+
 @RestController
 @AllArgsConstructor
 public class WbsParamClientImpl implements WbsParamClient{
@@ -23,6 +25,11 @@ public class WbsParamClientImpl implements WbsParamClient{
         return iWbsParamService.getBaseMapper().selectOne(Wrappers.lambdaQuery(WbsParam.class).eq(WbsParam::getNodeId, nodeId).eq(WbsParam::getType, 200).eq(WbsParam::getIsDeleted, 0).eq(WbsParam::getK,"FILE_TITLE"));
     }
 
+    @Override
+    public void saveWbsParams(List<WbsParam> wbsParamList) {
+        iWbsParamService.saveBatch(wbsParamList);
+    }
+
     @Override
     public String createFileTitle(WbsTreeContract contract) {
         return iWbsParamService.createFileTitle(contract);

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

@@ -84,6 +84,8 @@ public interface ArchiveTreeContractMapper extends BaseMapper<ArchiveTreeContrac
 
     List<ArchiveTreeContract> getListByProjectId(@Param("projectId") Long projectId);
 
+    List<ArchiveTreeContract> getTopAutoTypeNodeByProjectID(@Param("projectId") Long projectId);
+
     List<ArchiveTreeContract> getStorageNodeByGroupId(@Param("projectId") Long projectId, @Param("archiveAutoGroupId") Long archiveAutoGroupId);
 
     @MapKey("id")

+ 15 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ArchiveTreeContractMapper.xml

@@ -235,7 +235,7 @@
                         inner join u_archive_file b on b.node_id = a.id and b.is_deleted = a.is_deleted and b.project_id = a.project_id and (b.is_auto_file is null or b.is_auto_file != 1)
                            WHERE  a.is_deleted = 0
                              and a.project_id = #{projectId}
-                             and a.ancestors like CONCAT('%',d.id,'%')
+                             and (FIND_IN_SET(d.id,a.ancestors) or a.id = d.id)
         <if test="code!=null and code!=''">
             AND (a.tree_code = #{code} or a.tree_code = #{contractId} or a.parent_id = 0)
         </if>
@@ -357,6 +357,20 @@
         order by ancestors asc,tree_sort asc
     </select>
 
+
+    <select id="getTopAutoTypeNodeByProjectID" resultMap="archiveTreeContractResultMap">
+        SELECT
+            *
+        FROM
+            m_archive_tree_contract
+        WHERE
+            1 = 1
+          AND project_id = #{projectId}
+          AND is_deleted = 0
+          AND archive_auto_type = 1
+        order by ancestors asc,tree_sort asc
+    </select>
+
     <select id="getHavedBoxFileNodeByProjectID" resultMap="archiveTreeContractResultMap">
         SELECT
             *

+ 44 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/SignConfigMapper.java

@@ -0,0 +1,44 @@
+/*
+ *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *  Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the dreamlu.net developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: Chill 庄骞 (smallchill@163.com)
+ */
+package org.springblade.manager.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.apache.ibatis.annotations.Param;
+import org.springblade.manager.entity.SignConfig;
+import org.springblade.manager.entity.SignConfigRelation;
+import org.springblade.manager.vo.SignConfigVO;
+import org.springblade.system.vo.RoleVO2;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * 电签配置 Mapper 接口
+ *
+ * @author BladeX
+ * @since 2025-05-27
+ */
+public interface SignConfigMapper extends BaseMapper<SignConfig> {
+
+    List<RoleVO2> getRoleList(@Param("relationType") Integer relationType,@Param("roleName") String roleName);
+    List<SignConfigRelation> getSignConfigRelationListByConfId(@Param("confId") Long confId, @Param("type") Integer type);
+
+    List<SignConfig> selectPageByRoleId(IPage<SignConfig> page, @Param("roleId") Long roleId, @Param("keyword") String keyword, @Param("relationType") Integer relationType);
+
+    List<SignConfigVO> getConfigByENames(@Param("names") Set<String> names);
+}

+ 90 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/SignConfigMapper.xml

@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.manager.mapper.SignConfigMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="signConfigResultMap" type="org.springblade.manager.entity.SignConfig">
+        <result column="id" property="id"/>
+        <result column="create_user" property="createUser"/>
+        <result column="create_dept" property="createDept"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_user" property="updateUser"/>
+        <result column="update_time" property="updateTime"/>
+        <result column="status" property="status"/>
+        <result column="is_deleted" property="isDeleted"/>
+        <result column="e_name" property="eName"/>
+        <result column="e_id" property="eId"/>
+        <result column="e_key" property="eKey"/>
+        <result column="table_type" property="tableType"/>
+        <result column="element_type" property="elementType"/>
+        <result column="tenant_id" property="tenantId"/>
+    </resultMap>
+    <resultMap id="signConfigRelationResultMap" type="org.springblade.manager.entity.SignConfigRelation">
+        <result column="id" property="id"/>
+        <result column="create_user" property="createUser"/>
+        <result column="create_dept" property="createDept"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_user" property="updateUser"/>
+        <result column="update_time" property="updateTime"/>
+        <result column="status" property="status"/>
+        <result column="is_deleted" property="isDeleted"/>
+        <result column="relation_id" property="relationId"/>
+        <result column="relation_name" property="relationName"/>
+        <result column="relation_type" property="relationType"/>
+        <result column="type" property="type"/>
+        <result column="conf_id" property="confId"/>
+    </resultMap>
+    <resultMap id="signConfigVO" type="org.springblade.manager.vo.SignConfigVO" extends="signConfigResultMap">
+        <association property="relations" resultMap="signConfigRelationResultMap"/>
+    </resultMap>
+    <select id="getRoleList" resultType="org.springblade.system.vo.RoleVO2">
+        select distinct relation_id as roleId,relation_name as roleName from m_sign_config_relation
+            WHERE  type = 1 and is_deleted = 0
+        <if test="roleName != null and roleName != ''">
+            and relation_name like concat('%',#{roleName},'%')
+        </if>
+        <if test="relationType != null">
+            and relation_type = #{relationType}
+        </if>
+    </select>
+
+    <select id="getSignConfigRelationListByConfId" resultMap="signConfigRelationResultMap">
+        select id,conf_id,type,relation_type,relation_id,relation_name,create_user,create_dept,create_time,update_user,update_time,status,is_deleted from m_sign_config_relation
+        WHERE is_deleted = 0
+        <if test="type != null">
+            and type = #{type}
+        </if>
+        <if test="confId != null">
+            and conf_id = #{confId}
+        </if>
+    </select>
+    <select id="selectPageByRoleId" resultType="org.springblade.manager.entity.SignConfig">
+        select a.id,a.e_name,a.e_id,a.e_key,a.table_type,a.element_type,a.tenant_id,a.create_user,a.create_dept,a.create_time,a.update_user,a.update_time,a.status,a.is_deleted
+        from m_sign_config a WHERE a.is_deleted = 0
+        and ( SELECT count(1) from m_sign_config_relation  where type = 1 and is_deleted = 0 and conf_id = a.id
+        <if test="roleId != null">
+            and relation_id = #{roleId}
+        </if>
+        <if test="relationType != null">
+            and relation_type = #{relationType}
+        </if>
+        limit 1 ) > 0
+        <if test="keyword != null and keyword != ''">
+            and a.e_name like concat('%',#{keyword},'%')
+        </if>
+    </select>
+    <select id="getConfigByENames" resultMap="signConfigVO">
+        select a.id,a.e_name,a.e_id,a.e_key,a.table_type,a.element_type,a.tenant_id,a.create_user,a.create_dept,a.create_time,a.update_user,a.update_time,a.status,a.is_deleted,
+               b.id,b.conf_id,b.type,b.relation_type,b.relation_id,b.relation_name,b.create_user,b.create_dept,b.create_time,b.update_user,b.update_time,b.status,b.is_deleted
+        from m_sign_config a LEFT JOIN m_sign_config_relation b
+            on a.id = b.conf_id WHERE a.`status` = 1 and a.is_deleted = 0 and b.is_deleted = 0
+        <if test="names != null">
+            and a.e_name in
+            <foreach item="item" index="index" collection="names" open="(" separator="," close=")">
+                #{item}
+            </foreach>
+        </if>
+    </select>
+
+
+</mapper>

+ 35 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/SignConfigRelationMapper.java

@@ -0,0 +1,35 @@
+/*
+ *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *  Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the dreamlu.net developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: Chill 庄骞 (smallchill@163.com)
+ */
+package org.springblade.manager.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+import org.springblade.manager.entity.SignConfig;
+import org.springblade.manager.entity.SignConfigRelation;
+import org.springblade.system.vo.RoleVO2;
+
+import java.util.List;
+
+/**
+ * 电签配置关联表 Mapper 接口
+ *
+ * @author BladeX
+ * @since 2025-05-27
+ */
+public interface SignConfigRelationMapper extends BaseMapper<SignConfigRelation> {
+
+}

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

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.manager.mapper.SignConfigRelationMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="signConfigRelationResultMap" type="org.springblade.manager.entity.SignConfigRelation">
+        <result column="id" property="id"/>
+        <result column="create_user" property="createUser"/>
+        <result column="create_dept" property="createDept"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_user" property="updateUser"/>
+        <result column="update_time" property="updateTime"/>
+        <result column="status" property="status"/>
+        <result column="is_deleted" property="isDeleted"/>
+        <result column="relation_id" property="relationId"/>
+        <result column="relation_name" property="relationName"/>
+        <result column="relation_type" property="relationType"/>
+        <result column="conf_id" property="confId"/>
+    </resultMap>
+
+</mapper>

+ 6 - 2
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/TextdictInfoMapper.xml

@@ -23,6 +23,10 @@
         <result column="time_col_key" property="timeColKey"/>
     </resultMap>
 
+    <resultMap id="textdictInfoVoResultMap" type="org.springblade.manager.vo.TextdictInfoVO" extends="textdictInfoResultMap">
+
+    </resultMap>
+
     <select id="selectTextdictInfoPage" resultMap="textdictInfoResultMap">
         select distinct * from m_textdict_info where is_deleted = 0
         <if test="param2.type== 2 ">
@@ -40,13 +44,13 @@
         select  *,(SELECT parent_id from blade_role c where c.id=b.sig_role_id) as parentRoleId from m_textdict_info b where is_deleted = 0 and id=#{id}
     </select>
 
-    <select id="selectTextdictInfoByExcelId" resultMap="textdictInfoResultMap">
+    <select id="selectTextdictInfoByExcelId" resultMap="textdictInfoVoResultMap">
         SELECT a.* from m_textdict_info a,
                         (select tab_id,count(1) from m_textdict_info where is_deleted = 0 and type in('2','6') and excel_id=#{param2.excelId} GROUP BY tab_id ORDER BY count(tab_id) desc LIMIT 1) b
         where a.tab_id=b.tab_id and a.is_deleted = 0 and a.type in('2','6') and a.excel_id=#{param2.excelId}
     </select>
 
-    <select id="selectTextdictBYIds" resultMap="textdictInfoResultMap">
+    <select id="selectTextdictBYIds" resultMap="textdictInfoVoResultMap">
         SELECT a.* from m_textdict_info a
         where project_id=#{projectId} and  id in
         <foreach collection="ids" item="id" open="(" close=")" separator=",">

+ 7 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsFormElementMapper.java

@@ -77,4 +77,11 @@ public interface WbsFormElementMapper extends BaseMapper<WbsFormElement> {
      * @return
      */
     Integer selectFiledDataMaxLength(@Param("tableName") String initTableName,@Param("key") String eKey);
+
+    /**
+     * 统计当前表所有字段长度
+     * @param initTableName
+     * @return
+     */
+    int selectSumColumnLength(@Param("database") String database,@Param("tableName") String initTableName);
 }

+ 12 - 2
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsFormElementMapper.xml

@@ -167,10 +167,20 @@
         SELECT data_type FROM information_schema.columns WHERE table_name=#{initTableName} AND column_name = #{eKey}
     </select>
     <select id="selectFiledLength" resultType="java.util.Map">
-        select column_name `key`,character_octet_length length from INFORMATION_SCHEMA.COLUMNS  where table_name = #{initTableName}
+        select column_name `key`,character_maximum_length length from INFORMATION_SCHEMA.COLUMNS  where table_name = #{initTableName}
     </select>
     <select id="selectFiledDataMaxLength" resultType="java.lang.Integer">
-        select MAX(LENGTH(${key})) from ${tableName}
+        select IFNULL(MAX(CHAR_LENGTH(${key})),0) from ${tableName}
+    </select>
+    <select id="selectSumColumnLength" resultType="java.lang.Integer">
+        SELECT
+            SUM( CHARACTER_MAXIMUM_LENGTH )
+        FROM
+            information_schema.COLUMNS
+        WHERE
+            TABLE_SCHEMA = #{database}
+            AND TABLE_NAME = #{tableName}
+            AND DATA_TYPE = 'varchar'
     </select>
 
 </mapper>

+ 3 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreeContractMapper.java

@@ -146,4 +146,7 @@ public interface WbsTreeContractMapper extends EasyBaseMapper<WbsTreeContract> {
     void updateSortNotIsUseSort(@Param("type") int type,
                                 @Param("projectId") Long projectId,
                                 @Param("pKeyId") Long pKeyId);
+
+    void updateSortByPId(@Param("pId") Long pId,
+                         @Param("sort") Integer sort);
 }

+ 7 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreeContractMapper.xml

@@ -816,6 +816,13 @@
             a.project_id = #{projectId}
           AND a.is_deleted = 0
     </update>
+    <update id="updateSortByPId">
+        update
+            m_wbs_tree_contract
+        set
+            sort = sort +1
+        where p_id = #{pId} and sort >= #{sort}
+    </update>
 
     <select id="selectQueryValueLikeNodeName" resultMap="ResultMap">
         select *

+ 2 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreePrivateMapper.java

@@ -144,4 +144,6 @@ public interface WbsTreePrivateMapper extends EasyBaseMapper<WbsTreePrivate> {
      */
     void updateBatchAncestorsByPKeyId(@Param("allNodes") List<WbsTreePrivate> allNodes);
 
+    void updateSortByPId(@Param("pId") Long pId,
+                         @Param("sort") Integer sort);
 }

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

@@ -929,6 +929,11 @@
             where p_key_id = #{item.pKeyId}
         </foreach>
     </update>
+    <update id="updateSortByPId">
+        update m_wbs_tree_private
+        set sort = sort + 1
+        where p_id = #{pId} and sort >= #{sort}
+    </update>
 
     <select id="linkNodeTreeBynodeId" resultType="java.lang.Long" >
         select p_key_id from m_wbs_tree_private where `type` = 1 and is_deleted = 0

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

@@ -0,0 +1,21 @@
+package org.springblade.manager.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import org.springblade.manager.entity.WbsTreeSynchronousRecord;
+
+/**
+* @author LHB
+* @description 针对表【m_wbs_tree_synchronous_record(WBS同步记录表)】的数据库操作Mapper
+* @createDate 2025-05-15 13:52:09
+* @Entity generator.domain.MWbsTreeSynchronousRecord
+*/
+public interface WbsTreeSynchronousRecordMapper extends BaseMapper<WbsTreeSynchronousRecord> {
+
+}
+
+
+
+

+ 30 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreeSynchronousRecordMapper.xml

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.manager.mapper.WbsTreeSynchronousRecordMapper">
+
+    <resultMap id="BaseResultMap" type="org.springblade.manager.entity.WbsTreeSynchronousRecord">
+            <id property="id" column="id" />
+            <result property="projectId" column="project_id" />
+            <result property="projectName" column="project_name" />
+            <result property="range" column="range" />
+            <result property="source" column="source" />
+            <result property="type" column="type" />
+            <result property="nodeId" column="node_id" />
+            <result property="nodeName" column="node_name" />
+            <result property="isDeleted" column="is_deleted" />
+            <result property="createTime" column="create_time" />
+            <result property="createUser" column="create_user" />
+            <result property="createUserId" column="create_user_id" />
+            <result property="updateTime" column="update_time" />
+            <result property="updateUser" column="update_user" />
+            <result property="updateUserId" column="update_user_id" />
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,project_id,project_name,range,source,type,
+        node_id,node_name,is_deleted,create_time,create_user,
+        create_user_id,update_time,update_user,update_user_id
+    </sql>
+</mapper>

+ 12 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/ISignConfigRelationService.java

@@ -0,0 +1,12 @@
+package org.springblade.manager.service;
+
+import org.springblade.core.mp.base.BaseService;
+import org.springblade.manager.entity.SignConfig;
+import org.springblade.manager.entity.SignConfigRelation;
+import org.springblade.system.vo.RoleVO2;
+
+import java.util.List;
+
+public interface ISignConfigRelationService extends BaseService<SignConfigRelation> {
+
+}

+ 34 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/ISignConfigService.java

@@ -0,0 +1,34 @@
+package org.springblade.manager.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springblade.core.mp.base.BaseService;
+import org.springblade.manager.dto.SignConfigDTO;
+import org.springblade.manager.entity.SignConfig;
+import org.springblade.manager.entity.SignConfigRelation;
+import org.springblade.manager.entity.TableInfo;
+import org.springblade.manager.vo.SignConfigVO;
+import org.springblade.manager.vo.TextdictInfoVO;
+import org.springblade.manager.vo.WbsFormElementVO3;
+import org.springblade.system.vo.RoleVO;
+import org.springblade.system.vo.RoleVO2;
+
+import java.util.List;
+
+public interface ISignConfigService extends BaseService<SignConfig> {
+
+    List<RoleVO2> getRoleList(Integer type, String roleName);
+
+    List<SignConfigRelation> getSignConfigRelationListByConfId(Long confId, Integer type);
+
+    Boolean addOrEdit(List<SignConfigDTO> signConfigDTOs);
+
+    List<WbsFormElementVO3> elementList();
+
+    IPage<SignConfigVO> selectPageByRoleId(IPage<SignConfig> page, Long roleId, String keyword, Integer relationType);
+
+    List<RoleVO> queryAllRoleList(Integer type, String roleName);
+
+    List<TableInfo> tableList(Integer tableType, String name);
+
+    List<TextdictInfoVO> hasSignConfig(String initTableName, List<String> keys, TextdictInfoVO vo);
+}

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

@@ -20,6 +20,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import org.springblade.core.tool.api.R;
 import org.springblade.manager.dto.RangeInfo;
 import org.springblade.manager.entity.TextdictInfo;
+import org.springblade.manager.vo.TextdictBy345VO;
 import org.springblade.manager.vo.TextdictDataInfoVO;
 import org.springblade.manager.vo.TextdictInfoVO;
 import org.springblade.core.mp.base.BaseService;
@@ -47,4 +48,10 @@ public interface ITextdictInfoService extends IService<TextdictInfo> {
     void deleDataInfoById(String id);
 
     TextdictInfo selectTextdictInfoOne(String id,String sigRoleId,String projectId);
+
+    IPage<TextdictInfoVO> analysisHtmlDefault(String tabId);
+
+    void removeHtmlDefault(String tabId, String colKey);
+
+    void saveHtmlDefault(TextdictBy345VO textdictInfo);
 }

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

@@ -65,7 +65,6 @@ public interface IWbsTreePrivateService extends BaseService<WbsTreePrivate> {
     void eVisInfoRepeatDel(String pid);
 
     boolean syncNodeTable(String primaryKeyId);
-    List<WbsTreePrivate> syncNodeTable(String primaryKeyIdm,String a);
 
     R addWbsTreeContractInfo(String nodeId, String primaryKeyIds, Long contractId);
 

+ 25 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/WbsTreeSynchronousRecordService.java

@@ -0,0 +1,25 @@
+package org.springblade.manager.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.springblade.core.mp.support.Query;
+import org.springblade.manager.entity.ProjectInfo;
+import org.springblade.manager.entity.WbsTreePrivate;
+import org.springblade.manager.entity.WbsTreeSynchronousRecord;
+import org.springblade.manager.vo.WbsTreeSynchronousRecordVo;
+
+import java.util.List;
+
+/**
+* @author LHB
+* @description 针对表【m_wbs_tree_synchronous_record(WBS同步记录表)】的数据库操作Service
+* @createDate 2025-05-15 13:52:09
+*/
+public interface WbsTreeSynchronousRecordService extends IService<WbsTreeSynchronousRecord> {
+
+    WbsTreeSynchronousRecord insert(WbsTreeSynchronousRecord mWbsTreeSynchronousRecord);
+
+    List<WbsTreeSynchronousRecordVo> getProjectTemplate(String nodeIds);
+
+    WbsTreeSynchronousRecord getNodeStatus(Long id);
+}

+ 33 - 7
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ArchiveTreeContractSyncImpl.java

@@ -367,7 +367,7 @@ public class ArchiveTreeContractSyncImpl {
         Map<Long,WbsTreeContractVO6> wbsTreeContractVO6Map = new HashMap<>();
         // keyid 到id的映射
         Map<Long,Long> wbsTreeKeyToIdMap = new HashMap<>();
-        Map<Long,Integer> wbsTreeKeyToSortMap = new HashMap<>();
+        Map<Long,Integer> wbsTreeKeyToSortMap = new LinkedHashMap<>();
         for (WbsTreeContractVO6 wbsTreeContractVO6 : wbsTreeContractVO6s) {
             i++;
             wbsTreeKeyToSortMap.put(wbsTreeContractVO6.getPKeyId(),i);
@@ -381,7 +381,7 @@ public class ArchiveTreeContractSyncImpl {
 
         //同步质检关联节点
         syncNodes(contractId, informationQueryList, wbsTreeContractVO6Map, wbsTreeKeyToSortMap,
-                wbsTreeKeyToIdMap, archiveKeyIdMap, contractIndfo,classify,orgContractId);
+                wbsTreeKeyToIdMap, archiveKeyIdMap, contractIndfo,classify,orgContractId,archiveFiles);
 
 
         //wbs的keyId到 归档树的映射
@@ -467,8 +467,8 @@ public class ArchiveTreeContractSyncImpl {
 
     private void syncNodes(Long contractId, List<InformationQuery> informationQueryList,
                            Map<Long, WbsTreeContractVO6> wbsTreeContractVO6Map, Map<Long, Integer> wbsTreeKeyToSortMap,
-                           Map<Long, Long> wbsTreeKeyToIdMap, Map<Long, ArchiveFile> archiveKeyIdMap,
-                           ContractInfo contractIndfo,Integer classify,Long orgContractId) {
+                           Map<Long, Long> wbsTreeKeyToIdMap, Map<Long, ArchiveFile> checkMap,
+                           ContractInfo contractIndfo,Integer classify,Long orgContractId,List<ArchiveFile>  archiveFiles) {
         // 获取关联节点的合同段id
         Long associatedContractId = contractId;
         if (classify == 2) {
@@ -484,6 +484,7 @@ public class ArchiveTreeContractSyncImpl {
 
         Map<Long,Long> archiveTreeContractIdMap = new LinkedHashMap<>();
 
+
         for (ArchiveTreeContract node : associatedNodes) {
             Integer nodeLevel = Integer.valueOf(node.getDisplayHierarchy());
 
@@ -495,12 +496,37 @@ public class ArchiveTreeContractSyncImpl {
             // 获取该合同段下的wbs节点
             List<ArchiveTreeContract> archiveTreeContracts = getArchiveTreeContractsWbs(contractId, node.getId(),classify);
 
+            Set<Long> archiveTreeContractIds = archiveTreeContracts.stream()
+                    .map(ArchiveTreeContract::getId)
+                    .collect(Collectors.toSet());
+
             // 更新archiveTreeContractIdMap映射
              archiveTreeContractIdMap.clear();
             for (ArchiveTreeContract ar : archiveTreeContracts) {
                 archiveTreeContractIdMap.put(ar.getExtKeyId(), ar.getId());
             }
 
+            Map<Long, ArchiveFile> archiveKeyIdMap = new LinkedHashMap<>();
+            for (ArchiveFile file : archiveFiles) {
+                // 获取nodeId字符串
+                String nodeIdStr = file.getNodeId();
+                if (nodeIdStr != null && !nodeIdStr.isEmpty()) {
+                    try {
+                        Long nodeIdLong = Long.parseLong(nodeIdStr);
+                        // 如果转换后的nodeIdLong在archiveTreeContractIds集合中,则加入映射
+                        if (archiveTreeContractIds.contains(nodeIdLong)) {
+                            // 注意:这里使用file.getNodeExtId()作为key(原始代码逻辑)
+                            if (file.getNodeExtId()!= null) {
+                                archiveKeyIdMap.put(file.getNodeExtId(),file);
+                            }
+                        }
+                    } catch (NumberFormatException e) {
+                        // 转换失败,忽略这个文件
+                        log.warn("文件nodeId不是有效的数字: {}, 文件ID: {}", nodeIdStr, file.getId());
+                    }
+                }
+            }
+
             syncNode(informationQueryList, wbsTreeContractVO6Map, wbsTreeKeyToSortMap, wbsTreeKeyToIdMap,
                     archiveKeyIdMap, archiveTreeContractIdMap,
                     nodeLevel, node.getMajorDataType(), contractIndfo,classify);
@@ -565,9 +591,9 @@ public class ArchiveTreeContractSyncImpl {
                     // 2024 08 19
                     // else  if (info.getEVisaPdfUrl() != null && !info.getEVisaPdfUrl().equals(archiveFile.getPdfFileUrl())
                     //         || sort != null && !sort.equals(archiveFile.getSort())) {
-                    else  if (info.getNodePdfUrl() != null && !info.getNodePdfUrl().equals(archiveFile.getPdfFileUrl())
-                                || sort != null && !sort.equals(archiveFile.getSort())
-                                || nodeId != null && !nodeId.toString().equals(archiveFile.getNodeId())
+                    else  if ( (info.getNodePdfUrl() != null && !info.getNodePdfUrl().equals(archiveFile.getPdfFileUrl()))
+                                || (sort != null && !sort.equals(archiveFile.getSort()))
+                                || (nodeId != null && !nodeId.toString().equals(archiveFile.getNodeId()))
                                 || (StringUtils.isNotEmpty(info.getBusinessTime() ) && !info.getBusinessTime().equals(archiveFile.getFileTime()))
                                 || (info.getEVisaPdfSize()!= null && info.getEVisaPdfSize() > 0L && !info.getEVisaPdfSize().equals(archiveFile.getFileSize()))
                     ) {

+ 26 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/FormulaServiceImpl.java

@@ -684,7 +684,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                         return;
                     }
                     List<Map<String, Object>> tableNamePkIdsMaps = this.jdbcTemplate.queryForList(
-                            "select c.init_table_name tableName,c.p_key_id pkId,c.html_url url from" +
+                            "select c.init_table_name tableName,c.p_key_id pkId,c.html_url url,c.p_id from" +
                                     " (select id from m_wbs_tree_contract where contract_id=" + currentNode.getContractId() + " and is_deleted=0 and node_type=6 and tree_code like '" + parent.getTreeCode() + "%' ORDER BY sort) k" +
                                     " join m_wbs_tree_contract c on c.parent_id = k.id " +
                                     "where  c.contract_id=" + currentNode.getContractId() + " and c.is_deleted=0 "
@@ -705,6 +705,31 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                                 }
                                 List<Map<String, Object>> tableDatas = this.jdbcTemplate.queryForList("select * from " + tn + " where p_key_id in (" + targetIds + ")");
                                 String tmp = elementInfo == null ? "" : StringUtils.handleNull(elementInfo.get("ename"));
+                                // 优先查找当前节点下的元素
+                                if (!tableDatas.isEmpty()) {
+                                    Map<Long, Long> map = new HashMap<>();
+                                    tableNamePkIdsMaps.forEach(m -> {
+                                        if (StringUtils.isEquals(m.get("tableName"), tn)) {
+                                            Object o = m.get("pkId");
+                                            Object o1 = m.get("p_id");
+                                            if(o instanceof Long && currentNode.getPkId().equals(o1)) {
+                                                map.put((Long) o, 1L);
+                                            }
+                                        }
+                                    });
+                                    if (!map.isEmpty()) {
+                                        List<Map<String, Object>> datas = tableDatas.stream().filter(t -> {
+                                            Object pKeyId = t.get("p_key_id");
+                                            if (pKeyId instanceof Long) {
+                                                return map.containsKey(pKeyId);
+                                            }
+                                            return false;
+                                        }).collect(Collectors.toList());
+                                        if (!datas.isEmpty()) {
+                                            tableDatas = datas;
+                                        }
+                                    }
+                                }
                                 fill(tableDatas, removeList, tn, key, tmp, tec);
                             }
                         });

+ 38 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/SignConfigRelationServiceImpl.java

@@ -0,0 +1,38 @@
+/*
+ *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *  Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the dreamlu.net developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: Chill 庄骞 (smallchill@163.com)
+ */
+package org.springblade.manager.service.impl;
+
+
+import lombok.AllArgsConstructor;
+import org.springblade.core.mp.base.BaseServiceImpl;
+import org.springblade.manager.entity.SignConfigRelation;
+import org.springblade.manager.mapper.SignConfigRelationMapper;
+import org.springblade.manager.service.ISignConfigRelationService;
+import org.springframework.stereotype.Service;
+
+
+/**
+ * 电签配置关联表 服务实现类
+ *
+ * @author BladeX
+ * @since 2025-05-27
+ */
+@Service
+@AllArgsConstructor
+public class SignConfigRelationServiceImpl extends BaseServiceImpl<SignConfigRelationMapper, SignConfigRelation> implements ISignConfigRelationService {
+
+}

+ 381 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/SignConfigServiceImpl.java

@@ -0,0 +1,381 @@
+/*
+ *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *  Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the dreamlu.net developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: Chill 庄骞 (smallchill@163.com)
+ */
+package org.springblade.manager.service.impl;
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.AllArgsConstructor;
+import org.springblade.core.log.exception.ServiceException;
+import org.springblade.core.mp.base.BaseServiceImpl;
+import org.springblade.core.secure.utils.AuthUtil;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.BeanUtil;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.manager.dto.SignConfigDTO;
+import org.springblade.manager.entity.SignConfig;
+import org.springblade.manager.entity.SignConfigRelation;
+import org.springblade.manager.entity.TableInfo;
+import org.springblade.manager.entity.WbsFormElement;
+import org.springblade.manager.mapper.SignConfigMapper;
+import org.springblade.manager.mapper.WbsFormElementMapper;
+import org.springblade.manager.service.ISignConfigRelationService;
+import org.springblade.manager.service.ISignConfigService;
+import org.springblade.manager.service.ITableInfoService;
+import org.springblade.manager.utils.WbsElementUtil;
+import org.springblade.manager.vo.SignConfigVO;
+import org.springblade.manager.vo.TextdictInfoVO;
+import org.springblade.manager.vo.WbsFormElementVO3;
+import org.springblade.manager.wrapper.SignConfigWrapper;
+import org.springblade.system.feign.ISysClient;
+import org.springblade.system.vo.RoleVO;
+import org.springblade.system.vo.RoleVO2;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.support.TransactionTemplate;
+
+import javax.validation.constraints.NotEmpty;
+import java.util.*;
+import java.util.stream.Collectors;
+
+
+/**
+ * 电签配置 服务实现类
+ *
+ * @author BladeX
+ * @since 2025-05-27
+ */
+@Service
+@AllArgsConstructor
+public class SignConfigServiceImpl extends BaseServiceImpl<SignConfigMapper, SignConfig> implements ISignConfigService {
+
+    private final ITableInfoService tableInfoService;
+
+    private final WbsFormElementMapper wbsFormElementMapper;
+
+    private final TransactionTemplate transactionTemplate;
+
+    private final ISignConfigRelationService signConfigRelationService;
+
+    private final ISysClient sysClient;
+
+    @Override
+    public List<RoleVO2> getRoleList(Integer relationType, String roleName) {
+        return this.baseMapper.getRoleList(relationType, roleName);
+    }
+
+    @Override
+    public List<SignConfigRelation> getSignConfigRelationListByConfId(Long confId, Integer type) {
+        return this.baseMapper.getSignConfigRelationListByConfId(confId, type);
+    }
+
+    @Override
+    public Boolean addOrEdit(List<SignConfigDTO> signConfigDTOs) {
+        signConfigDTOs.forEach(signConfigDTO -> {
+            SignConfig config = new SignConfig();
+            BeanUtil.copyProperties(signConfigDTO, config);
+            if (signConfigDTO.getElementId() == null) {
+                if (signConfigDTO.getEId() == null) {
+                    throw new ServiceException("请选择元素");
+                }
+                signConfigDTO.setElementId(signConfigDTO.getEId() + "");
+            }
+            WbsFormElement element = wbsFormElementMapper.selectById(signConfigDTO.getElementId());
+            if (element == null) {
+                throw new ServiceException("未查找到该元素,请重新选择");
+            }
+            config.setEId(element.getId());
+            config.setTenantId(AuthUtil.getTenantId());
+            config.setEKey(element.getEKey());
+            config.setElementType(element.getEType());
+            config.setEName(element.getEName());
+            List<String> roleIds = signConfigDTO.getRoleIds();
+            List<SignConfigRelation> signConfigRelationsByRoles = new ArrayList<>();
+            List<SignConfigRelation> signConfigRelationsByTables = new ArrayList<>();
+            if (roleIds != null && !roleIds.isEmpty()) {
+                R<List<RoleVO>> roleResult = sysClient.search();
+                if (!roleResult.isSuccess() || roleResult.getData() == null || roleResult.getData().isEmpty()) {
+                    throw new ServiceException("获取岗位信息失败");
+                }
+                List<RoleVO> data = roleResult.getData();
+                Map<String, RoleVO> roleVOMap = new HashMap<>();
+                //先处理管理员
+                for (RoleVO vos : data) {
+                    if (vos.getRoleName().contains("施工方") || vos.getRoleName().contains("监理方") || vos.getRoleName().contains("业主方")) {
+                        List<RoleVO> children = vos.getChildren();
+                        roleVOMap.put(vos.getId() + "", vos);
+                        if (children != null && !children.isEmpty()) {
+                            children.forEach(child -> roleVOMap.put(child.getId() + "", child));
+                        }
+                    }
+                }
+                for (String roleId : roleIds) {
+                    RoleVO roleVO = roleVOMap.get(roleId);
+                    if (roleVO != null) {
+                        SignConfigRelation signConfigRelation = new SignConfigRelation();
+                        signConfigRelation.setRelationId(Long.valueOf(roleId));
+                        signConfigRelation.setType(1);
+                        signConfigRelation.setRelationName(roleVO.getRoleName());
+                        RoleVO parent = roleVOMap.get(roleVO.getParentId() + "");
+                        if (parent != null) {
+                            if (parent.getRoleName().contains("施工方")) {
+                                signConfigRelation.setRelationType(1);
+                            }
+                            if (parent.getRoleName().contains("监理方")) {
+                                signConfigRelation.setRelationType(2);
+                            }
+                            if (parent.getRoleName().contains("业主方")) {
+                                signConfigRelation.setRelationType(3);
+                            }
+                        }
+                        signConfigRelationsByRoles.add(signConfigRelation);
+                    }
+                }
+            }
+            List<String> tableIds = signConfigDTO.getTableIds();
+            if (tableIds != null && !tableIds.isEmpty()) {
+                List<TableInfo> tableInfos = tableInfoService.list(Wrappers.<TableInfo>lambdaQuery().select(TableInfo::getTabChName, TableInfo::getId, TableInfo::getTabType).in(TableInfo::getId, tableIds));
+                if (tableInfos == null || tableInfos.isEmpty()) {
+                    throw new ServiceException("获取元素表信息失败");
+                }
+                Map<String, TableInfo> tableMap = tableInfos.stream().collect(Collectors.toMap(tableInfo -> tableInfo.getId() + "", tab -> tab, (v1, v2) -> v1));
+                for (String tableId : tableIds) {
+                    TableInfo tableInfo = tableMap.get(tableId);
+                    if (tableInfo != null) {
+                        SignConfigRelation signConfigRelation = new SignConfigRelation();
+                        signConfigRelation.setRelationId(Long.valueOf(tableId));
+                        signConfigRelation.setType(0);
+                        signConfigRelation.setRelationName(tableInfo.getTabChName());
+                        signConfigRelation.setRelationType(tableInfo.getTabType());
+                        signConfigRelationsByTables.add(signConfigRelation);
+                    }
+                }
+                config.setTableType(1);
+            } else {
+                config.setTableType(0);
+            }
+            transactionTemplate.execute(transactionStatus -> {
+                if (config.getId() !=  null) {
+                    this.updateById(config);
+                    if (!signConfigRelationsByTables.isEmpty()) {
+                        signConfigRelationService.remove(Wrappers.<SignConfigRelation>lambdaQuery().eq(SignConfigRelation::getConfId, config.getId()).eq(SignConfigRelation::getType, 0));
+                    }
+                    if (!signConfigRelationsByRoles.isEmpty()) {
+                        signConfigRelationService.remove(Wrappers.<SignConfigRelation>lambdaQuery().eq(SignConfigRelation::getConfId, config.getId()).eq(SignConfigRelation::getType, 1));
+                    }
+                } else {
+                    this.save(config);
+                }
+                if (!signConfigRelationsByRoles.isEmpty()) {
+                    signConfigRelationsByRoles.forEach(signConfigRelation -> signConfigRelation.setConfId(config.getId()));
+                    this.signConfigRelationService.saveBatch(signConfigRelationsByRoles);
+                }
+                if (!signConfigRelationsByTables.isEmpty()) {
+                    signConfigRelationsByTables.forEach(signConfigRelation -> signConfigRelation.setConfId(config.getId()));
+                    this.signConfigRelationService.saveBatch(signConfigRelationsByTables);
+                }
+                return true;
+            });
+        });
+        return true;
+    }
+
+    @Override
+    public List<WbsFormElementVO3> elementList() {
+        List<WbsFormElement> list = wbsFormElementMapper.selectList(Wrappers.<WbsFormElement>lambdaQuery().select(WbsFormElement::getEName, WbsFormElement::getId, WbsFormElement::getEType)
+                .eq(WbsFormElement::getEType, WbsElementUtil.getElementType("签名")).groupBy(WbsFormElement::getEName));
+        List<WbsFormElementVO3> result =  list.stream().map(element -> {
+            WbsFormElementVO3 vo = new WbsFormElementVO3();
+            vo.setId(element.getId());
+            vo.setEName(element.getEName());
+            vo.setEType(element.getEType());
+            vo.setETypeName(WbsElementUtil.getElementTypeName(element.getEType()));
+            return vo;
+        }).collect(Collectors.toList());
+        return result;
+    }
+
+    @Override
+    public IPage<SignConfigVO> selectPageByRoleId(IPage<SignConfig> page, Long roleId, String keyword, Integer relationType) {
+        List<SignConfig> signConfigs = baseMapper.selectPageByRoleId(page, roleId, keyword, relationType);
+        page.setRecords(signConfigs);
+        IPage<SignConfigVO> pageVO = SignConfigWrapper.build().pageVO(page);
+        List<SignConfigVO> records = pageVO.getRecords();
+        List<Long> ids = records.stream().map(SignConfigVO::getId).collect(Collectors.toList());
+        if (!ids.isEmpty()) {
+            List<SignConfigRelation> signConfigRelations = signConfigRelationService.list(Wrappers.<SignConfigRelation>lambdaQuery().select(SignConfigRelation::getConfId, SignConfigRelation::getRelationId, SignConfigRelation::getType)
+                    .in(SignConfigRelation::getConfId, ids).eq(SignConfigRelation::getIsDeleted, 0));
+            Map<Long, Map<Integer, List<SignConfigRelation>>> map = signConfigRelations.stream().collect(Collectors.groupingBy(SignConfigRelation::getConfId, Collectors.groupingBy(SignConfigRelation::getType)));
+            records.forEach(record -> {
+                Map<Integer, List<SignConfigRelation>> listMap = map.get(record.getId());
+                if (listMap != null) {
+                    List<SignConfigRelation> list = listMap.get(1);
+                    if (list != null) {
+                        record.setRoleIds(list.stream().map(SignConfigRelation::getRelationId).map(String::valueOf).collect(Collectors.toList()));
+                    }
+                    list = listMap.get(0);
+                    if (list != null) {
+                        record.setTableIds(list.stream().map(SignConfigRelation::getRelationId).map(String::valueOf).collect(Collectors.toList()));
+                    }
+                }
+            });
+        }
+        return pageVO;
+    }
+
+    @Override
+    public List<RoleVO> queryAllRoleList(Integer type, String roleName) {
+        //获取当前系统配置的角色划分
+        R<List<RoleVO>> result = this.sysClient.search();
+        if (!result.isSuccess() || result.getData() == null || result.getData().isEmpty()) {
+            throw new ServiceException("获取岗位信息失败");
+        }
+        List<RoleVO> roleVOS = result.getData();
+        List<RoleVO> roles = new ArrayList<>();
+        //先处理管理员
+        for (RoleVO vos : roleVOS) {
+            if (vos.getRoleName().contains("施工方") || vos.getRoleName().contains("监理方") || vos.getRoleName().contains("业主方")) {
+                if (type != null ) {
+                    if (type == 1 && vos.getRoleName().contains("施工方")) {
+                        roles = vos.getChildren();
+                    } else if (type == 2 && vos.getRoleName().contains("监理方")) {
+                        roles = vos.getChildren();
+                    } else if (type == 3 && vos.getRoleName().contains("业主方")) {
+                        roles = vos.getChildren();
+                    }
+                } else {
+                    roles.addAll(vos.getChildren());
+                }
+            }
+        }
+        if (roleName != null && !roleName.isEmpty()) {
+            if (roles != null && !roles.isEmpty()) {
+                List<RoleVO> temp = new ArrayList<>();
+                for (RoleVO role : roles) {
+                    if (role.getRoleName().contains(roleName)) {
+                        temp.add(role);
+                        List<RoleVO> children = role.getChildren();
+                        if (children != null && !children.isEmpty()) {
+                            List<RoleVO> temp1 = new ArrayList<>();
+                            for (RoleVO child2 : children) {
+                                if (child2.getRoleName().contains(roleName)) {
+                                    temp1.add(child2);
+                                }
+                            }
+                            role.setChildren(temp1);
+                        }
+                    }
+                }
+                return temp;
+            }
+        }
+        return roles;
+    }
+
+    @Override
+    public List<TableInfo> tableList(Integer tableType, String name) {
+        List<TableInfo> tableInfos = this.tableInfoService.list(Wrappers.<TableInfo>lambdaQuery().eq(tableType != null, TableInfo::getTabType, tableType).like(name != null && !name.isEmpty(), TableInfo::getTabChName, name));
+        tableInfos.sort(Comparator.comparingInt(TableInfo::getTabType));
+        return tableInfos;
+    }
+
+    @Override
+    public List<TextdictInfoVO> hasSignConfig(String initTableName, List<String> keyNames, TextdictInfoVO vo) {
+        List<TextdictInfoVO> textdictInfoVOS = new ArrayList<>();
+        if (keyNames == null || keyNames.isEmpty()) {
+            return textdictInfoVOS;
+        }
+        Map<String, String> keyMap = keyNames.stream().collect(Collectors.toMap(key -> key.split("__")[0], key -> key, (key1, key2) -> key1));
+        List<TableInfo> tableInfos = this.tableInfoService.list(Wrappers.<TableInfo>lambdaQuery().select(TableInfo::getId).eq(TableInfo::getTabEnName, initTableName));
+        if (tableInfos == null || tableInfos.isEmpty()) {
+            return textdictInfoVOS;
+        }
+        List<WbsFormElement> list = this.wbsFormElementMapper.selectList(Wrappers.<WbsFormElement>lambdaQuery().select(WbsFormElement::getEName, WbsFormElement::getEKey)
+                .eq(WbsFormElement::getFId, tableInfos.get(0).getId()).in(WbsFormElement::getEKey, keyMap.keySet()));
+        if (list == null || list.isEmpty()) {
+            return textdictInfoVOS;
+        }
+        Set<String> names = list.stream().map(WbsFormElement::getEName).collect(Collectors.toSet());
+        List<SignConfigVO> signConfigs = this.baseMapper.getConfigByENames(names);
+        if (signConfigs == null || signConfigs.isEmpty()) {
+            return textdictInfoVOS;
+        }
+        Map<String, List<SignConfigVO>> map = signConfigs.stream().collect(Collectors.groupingBy(SignConfigVO::getEName));
+        Map<String, String> keyNameMap = list.stream().collect(Collectors.toMap(WbsFormElement::getEKey, WbsFormElement::getEName));
+        keyMap.forEach((key, value) -> {
+            String colName = keyNameMap.get(key);
+            if (colName == null) {
+                return;
+            }
+            List<SignConfigVO> signConfigVOS = map.get(colName);
+            if (signConfigVOS == null || signConfigVOS.isEmpty()) {
+                return;
+            }
+            Map<Long, String> roleIdNameMap = new HashMap<>();
+            signConfigVOS.forEach(signConfigVO -> {
+                List<SignConfigRelation> relations = signConfigVO.getRelations();
+                if (relations != null && !relations.isEmpty()) {
+                    Map<Integer, List<SignConfigRelation>> collect = relations.stream().collect(Collectors.groupingBy(SignConfigRelation::getType));
+                    // 部分表,判断tableInfos是否在其中
+                    if (signConfigVO.getTableType() == 1) {
+                        List<SignConfigRelation> tables = collect.get(0);
+                        if (tables == null || tables.isEmpty()) {
+                            return;
+                        }
+                        Map<Long, SignConfigRelation> tableMap = tables.stream().collect(Collectors.toMap(SignConfigRelation::getRelationId, v -> v, (v1, v2) -> v1));
+                        SignConfigRelation relation = tableMap.get(tableInfos.get(0).getId());
+                        if (relation == null) {
+                            return;
+                        }
+                    }
+                    List<SignConfigRelation> roles = collect.get(1);
+                    if (roles != null && !roles.isEmpty()) {
+                        roles.forEach(role -> {
+                            roleIdNameMap.put(role.getRelationId(), role.getRelationName());
+                        });
+                    }
+                }
+            });
+            if (!roleIdNameMap.isEmpty()) {
+                roleIdNameMap.forEach((roleId, roleName) -> {
+                    TextdictInfoVO textdictInfoVO = new TextdictInfoVO();
+                    if (vo != null) {
+                        BeanUtil.copy(vo, textdictInfoVO);
+                    }
+                    textdictInfoVO.setId(null);
+                    textdictInfoVO.setColKey(value);
+                    textdictInfoVO.setColName(colName);
+                    textdictInfoVO.setIsSystem(1);
+                    textdictInfoVO.setSigRoleId(roleId + "");
+                    textdictInfoVO.setSigRoleName(roleName);
+                    textdictInfoVOS.add(textdictInfoVO);
+                });
+            }
+        });
+        return textdictInfoVOS;
+    }
+
+    @Override
+    public boolean deleteLogic(@NotEmpty List<Long> ids) {
+        if (!ids.isEmpty()) {
+            transactionTemplate.execute(status -> {
+                super.deleteLogic(ids);
+                return signConfigRelationService.remove(Wrappers.<SignConfigRelation>lambdaQuery().in(SignConfigRelation::getConfId, ids));
+            });
+        }
+        return true;
+    }
+}

部分文件因为文件数量过多而无法显示