huangtf 2 éve
szülő
commit
888cd2a835
85 módosított fájl, 4064 hozzáadás és 462 törlés
  1. 25 4
      blade-common/src/main/java/org/springblade/common/utils/CommonUtil.java
  2. 0 6
      blade-ops/blade-resource/pom.xml
  3. 16 3
      blade-ops/blade-resource/src/main/java/org/springblade/resource/endpoint/OssEndpoint.java
  4. 12 0
      blade-service-api/blade-archive-api/src/main/java/org/springblade/archive/entity/ArchivesAuto.java
  5. 104 0
      blade-service-api/blade-archive-api/src/main/java/org/springblade/archive/vo/ArchivesAutoVO.java
  6. 4 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/ArchiveFile.java
  7. 2 2
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/TrialDetectionData.java
  8. 3 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/TrialDeviceInfo.java
  9. 9 3
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/TrialLaboratoryUserArchives.java
  10. 3 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/TrialMaterialMobilization.java
  11. 5 3
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/TrialSampleInfo.java
  12. 15 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/feign/ArchiveFileClient.java
  13. 5 6
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/TrialSamplingRecordVO.java
  14. 2 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/ArchiveTreeVO2.java
  15. 14 4
      blade-service-api/blade-user-api/pom.xml
  16. 202 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchiveFileAutoController.java
  17. 82 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchiveFileController.java
  18. 6 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/ArchivesAutoMapper.java
  19. 54 3
      blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/ArchivesAutoMapper.xml
  20. 3 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/IArchivesAutoService.java
  21. 68 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchivesAutoServiceImpl.java
  22. 232 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/utils/FileUtils.java
  23. 4 0
      blade-service/blade-business/pom.xml
  24. 85 8
      blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java
  25. 5 6
      blade-service/blade-business/src/main/java/org/springblade/business/controller/TrialDetectionController.java
  26. 8 0
      blade-service/blade-business/src/main/java/org/springblade/business/controller/TrialDeviceInfoController.java
  27. 8 0
      blade-service/blade-business/src/main/java/org/springblade/business/controller/TrialMaterialController.java
  28. 5 3
      blade-service/blade-business/src/main/java/org/springblade/business/excel/TrialDeviceInfoExcel.java
  29. 1 1
      blade-service/blade-business/src/main/java/org/springblade/business/excel/TrialMaterialMobilizationExcel.java
  30. 3 3
      blade-service/blade-business/src/main/java/org/springblade/business/excel/TrialSampleInfoExcel.java
  31. 24 0
      blade-service/blade-business/src/main/java/org/springblade/business/feignClient/ArchiveFileClientImpl.java
  32. 4 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/ArchiveFileMapper.java
  33. 28 4
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/ArchiveFileMapper.xml
  34. 95 1
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/InformationQueryMapper.xml
  35. 1 1
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/TrialDeviceUseMapper.xml
  36. 2 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/IArchiveFileService.java
  37. 4 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/ITrialDetectionDataService.java
  38. 3 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/ITrialDeviceUseService.java
  39. 3 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/ITrialMaterialMobilizationService.java
  40. 0 2
      blade-service/blade-business/src/main/java/org/springblade/business/service/ITrialSelfInspectionRecordService.java
  41. 12 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/ArchiveFileServiceImpl.java
  42. 5 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialContainerClassificationServiceImpl.java
  43. 130 7
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialDetectionDataServiceImpl.java
  44. 65 25
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialDeviceInfoServiceImpl.java
  45. 23 6
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialDeviceOverhaulServiceImpl.java
  46. 71 12
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialDeviceUseServiceImpl.java
  47. 1 1
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialLaboratoryUserArchivesServiceImpl.java
  48. 70 13
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialMaterialMobilizationServiceImpl.java
  49. 53 18
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialSampleInfoServiceImpl.java
  50. 77 66
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialSelfInspectionRecordServiceImpl.java
  51. 1228 0
      blade-service/blade-business/src/main/java/org/springblade/business/utils/DateUtils.java
  52. 26 3
      blade-service/blade-manager/src/main/java/com/jfireel/expression/node/impl/MinusNode.java
  53. 18 3
      blade-service/blade-manager/src/main/java/com/jfireel/expression/node/impl/MutliNode.java
  54. 1 1
      blade-service/blade-manager/src/main/java/com/jfireel/expression/util/number/SubtractUtil.java
  55. 23 51
      blade-service/blade-manager/src/main/java/com/mixsmart/utils/CustomFunction.java
  56. 158 1
      blade-service/blade-manager/src/main/java/com/mixsmart/utils/FormulaUtils.java
  57. 4 4
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ArchiveTreeController.java
  58. 49 28
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java
  59. 1 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/FirstController.java
  60. 19 23
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/FormulaController.java
  61. 2 10
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ProjectInfoController.java
  62. 15 15
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsParamController.java
  63. 12 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreePrivateController.java
  64. 19 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/formula/ITurnPointCalculator.java
  65. 11 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/formula/TurnPoint.java
  66. 11 10
      blade-service/blade-manager/src/main/java/org/springblade/manager/formula/impl/FormulaMileage.java
  67. 13 9
      blade-service/blade-manager/src/main/java/org/springblade/manager/formula/impl/FormulaTurnPoint.java
  68. 82 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/formula/impl/SubTable.java
  69. 1 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/formula/impl/TableElementConverter.java
  70. 5 3
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ArchiveTreeMapper.java
  71. 6 5
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ArchiveTreeMapper.xml
  72. 1 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreePrivateMapper.xml
  73. 0 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IContractInfoService.java
  74. 1 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IExcelTabService.java
  75. 1 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IFormulaService.java
  76. 1 3
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/ITextdictInfoService.java
  77. 5 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IWbsTreeContractService.java
  78. 2 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IWbsTreePrivateService.java
  79. 46 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ArchiveAutoRuleWbsServiceImpl.java
  80. 24 13
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ArchiveTreeServiceImpl.java
  81. 28 25
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ExcelTabServiceImpl.java
  82. 397 29
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/FormulaServiceImpl.java
  83. 63 3
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeContractServiceImpl.java
  84. 60 3
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreePrivateServiceImpl.java
  85. 75 3
      blade-service/blade-manager/src/main/java/org/springblade/manager/utils/FileUtils.java

+ 25 - 4
blade-common/src/main/java/org/springblade/common/utils/CommonUtil.java

@@ -2,18 +2,17 @@ package org.springblade.common.utils;
 
 import cn.hutool.core.io.FileUtil;
 import org.apache.commons.lang.StringUtils;
+import org.springframework.util.CollectionUtils;
 
 import java.io.*;
 import java.math.BigDecimal;
 import java.net.HttpURLConnection;
 import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Random;
+import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * 通用工具类
@@ -186,4 +185,26 @@ public class CommonUtil {
         return dest;
     }
 
+    /**
+     * Description: Java8 Stream分割list集合
+     * @param list 集合数据
+     * @param splitSize 几个分割一组
+     * @return 集合分割后的集合
+     */
+    public static <T> List<List<T>> splitList(List<T> list, int splitSize) {
+        //判断集合是否为空
+        if (CollectionUtils.isEmpty(list))
+            return Collections.emptyList();
+        //计算分割后的大小
+        int maxSize = (list.size() + splitSize - 1) / splitSize;
+        //开始分割
+        return Stream.iterate(0, n -> n + 1)
+                .limit(maxSize)
+                .parallel()
+                .map(a -> list.parallelStream().skip(a * splitSize).limit(splitSize).collect(Collectors.toList()))
+                .filter(b -> !b.isEmpty())
+                .collect(Collectors.toList());
+    }
+
+
 }

+ 0 - 6
blade-ops/blade-resource/pom.xml

@@ -115,12 +115,6 @@
             <artifactId>pdfbox</artifactId>
             <version>2.0.20</version>
         </dependency>
-        <dependency>
-            <groupId>org.springblade</groupId>
-            <artifactId>blade-business</artifactId>
-            <version>2.9.1.RELEASE</version>
-            <scope>compile</scope>
-        </dependency>
     </dependencies>
 
     <build>

+ 16 - 3
blade-ops/blade-resource/src/main/java/org/springblade/resource/endpoint/OssEndpoint.java

@@ -36,9 +36,11 @@ import org.springblade.resource.vo.NewBladeFile;
 import org.springframework.beans.BeanUtils;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
-import org.springblade.business.utils.FileUtils;
-
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.util.Objects;
 
 /**
@@ -183,7 +185,18 @@ public class OssEndpoint {
 		//压缩文件大小
 		while (bytes.length > targetSize) {
 			float reduceMultiple = 0.5f;
-			bytes = FileUtils.resizeImage2(bytes, reduceMultiple);
+			BufferedImage bi = ImageIO.read(new ByteArrayInputStream(bytes));
+			int width = (int) (bi.getWidth() * reduceMultiple);
+			int height = (int) (bi.getHeight() * reduceMultiple);
+			Image image = bi.getScaledInstance(width, height, Image.SCALE_SMOOTH);
+			BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+			Graphics g = tag.getGraphics();
+			g.setColor(Color.RED);
+			g.drawImage(image, 0, 0, null);
+			g.dispose();
+			ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+			ImageIO.write(tag, "JPEG", bOut);
+			bytes =bOut.toByteArray();
 		}
 		ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
 		//上传文件

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

@@ -19,6 +19,8 @@ package org.springblade.archive.entity;
 import com.baomidou.mybatisplus.annotation.TableName;
 import java.io.Serializable;
 import java.time.LocalDateTime;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
 import org.springblade.core.mp.base.BaseEntity;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
@@ -71,10 +73,12 @@ public class ArchivesAuto extends BaseEntity {
 	/**
 	* 文件起始时间
 	*/
+		@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
 		private LocalDateTime startDate;
 	/**
 	* 文件结束时间
 	*/
+		@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
 		private LocalDateTime endDate;
 	/**
 	* 保管期限(单位/年)
@@ -144,5 +148,13 @@ public class ArchivesAuto extends BaseEntity {
 	private Integer isOpen;
 	private Integer ischeck;
 
+	//是否案卷收集上传的案卷
+	private Integer isAutoFile;
+
+	private Integer autoFileSort;
 
+	/**
+	 * 立卷单位
+	 * **/
+	private String filingUnit;
 }

+ 104 - 0
blade-service-api/blade-archive-api/src/main/java/org/springblade/archive/vo/ArchivesAutoVO.java

@@ -16,10 +16,14 @@
  */
 package org.springblade.archive.vo;
 
+import io.swagger.annotations.ApiModelProperty;
 import org.springblade.archive.entity.ArchivesAuto;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * 视图实体类
  *
@@ -31,4 +35,104 @@ import lombok.EqualsAndHashCode;
 public class ArchivesAutoVO extends ArchivesAuto {
 	private static final long serialVersionUID = 1L;
 
+	/**
+	 * 当前页
+	 */
+	@ApiModelProperty("当前页")
+	private Integer current;
+
+	/**
+	 * 当前页
+	 */
+	@ApiModelProperty("当前页显示条数")
+	private Integer size;
+
+	/**
+	 * 输入框查询条件
+	 */
+	@ApiModelProperty("输入框查询条件")
+	private String queryValue;
+
+	/**
+	 * 节点查询条件
+	 */
+	@ApiModelProperty("节点查询条件")
+	private String nodeIds;
+
+	private List<String> nodeIdArray;
+
+	/**
+	 * 保密级别
+	 */
+	private String secretLevelValue;
+
+	/**
+	 * 保管期限(单位/年)
+	 */
+	private String storageTimeValue;
+
+	@ApiModelProperty("批量保存")
+	private List<ArchivesAutoVO> list;
+	/**
+	* 案卷收集附件信息
+	* */
+	@ApiModelProperty("附件信息")
+	private List<ApprovalFile> approvalFileList = new ArrayList<>();
+
+	public void setApprovalFileList(List<ApprovalFile> approvalFileList) {
+		this.approvalFileList = approvalFileList;
+	}
+
+	@Data
+	public static class ApprovalFile {
+
+		/**
+		 * 文件绑定的节点ID
+		 */
+		private String nodeId;
+
+		/**
+		 * 文件编号
+		 */
+		private String fileNumber;
+
+		/**
+		 * 文件名称
+		 */
+		private String fileName;
+
+		/**
+		 * 文件时间
+		 */
+		private String fileTime;
+
+		/**
+		 * 文件路径
+		 */
+		private String fileUrl;
+
+		/**
+		 * PDF文件路径
+		 */
+		private String pdfFileUrl;
+
+		/**
+		 * 文件页数
+		 */
+		private Integer filePage;
+
+		/**
+		 * 是否需要审批,0不需要,1需要
+		 */
+		private Integer isApproval;
+
+		/**
+		 * 是否需要认证,0不需要,1需要
+		 */
+		private Integer isNeedCertification;
+		/**
+		 * 责任者
+		 */
+		private String dutyUser;
+	}
 }

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

@@ -239,4 +239,8 @@ public class ArchiveFile extends BaseEntity {
 	 */
 	@ApiModelProperty("分盒编号")
 	private Integer boxNumber;
+
+	//是否案卷收集上传的案卷
+	@ApiModelProperty("是否案卷收集上传的案卷")
+	private Integer isAutoFile;
 }

+ 2 - 2
blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/TrialDetectionData.java

@@ -49,10 +49,10 @@ public class TrialDetectionData extends BaseEntity {
     private String testingAgencyCertificateNo;
 
     @ApiModelProperty(value = "样品数量")
-    private Integer materialCount;
+    private String materialCount;
 
     @ApiModelProperty(value = "代表数量")
-    private Integer representativeCount;
+    private String representativeCount;
 
     @ApiModelProperty(value = "取样人")
     private String userName;

+ 3 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/TrialDeviceInfo.java

@@ -3,6 +3,8 @@ package org.springblade.business.entity;
 
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.NullSerializer;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
@@ -97,6 +99,7 @@ public class TrialDeviceInfo extends BaseEntity {
      * 校验周期
      */
     @ApiModelProperty(value = "校验周期")
+    @JsonSerialize(nullsUsing = NullSerializer.class)
     private Integer calibrationCycle;
 
     /**

+ 9 - 3
blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/TrialLaboratoryUserArchives.java

@@ -18,6 +18,12 @@ import java.util.Date;
 public class TrialLaboratoryUserArchives extends BaseEntity {
     private static final long serialVersionUID = 1L;
 
+    /**
+     * 合同段id
+     */
+    @ApiModelProperty("合同段id")
+    private Long contractId;
+
     /**
      * 姓名
      */
@@ -46,7 +52,7 @@ public class TrialLaboratoryUserArchives extends BaseEntity {
      * 身份证
      */
     @ApiModelProperty("身份证")
-    private Long idCard;
+    private String idCard;
 
     /**
      * 出生日期
@@ -123,14 +129,14 @@ public class TrialLaboratoryUserArchives extends BaseEntity {
      * 劳动合同起始时间
      */
     @ApiModelProperty("劳动合同起始时间")
-    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd", timezone = "GMT+8")
     private Date laborContractStartDate;
 
     /**
      * 劳动合同终止时间
      */
     @ApiModelProperty("劳动合同终止时间")
-    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd", timezone = "GMT+8")
     private Date laborContractEndDate;
 
     /**

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

@@ -7,6 +7,9 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import org.springblade.core.mp.base.BaseEntity;
 
+import javax.validation.constraints.DecimalMax;
+import javax.validation.constraints.DecimalMin;
+import javax.validation.constraints.Size;
 import java.math.BigDecimal;
 import java.util.Date;
 

+ 5 - 3
blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/TrialSampleInfo.java

@@ -3,6 +3,7 @@ package org.springblade.business.entity;
 
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
@@ -35,6 +36,7 @@ public class TrialSampleInfo extends BaseEntity {
      * 取样人id
      */
     @ApiModelProperty(value = "取样人id")
+    @JsonFormat(shape = JsonFormat.Shape.STRING)
     private Long userId;
 
     /**
@@ -80,9 +82,9 @@ public class TrialSampleInfo extends BaseEntity {
     private String batchNumber;
 
     /**
-     * 拟部位
+     * 拟部位
      */
-    @ApiModelProperty(value = "拟部位")
+    @ApiModelProperty(value = "拟部位")
     private String proposedPosition;
 
     /**
@@ -120,7 +122,7 @@ public class TrialSampleInfo extends BaseEntity {
     /**
      * 是否委外 '0'=否 '1'=是
      */
-    @ApiModelProperty(value = "是否外 '0'=否 '1'=是")
+    @ApiModelProperty(value = "是否外 '0'=否 '1'=是")
     private Integer isOutsourcing;
 
     /**

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

@@ -2,7 +2,10 @@ package org.springblade.business.feign;
 
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springblade.business.entity.ArchiveFile;
 import org.springblade.business.vo.ArchiveFileVO;
 import org.springblade.common.constant.BusinessConstant;
 import org.springframework.cloud.openfeign.FeignClient;
@@ -46,4 +49,16 @@ public interface ArchiveFileClient {
 
     @PostMapping(API_PREFIX + "/updateArchiveFileByNodeId")
     boolean updateArchiveFileByNodeId(@RequestParam String ids,@RequestParam String nodeId);
+
+    @PostMapping(API_PREFIX + "/listWrappers")
+    List<ArchiveFile> listWrappers(@RequestBody LambdaQueryWrapper<ArchiveFile> in);
+
+    @PostMapping(API_PREFIX + "/updateWrappers")
+    boolean updateWrappers(@RequestBody LambdaUpdateWrapper<ArchiveFile> eq);
+
+    @PostMapping(API_PREFIX + "/removeFile")
+    boolean removeFile(@RequestBody List<Long> toLongList);
+
+    @PostMapping(API_PREFIX + "/getArchiveFileByArchivesId")
+    List<ArchiveFile> getArchiveFileByArchivesId(@RequestParam String archivesIds,@RequestParam String fileIds);
 }

+ 5 - 6
blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/TrialSamplingRecordVO.java

@@ -1,17 +1,15 @@
 package org.springblade.business.vo;
 
 
+import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
-import lombok.EqualsAndHashCode;
-import org.springblade.business.entity.TrialSamplingRecord;
 
+import java.io.Serializable;
 import java.util.Date;
 
-@Data
-@EqualsAndHashCode(callSuper = true)
-public class TrialSamplingRecordVO extends TrialSamplingRecord {
 
-    private static final long serialVersionUID = 1L;
+@Data
+public class TrialSamplingRecordVO implements Serializable {
 
     /**
      * 合同段id
@@ -31,6 +29,7 @@ public class TrialSamplingRecordVO extends TrialSamplingRecord {
     /**
      * 取样时间
      */
+    @JsonFormat(shape = JsonFormat.Shape.STRING,pattern = "yyyy-MM-dd",timezone = "GTM+8")
     private Date samplingDate;
 
     /**

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

@@ -185,4 +185,6 @@ public class ArchiveTreeVO2 implements INodeEx<ArchiveTreeVO2> {
 
     private String ancestors;
 
+    private boolean iswbsNode;  //是否为关联的wbs节点
+
 }

+ 14 - 4
blade-service-api/blade-user-api/pom.xml

@@ -12,8 +12,6 @@
     <artifactId>blade-user-api</artifactId>
     <name>${project.artifactId}</name>
     <version>${bladex.project.version}</version>
-    <packaging>jar</packaging>
-
     <dependencies>
         <dependency>
             <groupId>org.springblade</groupId>
@@ -23,9 +21,21 @@
             <groupId>org.springblade</groupId>
             <artifactId>blade-manager-api</artifactId>
             <version>2.9.1.RELEASE</version>
-            <scope>compile</scope>
         </dependency>
-
     </dependencies>
+    <packaging>jar</packaging>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>2.4.2</version>
+                <configuration>
+                    <skipTests>true</skipTests>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
 
 </project>

+ 202 - 0
blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchiveFileAutoController.java

@@ -0,0 +1,202 @@
+package org.springblade.archive.controller;
+
+import com.alibaba.excel.util.DateUtils;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.*;
+import lombok.AllArgsConstructor;
+import lombok.SneakyThrows;
+import org.apache.commons.lang.StringUtils;
+import org.springblade.archive.service.IArchivesAutoService;
+import org.springblade.archive.utils.FileUtils;
+import org.springblade.archive.vo.ArchivesAutoVO;
+import org.springblade.business.entity.ArchiveFile;
+import org.springblade.business.feign.ArchiveFileClient;
+import org.springblade.business.vo.ArchiveFileVO;
+import org.springblade.common.utils.SnowFlakeUtil;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.oss.model.BladeFile;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.BeanUtil;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.evisa.feign.EVisaClient;
+import org.springblade.manager.entity.ArchiveTreeContract;
+import org.springblade.manager.feign.ArchiveTreeContractClient;
+import org.springblade.resource.feign.IOSSClient;
+import org.springblade.system.user.entity.UserOauth;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.*;
+import java.util.stream.Collectors;
+
+
+/**
+ *  控制器
+ *
+ * @author BladeX
+ * @since 2022-07-08
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/archiveFileAuto")
+@Api(value = "案卷收集接口", tags = "案卷收集接口")
+public class ArchiveFileAutoController extends BladeController {
+
+    private final ArchiveFileClient archiveFileClient;
+    private final IOSSClient iossClient;
+    private final ArchiveTreeContractClient archiveTreeContractClient;
+    private final EVisaClient eVisaClient;
+    private final IArchivesAutoService archivesAutoService;
+    /**
+     * 批量新增
+     */
+    @PostMapping("/batchSave")
+    @ApiOperationSupport(order = 2)
+    @ApiOperation(value = "批量新增")
+    public R<Boolean> batchSave(@RequestBody ArchivesAutoVO archiveList){
+        try {
+            for(ArchivesAutoVO archive : archiveList.getList()) {
+                if(archive.getId() == null){
+
+                    archive.setId(SnowFlakeUtil.getId());
+                    int l = (int) System.currentTimeMillis();
+                    List<ArchivesAutoVO.ApprovalFile> saveList = archive.getApprovalFileList();
+                    ArchiveFileVO saveVos = new ArchiveFileVO();
+                    Integer pageN = 0;
+                    if (saveList != null && saveList.size() > 0) {
+                        int i = 1;
+                        List<ArchiveFileVO> list = new ArrayList<>();
+                        for (ArchivesAutoVO.ApprovalFile approvalFile : saveList) {
+                            ArchiveFileVO saveVo = BeanUtil.copy(approvalFile, ArchiveFileVO.class);
+                            saveVo.setSort(l + i);
+                            saveVo.setIsAutoFile(1);
+                            saveVo.setStatus(new Integer("0").equals(saveVo.getIsApproval()) ? 2 : 0);
+                            saveVo.setIsCertification(new Integer("0").equals(saveVo.getIsNeedCertification()) ? 1 : 0);
+                            saveVo.setArchiveId(archive.getId());
+                            saveVo.setOriginId(archive.getId());
+                            list.add(saveVo);
+                            pageN = pageN + saveVo.getFilePage();
+                            i++;
+                        }
+                        saveVos.setList(list);
+                    }
+                    this.archiveFileClient.saveArchiveFile(saveVos);
+                    archive.setFileN(saveVos.getSize());
+                    archive.setPageN(pageN);
+                    List<ArchiveTreeContract> archiveTreeContracts = this.archiveTreeContractClient.queryAllChildByAncestors(saveVos.getNodeId());
+                    if(archiveTreeContracts != null && archiveTreeContracts.size() >0){
+                        archive.setTreeSort(archiveTreeContracts.get(0).getTreeSort());
+                    }
+
+                    archive.setAutoFileSort(l+archive.getAutoFileSort());
+                    //待修改
+                    archive.setIsDeleted(0);
+                    archive.setIsArchive(0);
+                    archive.setIsAutoFile(1);
+                    archivesAutoService.save(archive);
+                }else{
+                    archivesAutoService.updateById(archive);
+                }
+            }
+        } catch (NumberFormatException e) {
+            e.printStackTrace();
+            return R.data(false);
+        }
+        return R.data(true);
+    }
+    /**
+     * 分页
+     */
+    @PostMapping("/page")
+    @ApiOperationSupport(order = 3)
+    @ApiOperation(value = "分页")
+    public R<Object> page( ArchivesAutoVO queryVo){
+        if(queryVo.getNodeIds() == null || queryVo.getNodeIds().equals("")){
+            return  R.data(null);
+        }
+        List<ArchiveTreeContract> archiveTreeContracts = this.archiveTreeContractClient.queryAllChildByAncestors(queryVo.getNodeIds());
+        if(archiveTreeContracts != null && archiveTreeContracts.size() > 0){
+            List<String> ids = JSONArray.parseArray(JSONObject.toJSONString(archiveTreeContracts.stream().map(ArchiveTreeContract::getId).distinct().collect(Collectors.toList())), String.class);
+            ids.add(queryVo.getNodeIds());
+            queryVo.setNodeIdArray(ids);
+        }
+
+        return R.data(archivesAutoService.selectArchivesAutoFilePage(queryVo));
+    }
+
+
+    /**
+     * 迁移文件
+     */
+    @PostMapping("/migrateFile")
+    @ApiOperationSupport(order = 4)
+    @ApiOperation(value = "迁移文件", notes = "传入ids")
+    public R migrateFile(@RequestParam String ids,@RequestParam String nodeId,@RequestParam String nodeSort) {
+        return R.status(archivesAutoService.updateArchivesAutoFileByNodeId(ids,nodeId,nodeSort));
+    }
+    /**
+     * 删除
+     */
+    @PostMapping("/remove")
+    @ApiOperationSupport(order = 5)
+    @ApiOperation(value = "逻辑删除", notes = "传入ids")
+    public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+        List<ArchiveFile> list = this.archiveFileClient.getArchiveFileByArchivesId(ids,"");
+        StringBuffer fileIds = new StringBuffer();
+        if(list != null && list.size()>0){
+            for(ArchiveFile archiveFile : list){
+                fileIds.append(archiveFile.getId());
+                fileIds.append(",");
+            }
+        }
+        /**先删除对应工程文件在删除案卷**/
+        boolean b = this.archiveFileClient.removeFile(Func.toLongList(fileIds.toString()));
+        if(b){
+            return R.status(archivesAutoService.deleteLogic(Func.toLongList(ids)));
+        }
+        return R.status(false);
+    }
+    /**
+     * 批量下载
+     */
+    @PostMapping("/batchDownloadFileToZip")
+    @ApiOperationSupport(order = 8)
+    @ApiOperation(value = "批量下载")
+    public void batchDownloadFileToZip(String ids, HttpServletResponse response){
+
+        if(StringUtils.isNotEmpty(ids)){
+            //获取文件
+            List<ArchiveFile> result = this.archiveFileClient.getArchiveFileByArchivesId(ids,"");
+            if(result != null && result.size() > 0){
+                List<String> urls = new ArrayList<>();
+                result.forEach(archiveFile -> urls.add(archiveFile.getFileUrl() + "@@@" + archiveFile.getFileName()));
+
+                //打包下载
+                FileUtils.batchDownloadFileToZip(urls, response);
+            }
+        }
+
+    }
+
+    /**
+     * 预览
+     */
+    @PostMapping("/mergePdf")
+    @ApiOperationSupport(order = 9)
+    @ApiOperation(value = "预览")
+    public R<Object> mergePdf(@RequestParam String ids){
+        List<ArchiveFile> result = this.archiveFileClient.getArchiveFileByArchivesId(ids,"");
+        List<String> pdfUrls = result.stream().map(archiveFile ->StringUtils.isNotEmpty(archiveFile.getPdfFileUrl())?archiveFile.getPdfFileUrl():archiveFile.getFileUrl()).distinct().collect(Collectors.toList());
+
+//        FileUtils.mergePdfPublicMethods(pdfUrls,"");
+        /**
+         * 案卷的只有一个文件,不合并先,需要的时候在把合并方法放出来
+         * **/
+        return R.data(pdfUrls);
+    }
+}

+ 82 - 0
blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchiveFileController.java

@@ -1,12 +1,17 @@
 package org.springblade.archive.controller;
 
+import com.alibaba.excel.util.DateUtils;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 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 lombok.SneakyThrows;
+import org.apache.commons.lang.StringUtils;
+import org.springblade.archive.utils.FileUtils;
 import org.springblade.business.entity.ArchiveFile;
 import org.springblade.business.feign.ArchiveFileClient;
 import org.springblade.business.vo.ArchiveFileVO;
@@ -15,6 +20,7 @@ import org.springblade.core.boot.ctrl.BladeController;
 import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.utils.Func;
+import org.springblade.evisa.feign.EVisaClient;
 import org.springblade.manager.entity.ArchiveTree;
 import org.springblade.manager.entity.ArchiveTreeContract;
 import org.springblade.manager.feign.ArchiveTreeContractClient;
@@ -22,7 +28,9 @@ import org.springblade.resource.feign.IOSSClient;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
+import javax.servlet.http.HttpServletResponse;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
@@ -43,6 +51,7 @@ public class ArchiveFileController extends BladeController {
     private final ArchiveFileClient archiveFileClient;
     private final IOSSClient iossClient;
     private final ArchiveTreeContractClient archiveTreeContractClient;
+    private final EVisaClient eVisaClient;
     /**
      * 上传文件
      *
@@ -177,4 +186,77 @@ public class ArchiveFileController extends BladeController {
     public R migrateFile(@RequestParam String ids,@RequestParam String nodeId) {
         return R.status(this.archiveFileClient.updateArchiveFileByNodeId(ids,nodeId));
     }
+
+    /**
+     * 批量认证(特殊签章 签个透明空白图片,主要目的是在验签的时候有验签信息 )
+     */
+    @PostMapping("/batchCertification")
+    @ApiOperationSupport(order = 9)
+    @ApiOperation(value = "批量认证")
+    public R<Boolean> batchCertification(@RequestBody ArchiveFileVO vo){
+        List<String> list = new ArrayList<>();
+        if(vo.getIds() != null && vo.getIds().size() > 0){
+            //获取文件
+            List<ArchiveFile> archiveFileList = this.archiveFileClient.listWrappers(Wrappers.<ArchiveFile>lambdaQuery().in(ArchiveFile::getId, vo.getIds()));
+            if(archiveFileList != null && archiveFileList.size() > 0){
+                for(ArchiveFile archiveFile : archiveFileList){
+                    //获取文件地址并调用接口认证
+                    String result = this.eVisaClient.certification(StringUtils.isNotEmpty(archiveFile.getEVisaFile()) ? archiveFile.getEVisaFile() : archiveFile.getPdfFileUrl(), archiveFile.getFileName(), archiveFile.getContractId());
+                    if(StringUtils.isNotEmpty(result) && result.contains("success") && result.startsWith("success")){
+                        //成功,更改状态
+                        //签章成功后的文件路径,如果与原pdf文件路径不匹配则更新
+                        String newPdfUrl = null;
+                        if(result.contains("@@@@")){
+                            newPdfUrl = result.split("@@@@")[1];
+                        }
+                        LambdaUpdateWrapper<ArchiveFile> wrappers = Wrappers.lambdaUpdate();
+                        if(StringUtils.isNotEmpty(newPdfUrl) && !archiveFile.getPdfFileUrl().equals(newPdfUrl)){
+                            //不为空且不匹配时,更新
+                            wrappers.set(ArchiveFile::getEVisaFile, newPdfUrl);
+                        }
+                        //修改认证状态为已认证
+                        wrappers.set(ArchiveFile::getIsCertification, 1);
+                        //添加认证时间
+                        wrappers.set(ArchiveFile::getCertificationTime, DateUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
+
+                        //修改状态
+                        this.archiveFileClient.updateWrappers(wrappers.eq(ArchiveFile::getId, archiveFile.getId()));
+                    } else {
+                        list.add(archiveFile.getId().toString());
+                    }
+                }
+            }
+        }
+        return list.size() == 0 ? R.data(true) : R.data(300, false, "没有找到证书文件或PDF文件");
+    }
+    /**
+     * 删除
+     */
+    @PostMapping("/remove")
+    @ApiOperationSupport(order = 10)
+    @ApiOperation(value = "逻辑删除", notes = "传入ids")
+    public R<Boolean> remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+        return R.status( this.archiveFileClient.removeFile(Func.toLongList(ids)));
+    }
+    /**
+     * 批量下载
+     */
+    @PostMapping("/batchDownloadFileToZip")
+    @ApiOperationSupport(order = 8)
+    @ApiOperation(value = "批量下载")
+    public void batchDownloadFileToZip(String ids, HttpServletResponse response){
+
+        if(StringUtils.isNotEmpty(ids)){
+            //获取文件
+            List<ArchiveFile> result = this.archiveFileClient.getArchiveFileByArchivesId("",ids);
+            if(result != null && result.size() > 0){
+                List<String> urls = new ArrayList<>();
+                result.forEach(archiveFile -> urls.add(archiveFile.getFileUrl() + "@@@" + archiveFile.getFileName()));
+
+                //打包下载
+                FileUtils.batchDownloadFileToZip(urls, response);
+            }
+        }
+
+    }
 }

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

@@ -16,6 +16,7 @@
  */
 package org.springblade.archive.mapper;
 
+import org.apache.ibatis.annotations.Param;
 import org.springblade.archive.entity.ArchivesAuto;
 import org.springblade.archive.vo.ArchivesAutoVO;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
@@ -39,4 +40,9 @@ public interface ArchivesAutoMapper extends BaseMapper<ArchivesAuto> {
 	 */
 	List<ArchivesAutoVO> selectArchivesAutoPage(IPage page, ArchivesAutoVO archivesAuto);
 
+	Integer selectArchivesAutoFileCount(@Param("vo") ArchivesAutoVO vo);
+
+	List<ArchivesAuto> selectArchivesAutoFilePage(@Param("current") Integer current, @Param("size") Integer size, @Param("vo")  ArchivesAutoVO vo);
+
+	Integer updateArchivesAutoFileByNodeId(@Param("ids") List<Long> ids,@Param("nodeId") String nodeId,@Param("nodeSort") String nodeSort);
 }

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

@@ -39,11 +39,14 @@
         <result column="file_n" property="fileN"/>
         <result column="page_n" property="pageN"/>
         <result column="mileage" property="mileage"/>
-        <result column="fileType" property="fileType"/>
+        <result column="file_type" property="fileType"/>
         <result column="size" property="size"/>
-        <result column="tree_sort" property="nodeSort"/>
-        <result column="isOpen" property="isOpen"/>
+        <result column="tree_sort" property="treeSort"/>
+        <result column="is_open" property="isOpen"/>
         <result column="ischeck" property="ischeck"/>
+        <result column="is_auto_file" property="isAutoFile"/>
+        <result column="auto_file_sort" property="autoFileSort"/>
+        <result column="filing_unit" property="filingUnit"/>
     </resultMap>
 
 
@@ -51,4 +54,52 @@
         select * from u_archives_auto where is_deleted = 0
     </select>
 
+
+    <select id="selectArchivesAutoFileCount" resultType="java.lang.Integer">
+        select count(id) from u_archives_auto where is_deleted = 0
+        <if test="vo.projectId != null and vo.projectId != ''">
+            and project_id = #{vo.projectId}
+        </if>
+        <if test="vo.contractId != null and vo.contractId != ''">
+            and contract_id = #{vo.contractId}
+        </if>
+        <if test="vo.contractId != null and vo.contractId != ''">
+            and is_auto_file = #{vo.isAutoFile}
+        </if>
+        <if test="vo.nodeIds != null and vo.nodeIds != ''">
+            and node_id in
+            <foreach collection="vo.nodeIdArray" item="nodeId" open="(" separator="," close=")">
+                #{nodeId}
+            </foreach>
+        </if>
+    </select>
+
+    <select id="selectArchivesAutoFilePage" resultMap="archivesAutoResultMap">
+        select * from u_archives_auto where is_deleted = 0
+        <if test="vo.projectId != null and vo.projectId != ''">
+            and project_id = #{vo.projectId}
+        </if>
+        <if test="vo.contractId != null and vo.contractId != ''">
+            and contract_id = #{vo.contractId}
+        </if>
+        <if test="vo.isAutoFile != null and vo.isAutoFile != ''">
+            and is_auto_file = #{vo.isAutoFile}
+        </if>
+        <if test="vo.nodeIds != null and vo.nodeIds != ''">
+            and node_id in
+            <foreach collection="vo.nodeIdArray" item="nodeId" open="(" separator="," close=")">
+                #{nodeId}
+            </foreach>
+        </if>
+        order by tree_sort DESC,auto_file_sort asc
+    </select>
+
+    <update id="updateArchivesAutoFileByNodeId" >
+        update u_archives_auto set node_id = #{nodeId},tree_sort = #{nodeSort} where
+        id in
+        <foreach collection="ids" item="id" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </update>
+
 </mapper>

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

@@ -38,4 +38,7 @@ public interface IArchivesAutoService extends BaseService<ArchivesAuto> {
 	 */
 	IPage<ArchivesAutoVO> selectArchivesAutoPage(IPage<ArchivesAutoVO> page, ArchivesAutoVO archivesAuto);
 
+	IPage<ArchivesAutoVO> selectArchivesAutoFilePage(ArchivesAutoVO queryVo);
+
+	boolean updateArchivesAutoFileByNodeId(String ids, String nodeId,String nodeSort);
 }

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

@@ -16,14 +16,25 @@
  */
 package org.springblade.archive.service.impl;
 
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import lombok.AllArgsConstructor;
+import org.apache.commons.lang.StringUtils;
 import org.springblade.archive.entity.ArchivesAuto;
 import org.springblade.archive.vo.ArchivesAutoVO;
 import org.springblade.archive.mapper.ArchivesAutoMapper;
 import org.springblade.archive.service.IArchivesAutoService;
 import org.springblade.core.mp.base.BaseServiceImpl;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.system.entity.DictBiz;
+import org.springblade.system.feign.IDictBizClient;
 import org.springframework.stereotype.Service;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 
+import java.util.List;
+
 /**
  *  服务实现类
  *
@@ -31,11 +42,68 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
  * @since 2023-02-17
  */
 @Service
+@AllArgsConstructor
 public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper, ArchivesAuto> implements IArchivesAutoService {
 
+	private final IDictBizClient iDictBizClient;
 	@Override
 	public IPage<ArchivesAutoVO> selectArchivesAutoPage(IPage<ArchivesAutoVO> page, ArchivesAutoVO archivesAuto) {
 		return page.setRecords(baseMapper.selectArchivesAutoPage(page, archivesAuto));
 	}
 
+	@Override
+	public IPage<ArchivesAutoVO> selectArchivesAutoFilePage(ArchivesAutoVO vo) {
+		Query query = new Query();
+		query.setCurrent(vo.getCurrent());
+		query.setSize(vo.getSize());
+		//设置分页
+		IPage<ArchivesAutoVO> iPage = Condition.getPage(query);
+
+		//汇总
+		Integer total = this.baseMapper.selectArchivesAutoFileCount(vo);
+		if(total == null){
+			total = 0;
+		}
+		//分页
+		int current = (vo.getCurrent() - 1) * vo.getSize();
+
+		List<ArchivesAuto> pageList = this.baseMapper.selectArchivesAutoFilePage(current, vo.getSize(), vo);
+		//设置分页信息
+		iPage.setTotal(total);
+		List<ArchivesAutoVO> pageVoList = JSONArray.parseArray(JSONObject.toJSONString(pageList), ArchivesAutoVO.class);
+		List<DictBiz> sheetSourceList = this.iDictBizClient.getList("security_level", "notRoot").getData();
+		List<DictBiz> sheetSourceList1 = this.iDictBizClient.getList("storage_period", "notRoot").getData();
+
+		pageVoList.forEach(vos -> {
+			if(StringUtils.isNotEmpty(vos.getSecretLevel())){
+				sheetSourceList.forEach(source -> {
+					if( source.getDictKey().equals(vos.getSecretLevel())){
+						vos.setSecretLevelValue(source.getDictValue());
+					}
+				});
+			}
+			if(StringUtils.isNotEmpty(vos.getStorageTime())){
+				sheetSourceList1.forEach(source -> {
+					if ( source.getDictKey().equals(vos.getStorageTime())) {
+						vos.setStorageTimeValue(source.getDictValue());
+					}
+				});
+			}
+		});
+
+		return iPage.setRecords(pageVoList);
+	}
+
+	@Override
+	public boolean updateArchivesAutoFileByNodeId(String ids, String nodeId,String nodeSort) {
+		try {
+			baseMapper.updateArchivesAutoFileByNodeId(Func.toLongList(ids),nodeId,nodeSort);
+
+		} catch (Exception e) {
+			e.printStackTrace();
+			return false;
+		}
+		return true;
+	}
+
 }

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

@@ -0,0 +1,232 @@
+package org.springblade.archive.utils;
+
+import com.itextpdf.text.Document;
+import com.itextpdf.text.pdf.PdfCopy;
+import com.itextpdf.text.pdf.PdfReader;
+import org.apache.commons.lang.StringUtils;
+import org.apache.poi.ss.usermodel.ClientAnchor;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.util.Units;
+import org.springblade.common.utils.CommonUtil;
+import org.springblade.common.vo.DataVO;
+import org.springblade.core.tool.utils.IoUtil;
+
+import javax.imageio.ImageIO;
+import javax.servlet.http.HttpServletResponse;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.net.URLEncoder;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+public class FileUtils {
+
+    public static void batchDownloadFileToZip(List<String> urls, HttpServletResponse response){
+        // 设置压缩流:直接写入response,实现边压缩边下载
+        ZipOutputStream zipos = null;
+        // 循环将文件写入压缩流
+        DataOutputStream os = null;
+        try{
+
+            // 响应头的设置
+            response.reset();
+            response.setCharacterEncoding("utf-8");
+            response.setContentType("multipart/form-data");
+            // 设置压缩包的名字
+            // 解决不同浏览器压缩包名字含有中文时乱码的问题
+            String downloadName = "附件-" + System.currentTimeMillis() + ".zip";
+            response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(downloadName, "UTF-8"));
+
+
+            try {
+                zipos = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
+                // 设置压缩方法
+                zipos.setMethod(ZipOutputStream.DEFLATED);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+            if(zipos == null){
+                return;
+            }
+
+            InputStream inputStream = null;
+
+            for(String url : urls){
+                if(StringUtils.isNotEmpty(url)){
+                    try{
+                        String fileName = null, symbol = "";
+                        if(url.contains("@@@")){
+                            String[] array = url.split("@@@");
+                            url = array[0];
+                            fileName = array[1];
+                            symbol = url.substring(url.lastIndexOf("."));
+                        }
+
+                        //获取文件流
+                        inputStream = CommonUtil.getOSSInputStream(url);
+                        //转换
+                        byte[] bytes = CommonUtil.InputStreamToBytes(inputStream);
+
+                        if(StringUtils.isEmpty(fileName)){
+                            fileName = url.substring(url.lastIndexOf("/") + 1);
+                            symbol = "";
+                        }
+                        zipos.putNextEntry(new ZipEntry(fileName + symbol));
+
+                        os = new DataOutputStream(zipos);
+                        os.write(bytes);
+                        zipos.closeEntry();
+
+                    }catch (Exception e){
+                        e.printStackTrace();
+                    } finally {
+                        IoUtil.closeQuietly(inputStream);
+                    }
+                }
+            }
+
+        }catch (Exception e){
+            e.printStackTrace();
+        } finally {
+            IoUtil.closeQuietly(os);
+            IoUtil.closeQuietly(zipos);
+        }
+    }
+
+    /**
+     * 压缩图片
+     */
+    public static byte[] resizeImage(byte[] srcImgData, float reduceMultiple) throws IOException {
+        BufferedImage bi = ImageIO.read(new ByteArrayInputStream(srcImgData));
+        /*int width = (int) (bi.getWidth() * reduceMultiple);
+        int height = (int) (bi.getHeight() * reduceMultiple);*/
+        int width = 600;
+        int height = 800;
+        Image image = bi.getScaledInstance(width, height, Image.SCALE_SMOOTH);
+        BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+        Graphics g = tag.getGraphics();
+        g.setColor(Color.RED);
+        g.drawImage(image, 0, 0, null);
+        g.dispose();
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+        ImageIO.write(tag, "JPEG", bOut);
+        return bOut.toByteArray();
+    }
+
+    /**
+     * 压缩图片2
+     */
+    public static byte[] resizeImage2(byte[] srcImgData, float reduceMultiple) throws IOException {
+        BufferedImage bi = ImageIO.read(new ByteArrayInputStream(srcImgData));
+        int width = (int) (bi.getWidth() * reduceMultiple);
+        int height = (int) (bi.getHeight() * reduceMultiple);
+        Image image = bi.getScaledInstance(width, height, Image.SCALE_SMOOTH);
+        BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+        Graphics g = tag.getGraphics();
+        g.setColor(Color.RED);
+        g.drawImage(image, 0, 0, null);
+        g.dispose();
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+        ImageIO.write(tag, "JPEG", bOut);
+        return bOut.toByteArray();
+    }
+
+    /**
+     * 图片定位
+     */
+    public static void imageOrientation(Sheet sheet, ClientAnchor anchor, DataVO dataVO) {
+        anchor.setDx1(Units.pixelToEMU(5));
+        anchor.setDy1(Units.pixelToEMU(5));
+        anchor.setCol2(anchor.getCol1());
+        anchor.setRow2(anchor.getRow1());
+        int k = getMergedRegionIndex(sheet, CommonUtil.join(dataVO.getX(), dataVO.getY(), dataVO.getX(), dataVO.getY(),","));
+        if(k>-1){
+            /*如果是合并单元格,则锚点第二坐标设置为合并区右下角单元格坐标*/
+            CellRangeAddress ca = sheet.getMergedRegion(k);
+            anchor.setCol1(ca.getFirstColumn());
+            anchor.setRow1(ca.getFirstRow());
+            anchor.setCol2(ca.getLastColumn());
+            anchor.setRow2(ca.getLastRow());
+        }
+        int dx=(int)(sheet.getColumnWidthInPixels(anchor.getCol2())+3);
+        int dy=Units.pointsToPixel(sheet.getRow(anchor.getRow2()).getHeightInPoints())-5;
+        anchor.setDx2(Units.pixelToEMU(dx));
+        anchor.setDy2(Units.pixelToEMU(dy));
+    }
+
+    public static int getMergedRegionIndex(Sheet sheet, String coords) {
+        for (int i = 0; i < sheet.getNumMergedRegions(); i++) {
+            CellRangeAddress ca = sheet.getMergedRegion(i);
+            int firstColumn = ca.getFirstColumn();
+            int lastColumn = ca.getLastColumn();
+            int firstRow = ca.getFirstRow();
+            int lastRow = ca.getLastRow();
+            Matcher mu = CommonUtil.matcher("(\\d{1,3}),(\\d{1,3}),(\\d{1,3}),(\\d{1,3})",coords);
+            /*合并单元格四个角坐标,只要任意一个在落在将要合并的区域里面意味着两者重合,就必须拆分前者*/
+            List<Integer[]> corners = Arrays.asList(new Integer[]{firstColumn,firstRow},new Integer[]{lastColumn,firstRow},new Integer[]{firstColumn,lastRow},new Integer[]{lastColumn,lastRow});
+            if(mu.find()){
+                int firstColumn2 = mu.group(1) == null ? 0 : Integer.parseInt(mu.group(1));
+                int lastColumn2 = mu.group(3) == null ? 0 : Integer.parseInt(mu.group(3));
+                int firstRow2 = mu.group(2) == null ? 0 : Integer.parseInt(mu.group(2));
+                int lastRow2 = mu.group(4) == null ? 0 : Integer.parseInt(mu.group(4));
+                for(Integer[] corner:corners){
+                    if(firstColumn2<=corner[0]&&corner[0]<=lastColumn2&&firstRow2<=corner[1]&&corner[1]<=lastRow2){
+                        return i;
+                    }
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * 合并方法
+     */
+    public static void mergePdfPublicMethods(List<String> urlList, String localImgUrl){
+        PdfReader reader = null;
+
+        Document doc = new Document();
+        PdfCopy pdfCopy = null;
+        try{
+            pdfCopy = new PdfCopy(doc, new FileOutputStream(localImgUrl));
+            int pageCount;
+            doc.open();
+
+            for(String urlStr : urlList){
+                try{
+                    //获取OSS文件输入流
+                    reader = new PdfReader(CommonUtil.getOSSInputStream(urlStr));
+
+                    pageCount = reader.getNumberOfPages();
+
+                    for(int i = 0; i < pageCount; ++i){
+                        int is = i + 1;
+                        pdfCopy.addPage(pdfCopy.getImportedPage(reader,is));
+                    }
+                }catch (Exception e){
+                    e.printStackTrace();
+                } finally {
+                    if(reader != null){
+                        reader.close();
+                    }
+                }
+            }
+
+        }catch (Exception e){
+            e.printStackTrace();
+        } finally {
+            if(pdfCopy != null){
+                pdfCopy.flush();
+                pdfCopy.close();
+            }
+            doc.close();
+        }
+    }
+
+}

+ 4 - 0
blade-service/blade-business/pom.xml

@@ -144,6 +144,10 @@
             <version>2.9.1.RELEASE</version>
             <scope>compile</scope>
         </dependency>
+        <dependency>
+            <groupId>org.jsoup</groupId>
+            <artifactId>jsoup</artifactId>
+        </dependency>
 
     </dependencies>
 

+ 85 - 8
blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java

@@ -27,8 +27,10 @@ import org.springblade.business.socket.WebSocket;
 import org.springblade.business.utils.FileUtils;
 import org.springblade.business.vo.*;
 import org.springblade.common.constant.CommonConstant;
+import org.springblade.common.constant.LauncherConstant;
 import org.springblade.common.utils.CommonUtil;
 import org.springblade.common.utils.SnowFlakeUtil;
+import org.springblade.core.cache.utils.CacheUtil;
 import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.mp.support.Condition;
 import org.springblade.core.mp.support.Query;
@@ -50,8 +52,14 @@ import org.springblade.system.cache.ParamCache;
 import org.springblade.system.entity.DictBiz;
 import org.springblade.system.feign.IDictBizClient;
 import org.springframework.beans.BeanUtils;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.cache.annotation.Caching;
+import org.springframework.data.redis.core.RedisConnectionUtils;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springblade.core.boot.ctrl.BladeController;
@@ -60,6 +68,8 @@ import java.io.IOException;
 import java.util.*;
 import java.util.stream.Collectors;
 
+import static org.springblade.core.cache.constant.CacheConstant.SYS_CACHE;
+
 /**
  * 资料填报及查询控制器
  *
@@ -110,6 +120,8 @@ public class InformationWriteQueryController extends BladeController {
 
     private final ITreeContractFirstService treeContractFirstService;
 
+    private static final String CONTRACT_CACHE_WBSTREE = "contract:wbstree:";
+
     /**
      * 获取文件题名
      */
@@ -1857,9 +1869,9 @@ public class InformationWriteQueryController extends BladeController {
 
         if (queryProcess != null && queryProcess.size() > 0) {
             //检查这些填报节点是否存在已经审批或已经上报的节点,如果存在则不允许删除
-            List<QueryProcessDataVO> approvalList = queryProcess.stream().filter(vo -> new Integer("2").equals(vo.getStatus())).collect(Collectors.toList());
+            List<QueryProcessDataVO> approvalList = queryProcess.stream().filter(vo -> new Integer("2").equals(vo.getStatus()) && vo.getInformationQueryId()!=null).collect(Collectors.toList());
             //
-            List<QueryProcessDataVO> runTaskList = queryProcess.stream().filter(vo -> new Integer("1").equals(vo.getStatus())).collect(Collectors.toList());
+            List<QueryProcessDataVO> runTaskList = queryProcess.stream().filter(vo -> new Integer("1").equals(vo.getStatus()) && vo.getInformationQueryId()!=null).collect(Collectors.toList());
             if (approvalList.size() > 0 || runTaskList.size() > 0) {
                 //说明存在已经审批或已经上报的节点,不允许删除
                 return R.data(300, false, "存在已经上报或审批的节点,不允许删除");
@@ -2389,7 +2401,25 @@ public class InformationWriteQueryController extends BladeController {
         if (StringUtils.isNotEmpty(primaryKeyId)) {
             parentId = primaryKeyId;
         }
-        return R.data(this.queryContractTree(parentId, contractId, contractIdRelation, classifyType));
+        String dataInfoId = contractId+"_"+parentId+"_"+classifyType;
+        queryContractWbsTreeByContractIdAndType2(primaryKeyId,parentId,contractId,contractIdRelation,classifyType);
+        List<WbsTreeContractTreeVOS> wbsTreeContractTreeVOS = CacheUtil.get(LauncherConstant.APPLICATION_MANAGER_NAME, CONTRACT_CACHE_WBSTREE, dataInfoId, List.class);
+        if (wbsTreeContractTreeVOS == null) {
+            wbsTreeContractTreeVOS = this.queryContractTree(parentId, contractId, contractIdRelation, classifyType);
+            CacheUtil.put(LauncherConstant.APPLICATION_MANAGER_NAME, CONTRACT_CACHE_WBSTREE, dataInfoId, wbsTreeContractTreeVOS);
+        }
+        return R.data(wbsTreeContractTreeVOS);
+    }
+
+    @Async
+    public void queryContractWbsTreeByContractIdAndType2(String primaryKeyId,
+                                                                                   String parentId,
+                                                                                   String contractId,
+                                                                                   String contractIdRelation,
+                                                                                   String classifyType) {
+        String dataInfoId = contractId+"_"+parentId+"_"+classifyType;
+        List<WbsTreeContractTreeVOS> wbsTreeContractTreeVOS = this.queryContractTree(parentId, contractId, contractIdRelation, classifyType);
+            CacheUtil.put(LauncherConstant.APPLICATION_MANAGER_NAME, CONTRACT_CACHE_WBSTREE, dataInfoId, wbsTreeContractTreeVOS);
     }
 
     /**
@@ -2441,6 +2471,7 @@ public class InformationWriteQueryController extends BladeController {
         return R.data(rootTreeNode);
     }
 
+
     /**
      * 查询合同段划分树公共代码
      */
@@ -2454,17 +2485,64 @@ public class InformationWriteQueryController extends BladeController {
             //监理/业主合同段,需要获取关联的施工方合同段根节点数据
             List<String> contractIds = new ArrayList<>();
             if (StringUtils.isEmpty(parentId)) {
+                // 获取 有几个合同段主键Id
                 contractIds = this.contractClient.getProcessContractByJLContractId(contractId);
             } else {
                 contractIds.add(contractIdRelation);
             }
             if (contractIds.size() > 0) {
-
                 //监理复制加载树问题
                 if (StringUtils.isEmpty(classifyType)) {
                     classifyType = "2";
                 }
+                if (StringUtils.isNotEmpty(parentId)) {
+                    //子节点
+                    rootTreeNode = this.informationQueryService.queryContractTreeSupervision(contractIds, parentId, Integer.parseInt(classifyType));
+                } else {
+                    //根节点
+                    rootTreeNode = this.informationQueryService.queryContractTreeSupervision(contractIds, "0", Integer.parseInt(classifyType));
+                    //设置根节点数量统计
+                    for (WbsTreeContractTreeVOS root : rootTreeNode) {
+                        List<WbsTreeContractTreeVOS> rootZi = this.informationQueryService.queryContractTreeSupervision(Func.toStrList(root.getContractIdRelation()), root.getId().toString(), Integer.parseInt(classifyType));
+                        List<Long> collect = rootZi.stream().map(WbsTreeContractTreeVOS::getSubmitCounts).collect(Collectors.toList());
+                        Long reduce = collect.stream().reduce(0L, Long::sum);
+                        root.setSubmitCounts(reduce);
+                    }
+                }
+            } else {
+                rootTreeNode = new ArrayList<>();
+            }
+        } else {
+            //施工合同段
+            rootTreeNode = this.informationQueryService.queryContractTree(contractId, StringUtils.isNotEmpty(parentId) ? parentId : "0", 1);
+        }
+        return rootTreeNode;
+    }
+ /*
+    *//**
+     * 查询合同段划分树公共代码
+     *//*
+    private List<WbsTreeContractTreeVOS> queryContractTree(String parentId, String contractId, String contractIdRelation, String classifyType) {
+        List<WbsTreeContractTreeVOS> rootTreeNode;
 
+        //获取合同段,检查是否是监理合同段
+        ContractInfo contractInfo = this.contractClient.getContractById(Long.parseLong(contractId));
+
+        if (new Integer("2").equals(contractInfo.getContractType()) || new Integer("3").equals(contractInfo.getContractType())) {
+            //监理/业主合同段,需要获取关联的施工方合同段根节点数据
+            List<String> contractIds = new ArrayList<>();
+            if (StringUtils.isEmpty(parentId)) {
+                // 获取 有几个合同段主键Id
+                contractIds = this.contractClient.getProcessContractByJLContractId(contractId);
+            } else {
+                contractIds.add(contractIdRelation);
+            }
+            if (contractIds.size() > 0) {
+
+                //监理复制加载树问题
+                if (StringUtils.isEmpty(classifyType)) {
+                    classifyType = "2";
+                }
                 if (StringUtils.isNotEmpty(parentId)) {
                     //子节点
                     rootTreeNode = this.informationQueryService.queryContractTreeSupervision(contractIds, parentId, Integer.parseInt(classifyType));
@@ -2480,7 +2558,6 @@ public class InformationWriteQueryController extends BladeController {
                         root.setSubmitCounts(reduce);
                     }
                 }
-
             } else {
                 rootTreeNode = new ArrayList<>();
             }
@@ -2488,14 +2565,14 @@ public class InformationWriteQueryController extends BladeController {
         } else {
             //施工合同段
             rootTreeNode = this.informationQueryService.queryContractTree(contractId, StringUtils.isNotEmpty(parentId) ? parentId : "0", 1);
-            rootTreeNode.stream().forEach(rtn->{
+            *//*rootTreeNode.stream().forEach(rtn->{
                 if (rtn.getSubmitCounts() > 0L && rtn.getColorStatus() <= 1 && rtn.getNotExsitChild() == false){
                     rtn.setColorStatus(2);
                 }
-            });
+            });*//*
         }
 
         return rootTreeNode;
     }
-
+*/
 }

+ 5 - 6
blade-service/blade-business/src/main/java/org/springblade/business/controller/TrialDetectionController.java

@@ -347,13 +347,12 @@ public class TrialDetectionController extends BladeController {
         return R.fail(200, "未查询到数据");
     }
 
-    @PostMapping("/self/record-sample/submit")
+    @PostMapping("/self/record-sample/getData")
     @ApiOperationSupport(order = 27)
-    @ApiOperation(value = "自检记录关联取样信息保存", notes = "传入RecordSampleSubmitDTO")
-    public R<Object> recordSampleSubmit(@Valid @RequestBody RecordSampleSubmitDTO dto) {
-        //TODO 已剥离,融合到自检记录保存中
-        //return R.status(iTrialSelfInspectionRecordService.recordSampleSubmit(dto));
-        return R.status(true);
+    @ApiOperation(value = "获取关联取样信息对应在表中的Data与Key", notes = "传入tabPKeyId、样品sampleIds")
+    public R<Map<String, String>> getRecordSampleData(String tabPKeyId, String sampleIds) {
+        Map<String, String> result = iTrialDetectionDataService.getRecordSampleData(tabPKeyId, sampleIds);
+        return R.data(result);
     }
 
 }

+ 8 - 0
blade-service/blade-business/src/main/java/org/springblade/business/controller/TrialDeviceInfoController.java

@@ -28,6 +28,7 @@ import org.springframework.web.multipart.MultipartFile;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 import java.util.List;
+import java.util.Map;
 
 @RestController
 @RequestMapping("/device")
@@ -118,6 +119,13 @@ public class TrialDeviceInfoController extends BladeController {
         return R.status(iTrialDeviceUseService.useSubmit(dto));
     }
 
+    @GetMapping("/use/submit/getSampleInfo")
+    @ApiOperationSupport(order = 11)
+    @ApiOperation(value = "使用设备新增或修改时,获取检测项目关联的样品信息", notes = "传入节点primaryKeyId")
+    public R<Map<String,String>> useSubmitGetSampleInfo(@RequestParam String primaryKeyId) {
+        return R.data(iTrialDeviceUseService.useSubmitGetSampleInfo(primaryKeyId));
+    }
+
     @GetMapping("/use/remove")
     @ApiOperationSupport(order = 12)
     @ApiOperation(value = "使用设备批量删除", notes = "传入ids")

+ 8 - 0
blade-service/blade-business/src/main/java/org/springblade/business/controller/TrialMaterialController.java

@@ -29,6 +29,7 @@ import org.springframework.web.multipart.MultipartFile;
 
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
+import java.text.ParseException;
 import java.util.List;
 
 @RestController
@@ -54,6 +55,13 @@ public class TrialMaterialController extends BladeController {
         return R.data(iTrialMaterialMobilizationService.samplingRecordList(id));
     }
 
+    @PostMapping("/mobilization/upload-file")
+    @ApiOperationSupport(order = 1)
+    @ApiOperation(value = "附件上传", notes = "传入材料id、type、url地址")
+    public R<Object> uploadFiles(@RequestParam("id") String id,@RequestParam("type") Integer type,@RequestParam("url") String url) {
+        return R.data(iTrialMaterialMobilizationService.uploadFile(id, type, url));
+    }
+
     @GetMapping("/mobilization/detail")
     @ApiOperationSupport(order = 2)
     @ApiOperation(value = "进场材料详情", notes = "传入id")

+ 5 - 3
blade-service/blade-business/src/main/java/org/springblade/business/excel/TrialDeviceInfoExcel.java

@@ -5,6 +5,8 @@ import com.alibaba.excel.annotation.write.style.ColumnWidth;
 import com.alibaba.excel.annotation.write.style.ContentRowHeight;
 import com.alibaba.excel.annotation.write.style.HeadRowHeight;
 import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.NullSerializer;
 import lombok.Data;
 
 import java.io.Serializable;
@@ -51,7 +53,7 @@ public class TrialDeviceInfoExcel implements Serializable {
     private String accuracy;
 
     @ExcelProperty("效验周期(月)")
-    @JsonFormat(shape = JsonFormat.Shape.STRING)
+    @JsonSerialize(nullsUsing = NullSerializer.class)
     private Integer calibrationCycle;
 
     @ExcelProperty("最近效验时间")
@@ -60,11 +62,11 @@ public class TrialDeviceInfoExcel implements Serializable {
 
     @ExcelProperty("状态")
     @JsonFormat(shape = JsonFormat.Shape.STRING)
-    private Integer status;
+    private String status;
 
     @ExcelProperty("是否需要效验")
     @JsonFormat(shape = JsonFormat.Shape.STRING)
-    private Integer isCalibration;
+    private String isCalibration;
 
     @ExcelProperty("设备采集编号")
     private String equipmentAcquisitionNumber;

+ 1 - 1
blade-service/blade-business/src/main/java/org/springblade/business/excel/TrialMaterialMobilizationExcel.java

@@ -30,7 +30,7 @@ public class TrialMaterialMobilizationExcel implements Serializable {
     private String materialName;
 
     @ExcelProperty(value = "材料类型")
-    private Integer materialType;
+    private String materialType;
 
     @ExcelProperty(value = "规格型号")
     private String specificationModel;

+ 3 - 3
blade-service/blade-business/src/main/java/org/springblade/business/excel/TrialSampleInfoExcel.java

@@ -49,7 +49,7 @@ public class TrialSampleInfoExcel implements Serializable {
     @ExcelProperty(value = "生产批号")
     private String batchNumber;
 
-    @ExcelProperty(value = "拟部位")
+    @ExcelProperty(value = "拟部位")
     private String proposedPosition;
 
     @ExcelProperty(value = "供应商单位")
@@ -69,7 +69,7 @@ public class TrialSampleInfoExcel implements Serializable {
     @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd", timezone = "GMT+8")
     private Date samplingDate;
 
-    @ExcelProperty(value = "是否外")
-    private Integer isOutsourcing;
+    @ExcelProperty(value = "是否外")
+    private String isOutsourcing;
 
 }

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

@@ -2,8 +2,11 @@ package org.springblade.business.feignClient;
 
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import lombok.AllArgsConstructor;
+import org.springblade.business.entity.ArchiveFile;
 import org.springblade.business.feign.ArchiveFileClient;
 import org.springblade.business.service.IArchiveFileService;
 import org.springblade.business.vo.ArchiveFileVO;
@@ -61,4 +64,25 @@ public class ArchiveFileClientImpl implements ArchiveFileClient {
     public boolean updateArchiveFileByNodeId(String ids, String nodeId) {
         return this.iArchiveFileService.updateArchiveFileByNodeId(ids,nodeId);
     }
+
+    @Override
+    public List<ArchiveFile> listWrappers(LambdaQueryWrapper<ArchiveFile> in) {
+        return this.iArchiveFileService.list(in);
+    }
+
+    @Override
+    public boolean updateWrappers(LambdaUpdateWrapper<ArchiveFile> eq) {
+        return this.iArchiveFileService.update(eq);
+    }
+
+    @Override
+    public boolean removeFile(List<Long> toLongList) {
+        return this.iArchiveFileService.deleteLogic(toLongList);
+    }
+
+    @Override
+    public List<ArchiveFile> getArchiveFileByArchivesId(String archivesIds,String fileIds) {
+
+        return this.iArchiveFileService.getArchiveFileByArchivesId(archivesIds,fileIds);
+    }
 }

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

@@ -62,4 +62,8 @@ public interface ArchiveFileMapper extends BaseMapper<ArchiveFile> {
 	List<Object> selectBoxNameAndBoxNumber(String nodeId);
 
 	Integer updateArchiveFileByNodeId(List<Long> ids, String nodeId);
+
+	List<ArchiveFile> getArchiveFileByArchivesId(@Param("ids") List<Long> ids);
+
+	List<ArchiveFile> getArchiveFileByFileIds(@Param("ids") List<Long> ids);
 }

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

@@ -49,6 +49,7 @@
         <result column="sort" property="sort"/>
         <result column="box_name" property="boxName"/>
         <result column="box_number" property="boxNumber"/>
+        <result column="is_auto_file" property="isAutoFile"/>
     </resultMap>
     <update id="recoveryByIds">
         update u_archive_file set is_deleted = 0 where
@@ -59,7 +60,7 @@
     </update>
 
     <select id="selectArchiveFileCount" resultType="java.lang.Integer">
-        select count(id) from u_archive_file where is_deleted = 0
+        select count(id) from u_archive_file where is_deleted = 0  and (is_auto_file is null or is_auto_file != 1)
         <if test="vo.isApprovalValue != null and vo.isApprovalValue != ''">
             and status = #{vo.isApprovalValue}
         </if>
@@ -72,6 +73,7 @@
         <if test="vo.contractId != null and vo.contractId != ''">
             and contract_id = #{vo.contractId}
         </if>
+
         <if test="vo.nodeIds != null and vo.nodeIds != ''">
             and node_id in
             <foreach collection="vo.nodeIdArray" item="nodeId" open="(" separator="," close=")">
@@ -91,7 +93,7 @@
     </select>
 
     <select id="selectArchiveFilePage" resultMap="archiveFileResultMap">
-        select * from u_archive_file where is_deleted = 0
+        select * from u_archive_file where is_deleted = 0 and (is_auto_file is null or is_auto_file != 1)
         <if test="vo.isApprovalValue != null and vo.isApprovalValue != ''">
             and status = #{vo.isApprovalValue}
         </if>
@@ -124,7 +126,7 @@
     </select>
 
     <select id="selectArchiveFilePageByBoxNameCount" resultType="java.lang.Integer">
-        select count(id) from u_archive_file where is_deleted = 0
+        select count(id) from u_archive_file where is_deleted = 0 and (is_auto_file is null or is_auto_file != 1)
         <if test="vo.isApprovalValue != null and vo.isApprovalValue != ''">
             and status = #{vo.isApprovalValue}
         </if>
@@ -166,7 +168,7 @@
         order by box_number,sort,create_time DESC
     </select>
     <select id="selectArchiveFilePageByBoxName" resultMap="archiveFileResultMap">
-        select * from u_archive_file where is_deleted = 0
+        select * from u_archive_file where is_deleted = 0 and (is_auto_file is null or is_auto_file != 1)
         <if test="vo.isApprovalValue != null and vo.isApprovalValue != ''">
             and status = #{vo.isApprovalValue}
         </if>
@@ -243,4 +245,26 @@
             #{id}
         </foreach>
     </update>
+
+
+    <select id="getArchiveFileByArchivesId" resultMap="archiveFileResultMap">
+        select * from u_archive_file where is_deleted = 0
+        <if test="ids != null and ids != ''">
+            and archive_id in
+            <foreach collection="ids" item="id" open="(" separator="," close=")">
+                #{id}
+            </foreach>
+        </if>
+        order by sort,create_time DESC
+    </select>
+    <select id="getArchiveFileByFileIds" resultMap="archiveFileResultMap">
+        select * from u_archive_file where is_deleted = 0
+        <if test="ids != null and ids != ''">
+            and id in
+            <foreach collection="ids" item="id" open="(" separator="," close=")">
+                #{id}
+            </foreach>
+        </if>
+        order by sort,create_time DESC
+    </select>
 </mapper>

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

@@ -86,6 +86,99 @@
             where p_key_id = #{item.pKeyId}
         </foreach>
     </update>
+<!--
+    <select id="queryContractTreeSupervision" resultMap="queryContractTreeMap">
+        SELECT c.*,
+        CASE
+        WHEN c.allCount = c.savaCont THEN 2
+        WHEN c.allCount = c.submitCounts THEN 3
+        WHEN c.allCount = c.appCount THEN 4
+        WHEN c.savaCont &gt;=1 or c.submitCounts &gt;=1 or c.appCount &gt;=1 THEN 2
+        ELSE 1 END AS colorStatus
+        from (
+        SELECT
+        wtc.is_concealed_works_node AS "isConcealedWorksNode",
+        wtc.p_key_id AS primaryKeyId,
+        wtc.id,
+        CASE wtc.parent_id WHEN 0 THEN (select ci.contract_name from m_contract_info AS ci where wtc.contract_id = ci.id) ELSE IFNULL(if(length(trim(wtc.full_name)) > 0, wtc.full_name, wtc.node_name),wtc.node_name) END AS title,
+        wtc.parent_id AS parentId,
+        wtc.partition_code AS partitionCode,
+        wtc.contract_id AS contractId,
+        wtc.old_id AS oldId,
+        wtc.major_data_type AS majorDataType,
+        wtc.node_type AS `type`,
+        wtc.node_type AS nodeType,
+        CASE wtc.node_type WHEN 6 THEN 'true' ELSE 'false' END AS leaf,
+        CASE (select count(tc.p_key_id) from m_wbs_tree_contract AS tc where tc.parent_id = wtc.id and tc.contract_id = wtc.contract_id and tc.type = 1 and tc.is_deleted = 0 and tc.node_type != 111)
+        WHEN 0 THEN 'true' ELSE 'false' END AS notExsitChild,
+        ctd.file_url AS fileUrl,
+        ctd.id AS drawingsId,
+        CASE (select count(tcf.id) from u_tree_contract_first AS tcf where tcf.is_deleted = 0 and tcf.wbs_node_id = wtc.p_key_id) WHEN 0 THEN 'false' ELSE 'true' END AS isFirst,
+        (SELECT count(1) from m_wbs_tree_contract where id in(SELECT parent_id from m_wbs_tree_contract a where a.contract_id=#{contractId} and a.is_deleted=0 and a.type=2 and table_owner in(1,2,3)
+        ) and contract_id=wtc.contract_id and type =1 and is_deleted=0 and FIND_IN_SET(wtc.id,ancestors)) as allCount,
+        (SELECT count(1) from m_wbs_tree_contract a ,u_information_query b where a.p_key_id=b.wbs_id and FIND_IN_SET(wtc.id,a.ancestors)  and a.contract_id=wtc.contract_id and b.is_deleted=0 and a.is_deleted=0 and a.`status`=0 and b.classify=1) as savaCont,
+        (SELECT count(1) from m_wbs_tree_contract a ,u_information_query b where a.p_key_id=b.wbs_id and FIND_IN_SET(wtc.id,a.ancestors)  and a.contract_id=wtc.contract_id and b.is_deleted=0 and a.is_deleted=0 and a.`status`=1 and b.classify=1) as submitCounts,
+        (SELECT count(1) from m_wbs_tree_contract a ,u_information_query b where a.p_key_id=b.wbs_id and FIND_IN_SET(wtc.id,a.ancestors)  and a.contract_id=wtc.contract_id and b.is_deleted=0 and a.is_deleted=0 and a.`status`=2 and b.classify=1) as appCount
+        FROM
+        m_wbs_tree_contract AS wtc
+        LEFT JOIN u_contract_tree_drawings AS ctd ON ctd.is_deleted = 0 and ctd.process_id = wtc.p_key_id
+        WHERE wtc.type = 1
+        AND wtc.is_deleted= 0
+        AND wtc.node_type != 111
+        AND wtc.parent_id = #{parentId}
+        and wtc.contract_id IN
+        <foreach collection="contractIds" item="contractId" open="(" separator="," close=")">
+            #{contractId}
+        </foreach>
+        ORDER BY wtc.sort,wtc.create_time
+        ) c
+    </select>
+
+
+    <select id="queryContractTree" resultMap="queryContractTreeMap">
+        SELECT c.*,
+               CASE
+                   WHEN c.allCount = c.savaCont THEN 2
+                   WHEN c.allCount = c.submitCount THEN 3
+                   WHEN c.allCount = c.appCount THEN 4
+                   WHEN c.savaCont>=1 or c.submitCount>=1 or c.appCount>=1 THEN 2
+                   ELSE 1 END AS colorStatus
+        from (
+                 SELECT
+                     wtc.is_concealed_works_node AS "isConcealedWorksNode",
+                     wtc.p_key_id AS primaryKeyId,
+                     wtc.id,
+                     CASE wtc.parent_id WHEN 0 THEN (select ci.contract_name from m_contract_info AS ci where wtc.contract_id = ci.id) ELSE IFNULL(if(length(trim(wtc.full_name)) > 0, wtc.full_name, wtc.node_name),wtc.node_name) END AS title,
+                     wtc.parent_id AS parentId,
+                     wtc.partition_code AS partitionCode,
+                     wtc.contract_id AS contractId,
+                     wtc.old_id AS oldId,
+                     wtc.major_data_type AS majorDataType,
+                     wtc.node_type AS `type`,
+                     wtc.node_type AS nodeType,
+                     CASE wtc.node_type WHEN 6 THEN 'true' ELSE 'false' END AS leaf,
+                     CASE (select count(tc.p_key_id) from m_wbs_tree_contract AS tc where tc.parent_id = wtc.id and tc.contract_id =wtc.contract_id and tc.type = 1 and tc.is_deleted = 0 and tc.node_type != 111)
+            WHEN 0 THEN 'true' ELSE 'false' END AS notExsitChild,
+        ctd.file_url AS fileUrl,
+        ctd.id AS drawingsId,
+        CASE (select count(tcf.id) from u_tree_contract_first AS tcf where tcf.is_deleted = 0 and tcf.wbs_node_id = wtc.p_key_id) WHEN 0 THEN 'false' ELSE 'true' END AS isFirst,
+			 (SELECT count(1) from m_wbs_tree_contract where id in(SELECT parent_id from m_wbs_tree_contract a where a.is_deleted=0 and a.type=2 and table_owner in(1,2,3)
+				) and contract_id=wtc.contract_id and type =1 and is_deleted=0 and FIND_IN_SET(wtc.id,ancestors)) as allCount,
+			 (SELECT count(1) from m_wbs_tree_contract a ,u_information_query b where a.p_key_id=b.wbs_id and FIND_IN_SET(wtc.id,a.ancestors)  and a.contract_id=wtc.contract_id and b.is_deleted=0 and a.is_deleted=0 and a.`status`=0 and b.classify=1) as savaCont,
+			 (SELECT count(1) from m_wbs_tree_contract a ,u_information_query b where a.p_key_id=b.wbs_id and FIND_IN_SET(wtc.id,a.ancestors)  and a.contract_id=wtc.contract_id and b.is_deleted=0 and a.is_deleted=0 and a.`status`=1 and b.classify=1) as submitCount,
+			 (SELECT count(1) from m_wbs_tree_contract a ,u_information_query b where a.p_key_id=b.wbs_id and FIND_IN_SET(wtc.id,a.ancestors)  and a.contract_id=wtc.contract_id and b.is_deleted=0 and a.is_deleted=0 and a.`status`=2 and b.classify=1) as appCount
+				FROM
+        m_wbs_tree_contract AS wtc
+        LEFT JOIN u_contract_tree_drawings AS ctd ON ctd.is_deleted = 0 and ctd.process_id = wtc.p_key_id
+        WHERE wtc.type = 1
+        AND wtc.is_deleted= 0
+        AND wtc.node_type != 111
+        AND wtc.parent_id = #{parentId}
+        AND wtc.contract_id = #{contractId}
+        ORDER BY wtc.sort,wtc.create_time
+		) c
+    </select>-->
+
 
     <select id="queryContractTreeSupervision" resultMap="queryContractTreeMap">
         SELECT
@@ -177,7 +270,7 @@
         ORDER BY wtc.sort,wtc.create_time
     </select>
 
-    <select id="queryContractTree" resultMap="queryContractTreeMap">
+ <select id="queryContractTree" resultMap="queryContractTreeMap">
         SELECT
             wtc.is_concealed_works_node AS "isConcealedWorksNode",
             wtc.p_key_id AS primaryKeyId,
@@ -254,6 +347,7 @@
                 group by wtc.p_key_id
             ) AS querys
         ) AS querys ON wtc.p_key_id = querys.pKeyId
+
         WHERE wtc.type = 1
         AND wtc.is_deleted= 0
         AND wtc.node_type != 111

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

@@ -30,7 +30,7 @@
     </resultMap>
 
     <select id="selectTrialTreeAll" resultType="org.springblade.manager.entity.WbsTreePrivate">
-        select * from m_wbs_tree_private where project_id = #{projectId} and wbs_type = 2 and status = 1 and is_deleted = 0
+        select p_key_id,id,node_name from m_wbs_tree_private where project_id = #{projectId} and wbs_type = 2 and status = 1 and is_deleted = 0
     </select>
 
 </mapper>

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

@@ -65,4 +65,6 @@ public interface IArchiveFileService extends BaseService<ArchiveFile> {
 	List<Object> selectBoxNameAndBoxNumber(String nodeId);
 
 	boolean updateArchiveFileByNodeId(String ids, String nodeId);
+
+	List<ArchiveFile> getArchiveFileByArchivesId(String archivesIds,String fileIds);
 }

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

@@ -7,6 +7,8 @@ import org.springblade.business.entity.TrialDetectionData;
 import org.springblade.business.vo.TrialDetectionDataVO;
 import org.springblade.core.mp.base.BaseService;
 
+import java.util.Map;
+
 public interface ITrialDetectionDataService extends BaseService<TrialDetectionData> {
 
     TrialDetectionData dataDetail(Long id);
@@ -17,4 +19,6 @@ public interface ITrialDetectionDataService extends BaseService<TrialDetectionDa
 
     boolean dataCopy(TrialDetectionDataDTO dto);
 
+    Map<String, String> getRecordSampleData(String tabPKeyId,String sampleIds);
+
 }

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

@@ -9,6 +9,7 @@ import org.springblade.core.mp.base.BaseService;
 
 import javax.servlet.http.HttpServletResponse;
 import java.util.List;
+import java.util.Map;
 
 public interface ITrialDeviceUseService extends BaseService<TrialDeviceUse> {
 
@@ -22,4 +23,6 @@ public interface ITrialDeviceUseService extends BaseService<TrialDeviceUse> {
 
     boolean importBatchDeviceUse(List<TrialDeviceUseExcel> list, Long projectId, Long contractId);
 
+    Map<String,String> useSubmitGetSampleInfo(String primaryKeyId);
+
 }

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

@@ -9,6 +9,7 @@ import org.springblade.business.vo.TrialSamplingRecordVO;
 import org.springblade.core.mp.base.BaseService;
 
 import javax.servlet.http.HttpServletResponse;
+import java.text.ParseException;
 import java.util.List;
 
 
@@ -32,4 +33,6 @@ public interface ITrialMaterialMobilizationService extends BaseService<TrialMate
 
     List<TrialSamplingRecordVO> samplingRecordList(Long id);
 
+    boolean uploadFile(String id, Integer type, String url);
+
 }

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

@@ -31,10 +31,8 @@ public interface ITrialSelfInspectionRecordService extends BaseService<TrialSelf
 
     String selfPrintNullPdf(String ids) throws Exception;
 
-    @Async
     void updateTrialSelfInspectionRecordStatus(String pdfUrlEVisa, TaskApprovalVO obj) throws FileNotFoundException;
 
-    @Async
     void updateTrialSelfInspectionRecordStatusFC(TaskApprovalVO obj);
 
     String addBussFile(MultipartFile file, Long pkeyId, String nodeId, String contractId, String projectId, String classify, String id, String tableType) throws Exception;

+ 12 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/ArchiveFileServiceImpl.java

@@ -17,6 +17,7 @@ import org.springblade.system.feign.IDictBizClient;
 import org.springframework.stereotype.Service;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
@@ -144,6 +145,17 @@ public class ArchiveFileServiceImpl extends BaseServiceImpl<ArchiveFileMapper, A
 		return true;
 	}
 
+	@Override
+	public List<ArchiveFile> getArchiveFileByArchivesId(String archivesIds,String fileIds) {
+		if(!archivesIds.isEmpty() && archivesIds != ""){
+			return baseMapper.getArchiveFileByArchivesId(Func.toLongList(archivesIds));
+		}else if(!fileIds.isEmpty() && fileIds != ""){
+			return baseMapper.getArchiveFileByFileIds(Func.toLongList(fileIds));
+		}else{
+			return new ArrayList<>();
+		}
+	}
+
 	@Override
 	public IPage<ArchiveFileVO> selectArchiveFilePageByBoxName(ArchiveFileVO vo) {
 		Query query = new Query();

+ 5 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialContainerClassificationServiceImpl.java

@@ -230,6 +230,11 @@ public class TrialContainerClassificationServiceImpl
                     String s1 = s.split(" ")[0];
                     objectObjectEntry.setValue(s1);
                 }
+                if (objectObjectEntry.getValue().toString().contains(" 00:00:00.0")) {
+                    Object value = objectObjectEntry.getValue();
+                    String replace = value.toString().replace(" 00:00:00.0", "");
+                    objectObjectEntry.setValue(replace);
+                }
             }
         }
         return page.setRecords(hashMaps);

+ 130 - 7
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialDetectionDataServiceImpl.java

@@ -2,36 +2,56 @@ package org.springblade.business.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.AllArgsConstructor;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.time.DateUtils;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
 import org.springblade.business.dto.TrialDetectionDataDTO;
 import org.springblade.business.dto.TrialDetectionDataPageDTO;
 import org.springblade.business.entity.TrialDetectionData;
+import org.springblade.business.entity.TrialSampleInfo;
+import org.springblade.business.entity.TrialSelfInspectionRecord;
 import org.springblade.business.mapper.TrialDetectionDataMapper;
 import org.springblade.business.mapper.TrialSelfInspectionRecordMapper;
 import org.springblade.business.service.ITrialDetectionDataService;
 import org.springblade.business.vo.TrialDetectionDataVO;
+import org.springblade.business.vo.TrialSelfSample;
 import org.springblade.common.utils.SnowFlakeUtil;
+import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.mp.base.BaseServiceImpl;
 import org.springblade.core.mp.support.Condition;
 import org.springblade.core.mp.utils.PageUtil;
-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.manager.entity.TextdictInfo;
+import org.springblade.manager.entity.WbsFormElement;
+import org.springblade.manager.entity.WbsTreePrivate;
+import org.springblade.manager.feign.WbsTreeContractClient;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.stereotype.Service;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 @Service
 @AllArgsConstructor
 public class TrialDetectionDataServiceImpl extends BaseServiceImpl<TrialDetectionDataMapper, TrialDetectionData> implements ITrialDetectionDataService {
 
     private final TrialSelfInspectionRecordMapper inspectionRecordMapper;
-
+    private final JdbcTemplate jdbcTemplate;
 
     @Override
     public TrialDetectionData dataDetail(Long id) {
@@ -40,6 +60,34 @@ public class TrialDetectionDataServiceImpl extends BaseServiceImpl<TrialDetectio
 
     @Override
     public boolean dataSubmit(TrialDetectionData obj) {
+        List<TrialDetectionData> trialDetectionData = baseMapper.selectList(Wrappers.<TrialDetectionData>lambdaQuery()
+                .select(TrialDetectionData::getId)
+                .isNotNull(TrialDetectionData::getReportNo)
+                .eq(TrialDetectionData::getReportNo, obj.getReportNo()));
+        if (ObjectUtil.isEmpty(obj.getId()) && trialDetectionData.size() > 0) {
+            throw new ServiceException("报告编号已存在,请重新填写");
+        }
+        if (ObjectUtil.isNotEmpty(obj.getId()) && trialDetectionData.size() > 0) {
+            TrialDetectionData data = trialDetectionData.stream().findAny().orElse(null);
+            if (!obj.getId().equals(data.getId())) {
+                throw new ServiceException("报告编号已存在,请重新填写");
+            }
+        }
+
+        List<TrialDetectionData> trialDetectionData2 = baseMapper.selectList(Wrappers.<TrialDetectionData>lambdaQuery()
+                .select(TrialDetectionData::getId)
+                .isNotNull(TrialDetectionData::getEntrustNo)
+                .eq(TrialDetectionData::getEntrustNo, obj.getEntrustNo()));
+        if (ObjectUtil.isEmpty(obj.getId()) && trialDetectionData2.size() > 0) {
+            throw new ServiceException("委托编号已存在,请重新填写");
+        }
+        if (ObjectUtil.isNotEmpty(obj.getId()) && trialDetectionData2.size() > 0) {
+            TrialDetectionData data = trialDetectionData2.stream().findAny().orElse(null);
+            if (!obj.getId().equals(data.getId())) {
+                throw new ServiceException("委托编号已存在,请重新填写");
+            }
+        }
+
         return this.saveOrUpdate(obj);
     }
 
@@ -60,7 +108,7 @@ public class TrialDetectionDataServiceImpl extends BaseServiceImpl<TrialDetectio
         if (StringUtils.isNotEmpty(dto.getQueryValue())) {
             queryWrapper.lambda().and(wrapper -> wrapper.like(TrialDetectionData::getEntrustNo, dto.getQueryValue()).or().like(TrialDetectionData::getReportNo, dto.getQueryValue()));
         }
-        IPage<TrialDetectionData> pages = this.page(page, queryWrapper.lambda().orderBy(true, true, TrialDetectionData::getCreateTime));
+        IPage<TrialDetectionData> pages = this.page(page, queryWrapper.lambda().orderBy(true, false, TrialDetectionData::getCreateTime));
         List<TrialDetectionDataVO> trialDetectionDataVOS = BeanUtil.copyProperties(pages.getRecords(), TrialDetectionDataVO.class);
 
         if (ObjectUtil.isNotEmpty(dto.getQualityTestPKeyId())) {
@@ -100,7 +148,7 @@ public class TrialDetectionDataServiceImpl extends BaseServiceImpl<TrialDetectio
         } else {
             //单条复制编辑新增保存
             TrialDetectionData obj = BeanUtil.copyProperties(dto, TrialDetectionData.class);
-            if (obj != null){
+            if (obj != null) {
                 obj.setId(SnowFlakeUtil.getId());
                 obj.setEntrustNo(String.valueOf(SnowFlakeUtil.getId()));
                 obj.setReportNo(String.valueOf(SnowFlakeUtil.getId()));
@@ -110,6 +158,81 @@ public class TrialDetectionDataServiceImpl extends BaseServiceImpl<TrialDetectio
         return true;
     }
 
+    @Override
+    public Map<String, String> getRecordSampleData(String tabPKeyId, String sampleIds) {
+        Map<String, String> resultMap = new HashMap<>();
+        //获取表中的数据信息Data、以及对应的Key值
+        WbsTreePrivate wbsTreePrivate = jdbcTemplate.query("select init_table_name,html_url,p_key_id from m_wbs_tree_private where p_key_id =" + tabPKeyId, new BeanPropertyRowMapper<>(WbsTreePrivate.class)).stream().findAny().orElse(null);
+        if (wbsTreePrivate == null) {
+            return null;
+        }
+        if (wbsTreePrivate.getHtmlUrl() == null) {
+            return null;
+        }
+
+        // 匹配关联
+        try {
+            File file1 = ResourceUtil.getFile(wbsTreePrivate.getHtmlUrl());
+            String htmlString = IoUtil.readToString(new FileInputStream(file1));
+            Document doc = Jsoup.parse(htmlString);
+            Elements ypName = doc.select("el-input[placeholder~=样品名称.*]");
+            Elements ypNumber = doc.select("el-input[placeholder~=样品编号.*]");
+            Elements ypCount = doc.select("el-input[placeholder~=样品数量.*]");
+            Elements ypMs = doc.select("el-input[placeholder~=样品描述.*]");
+
+            //获取样品信息
+            if (StringUtils.isNotEmpty(sampleIds)) {
+                List<TrialSampleInfo> trialSampleInfoList = jdbcTemplate.query("select material_name,specification_number,sample_description,material_count from u_trial_sample_info where id in(" + sampleIds + ")", new BeanPropertyRowMapper<>(TrialSampleInfo.class));
+                List<String> names = trialSampleInfoList.stream().map(TrialSampleInfo::getMaterialName).collect(Collectors.toList());
+                List<String> numbers = trialSampleInfoList.stream().map(TrialSampleInfo::getSpecificationNumber).collect(Collectors.toList());
+                List<String> descriptions = trialSampleInfoList.stream().map(TrialSampleInfo::getSampleDescription).collect(Collectors.toList());
+                List<Integer> counts = trialSampleInfoList.stream().map(TrialSampleInfo::getMaterialCount).collect(Collectors.toList());
+
+                //样品名称
+                if (ypName.size() >= 1) {
+                    for (Element element : ypName) {
+                        int trIndex = Integer.parseInt(element.attr("trindex"));
+                        if (trIndex <= 6) {
+                            resultMap.put(element.attr("keyName"), ObjectUtils.isNotEmpty(names) ? StringUtils.join(names, "、") : "");
+                        }
+                    }
+                }
+                //样品编号
+                if (ypNumber.size() >= 1) {
+                    for (Element element : ypNumber) {
+                        int trIndex = Integer.parseInt(element.attr("trindex"));
+                        if (trIndex <= 6) {
+                            resultMap.put(element.attr("keyName"), ObjectUtils.isNotEmpty(numbers) ? StringUtils.join(numbers, "、") : "");
+                        }
+                    }
+                }
+                //样品数量
+                if (ypCount.size() >= 1) {
+                    for (Element element : ypCount) {
+                        int trIndex = Integer.parseInt(element.attr("trindex"));
+                        if (trIndex <= 6) {
+                            resultMap.put(element.attr("keyName"), ObjectUtils.isNotEmpty(counts) ? counts.stream().reduce(Integer::sum).orElse(0).toString() : "");
+                        }
+                    }
+                }
+                //样品描述
+                if (ypMs.size() >= 1) {
+                    for (Element element : ypMs) {
+                        int trIndex = Integer.parseInt(element.attr("trindex"));
+                        if (trIndex <= 6) {
+                            resultMap.put(element.attr("keyName"), ObjectUtils.isNotEmpty(descriptions) ? StringUtils.join(descriptions, "、") : "");
+                        }
+                    }
+                }
+
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return resultMap;
+    }
+
 }
 
 

+ 65 - 25
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialDeviceInfoServiceImpl.java

@@ -3,10 +3,7 @@ package org.springblade.business.service.impl;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.lowagie.text.Document;
-import com.lowagie.text.DocumentException;
-import com.lowagie.text.Font;
-import com.lowagie.text.Paragraph;
+import com.lowagie.text.*;
 import com.lowagie.text.pdf.BaseFont;
 import com.lowagie.text.pdf.PdfPTable;
 import com.lowagie.text.pdf.PdfWriter;
@@ -25,6 +22,7 @@ import org.springblade.business.vo.TrialDeviceInfoVO3;
 import org.springblade.business.wrapper.TrialDeviceInfoWarpper;
 import org.springblade.common.utils.CommonUtil;
 import org.springblade.common.utils.SystemUtils;
+import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.mp.base.BaseServiceImpl;
 import org.springblade.core.mp.support.Condition;
 import org.springblade.core.oss.model.BladeFile;
@@ -56,14 +54,25 @@ public class TrialDeviceInfoServiceImpl extends BaseServiceImpl<TrialDeviceInfoM
 
     @Override
     public boolean submit(TrialDeviceInfo obj) {
-        if (ObjectUtil.isNotEmpty(obj.getId())) {
+        TrialDeviceInfo selectOne = baseMapper.selectOne(Wrappers.<TrialDeviceInfo>lambdaQuery().select(TrialDeviceInfo::getId, TrialDeviceInfo::getDeviceName).eq(TrialDeviceInfo::getDeviceNumber, obj.getDeviceNumber()));
+
+        if (ObjectUtil.isNotEmpty(obj.getId())) { //编辑
+            if (ObjectUtil.isNotEmpty(selectOne) && !selectOne.getId().equals(obj.getId())) {
+                throw new ServiceException("当前设备编号已存在,请重新填写");
+            }
+
             TrialDeviceInfo trialDeviceInfo = baseMapper.selectById(obj.getId());
             if (ObjectUtil.isNotEmpty(trialDeviceInfo.getLastCalibrationTime()) && ObjectUtil.isNotEmpty(obj.getLastCalibrationTime())
                     && !trialDeviceInfo.getLastCalibrationTime().equals(obj.getLastCalibrationTime())) {
                 //如果修改了最近校验时间,那么每次编辑默认修改校验为0=否
                 obj.setIsCalibration(0);
             }
+        } else { //新增
+            if (ObjectUtil.isNotEmpty(selectOne)) {
+                throw new ServiceException("当前设备编号已存在,请重新填写");
+            }
         }
+
         return this.saveOrUpdate(obj);
     }
 
@@ -113,9 +122,19 @@ public class TrialDeviceInfoServiceImpl extends BaseServiceImpl<TrialDeviceInfoM
         List<TrialDeviceClassification> deviceClassifications = trialDeviceClassificationMapper.selectList(Wrappers.<TrialDeviceClassification>query().lambda().eq(TrialDeviceClassification::getContractId, contractId));
 
         QueryWrapper<TrialDeviceInfo> queryWrapper = Condition.getQueryWrapper(obj);
-        if (ObjectUtil.isNotEmpty(obj.getDeviceClassId())) {
-            queryWrapper.lambda().eq(TrialDeviceInfo::getDeviceClassId, obj.getDeviceClassId());
+
+        if (ObjectUtil.isEmpty(obj.getDeviceClassId()) || obj.getDeviceClassId() == 0) {
+            List<Long> ids = deviceClassifications.stream().map(TrialDeviceClassification::getId).collect(Collectors.toList());
+            if (ids.size() > 0) {
+                obj.setDeviceClassId(null);
+                queryWrapper.lambda().in(TrialDeviceInfo::getDeviceClassId, ids);
+            }
+        } else {
+            if (ObjectUtil.isNotEmpty(obj.getDeviceClassId())) {
+                queryWrapper.lambda().eq(TrialDeviceInfo::getDeviceClassId, obj.getDeviceClassId());
+            }
         }
+
         if (ObjectUtil.isNotEmpty(obj.getIsCalibration())) {
             queryWrapper.lambda().eq(TrialDeviceInfo::getIsCalibration, obj.getIsCalibration());
         }
@@ -166,7 +185,7 @@ public class TrialDeviceInfoServiceImpl extends BaseServiceImpl<TrialDeviceInfoM
             }
 
             //创建文档,设置页面大小、左右上下边距
-            Document document = new Document();
+            Document document = new Document(new RectangleReadOnly(842F, 595F)); //横向pdf
 
             BaseFont bfChinese = null;
             String pdfUrl = null;
@@ -233,30 +252,39 @@ public class TrialDeviceInfoServiceImpl extends BaseServiceImpl<TrialDeviceInfoM
             document.add(tableTitle);
             document.add(new Paragraph("\n"));
 
-            String[] array = {"ID", "设备名称", "设备分类", "设备编号", "设备型号", "生产厂家", "出厂日期", "出厂编号", "进场日期", "测量范围",
-                    "精准度", "校准周期(月)", "最近校验时间", "状态", "是否需要校验", "设备采集编号", "设备管理人员", "备注"};
+            String[] array = {"ID", "设备名称", "设备分类", "设备编号", "设备型号", "生产厂家", "出厂日期", "出厂编号", "进场日期", "测量范围", "精准度", "校准周期(月)", "最近校验时间", "状态", "是否需要校验", "设备采集编号", "设备管理人员", "备注"};
             for (String s : array) {
                 PDFUtil.createTableCell(s, textFont, table, lineHeight, colSpan);
             }
             for (TrialDeviceInfo pdfDatum : pdfData) {
                 PDFUtil.createTableCell(String.valueOf(pdfDatum.getId()), textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(pdfDatum.getDeviceName(), textFont, table, lineHeight, colSpan);
+
+                String className = "";
                 for (TrialDeviceClassification classification : deviceClassificationList) {
                     if (classification.getId().equals(pdfDatum.getDeviceClassId())) {
-                        PDFUtil.createTableCell(classification.getClassName(), textFont, table, lineHeight, colSpan);
+                        className = classification.getClassName();
+                        break;
                     }
                 }
+                PDFUtil.createTableCell(className, textFont, table, lineHeight, colSpan);
+
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getDeviceNumber()) ? pdfDatum.getDeviceNumber() : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getDeviceModel()) ? pdfDatum.getDeviceModel() : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getManufacturer()) ? pdfDatum.getManufacturer() : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getFactoryDate()) ? pdfDatum.getFactoryDate().toString() : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getFactoryNumber()) ? pdfDatum.getFactoryNumber() : "", textFont, table, lineHeight, colSpan);
-                PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getEquipmentAcquisitionNumber()) ? pdfDatum.getEquipmentAcquisitionNumber() : "", textFont, table, lineHeight, colSpan);
-                PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getAccuracy()) ? pdfDatum.getAccuracy() : "", textFont, table, lineHeight, colSpan);
+
+                PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getMobilizationDate()) ? DateUtil.format(pdfDatum.getMobilizationDate(), "yyyy-MM-dd") : "", textFont, table, lineHeight, colSpan);
+
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getMeasuringRange()) ? pdfDatum.getMeasuringRange() : "", textFont, table, lineHeight, colSpan);
-                PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getLastCalibrationTime()) ? pdfDatum.getLastCalibrationTime().toString() : "", textFont, table, lineHeight, colSpan);
-                PDFUtil.createTableCell(pdfDatum.getStatus().equals(0) ? "已停用" : "启用中", textFont, table, lineHeight, colSpan);
-                PDFUtil.createTableCell(pdfDatum.getIsCalibration().equals(0) ? "否" : "是", textFont, table, lineHeight, colSpan);
+                PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getAccuracy()) ? pdfDatum.getAccuracy() : "", textFont, table, lineHeight, colSpan);
+                PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getCalibrationCycle()) ? pdfDatum.getCalibrationCycle().toString() : "", textFont, table, lineHeight, colSpan);
+
+                PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getLastCalibrationTime()) ? DateUtil.format(pdfDatum.getLastCalibrationTime(), "yyyy-MM-dd") : "", textFont, table, lineHeight, colSpan);
+
+                PDFUtil.createTableCell(new Integer(0).equals(pdfDatum.getStatus()) ? "已停用" : "启用中", textFont, table, lineHeight, colSpan);
+                PDFUtil.createTableCell(new Integer(0).equals(pdfDatum.getIsCalibration()) ? "否" : "是", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getEquipmentAcquisitionNumber()) ? pdfDatum.getEquipmentAcquisitionNumber() : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getManagerName()) ? pdfDatum.getManagerName() : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getRemarks()) ? pdfDatum.getRemarks() : "", textFont, table, lineHeight, colSpan);
@@ -305,19 +333,31 @@ public class TrialDeviceInfoServiceImpl extends BaseServiceImpl<TrialDeviceInfoM
         List<TrialDeviceClassification> deviceClassifications = trialDeviceClassificationMapper.selectList(Wrappers.<TrialDeviceClassification>query().lambda().eq(TrialDeviceClassification::getContractId, contractId));
         List<TrialDeviceInfo> listData = new ArrayList<>();
         for (TrialDeviceInfoExcel trialDeviceInfoExcel : list) {
-            for (TrialDeviceClassification deviceClassification : deviceClassifications) {
-                if (trialDeviceInfoExcel.getDeviceClassName().equals(deviceClassification.getClassName())) {
-                    TrialDeviceInfo trialDeviceInfo = BeanUtil.copyProperties(trialDeviceInfoExcel, TrialDeviceInfo.class);
-                    if (trialDeviceInfo != null) {
-                        trialDeviceInfo.setStatus(trialDeviceInfoExcel.getStatus().equals(1) ? 1 : 0);
-                        trialDeviceInfo.setIsCalibration(trialDeviceInfoExcel.getIsCalibration().equals(1) ? 1 : 0);
-                        trialDeviceInfo.setDeviceClassId(deviceClassification.getId());
-                        listData.add(trialDeviceInfo);
+            if (ObjectUtil.isNotEmpty(trialDeviceInfoExcel.getDeviceClassName())) {
+                for (TrialDeviceClassification deviceClassification : deviceClassifications) {
+                    if (trialDeviceInfoExcel.getDeviceClassName().equals(deviceClassification.getClassName())) {
+                        TrialDeviceInfo trialDeviceInfo = BeanUtil.copyProperties(trialDeviceInfoExcel, TrialDeviceInfo.class);
+                        if (trialDeviceInfo != null) {
+                            trialDeviceInfo.setStatus(("已启用").equals(trialDeviceInfoExcel.getStatus()) ? 1 : 0);
+                            trialDeviceInfo.setIsCalibration(("是").equals(trialDeviceInfoExcel.getIsCalibration()) ? 1 : 0);
+                            trialDeviceInfo.setDeviceClassId(deviceClassification.getId());
+                            listData.add(trialDeviceInfo);
+                        }
                     }
                 }
             }
         }
-        return this.saveBatch(listData, 1000);
+        if (listData.size() > 0) {
+            List<String> numbers = listData.stream().map(TrialDeviceInfo::getDeviceNumber).collect(Collectors.toList());
+            List<TrialDeviceInfo> trialDeviceInfos = baseMapper.selectList(Wrappers.<TrialDeviceInfo>lambdaQuery().select(TrialDeviceInfo::getId, TrialDeviceInfo::getDeviceName).in(TrialDeviceInfo::getDeviceNumber, numbers));
+            if (trialDeviceInfos.size() > 0) {
+                List<String> collect = trialDeviceInfos.stream().map(TrialDeviceInfo::getDeviceName).collect(Collectors.toList());
+                throw new ServiceException("【" + StringUtils.join(collect, ",") + "】的设备编号重复,请重新填写设备编号");
+            }
+
+            return this.saveBatch(listData, 1000);
+        }
+        return true;
     }
 
     @Override

+ 23 - 6
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialDeviceOverhaulServiceImpl.java

@@ -17,6 +17,7 @@ import org.springblade.business.dto.TrialDeviceOverhaulDTO;
 import org.springblade.business.entity.TrialDeviceClassification;
 import org.springblade.business.entity.TrialDeviceInfo;
 import org.springblade.business.entity.TrialDeviceOverhaul;
+import org.springblade.business.entity.TrialDeviceUse;
 import org.springblade.business.excel.TrialDeviceOverhaulExcel;
 import org.springblade.business.mapper.TrialDeviceClassificationMapper;
 import org.springblade.business.mapper.TrialDeviceInfoMapper;
@@ -70,7 +71,7 @@ public class TrialDeviceOverhaulServiceImpl extends BaseServiceImpl<TrialDeviceO
             dto.setFactoryNumber(trialDeviceInfo.getFactoryNumber());
         }
         TrialDeviceOverhaul trialDeviceOverhaul = BeanUtil.copyProperties(dto, TrialDeviceOverhaul.class);
-        if (trialDeviceOverhaul != null){
+        if (trialDeviceOverhaul != null) {
             return this.saveOrUpdate(trialDeviceOverhaul);
         }
         return false;
@@ -82,11 +83,21 @@ public class TrialDeviceOverhaulServiceImpl extends BaseServiceImpl<TrialDeviceO
         List<TrialDeviceClassification> deviceClassificationList = trialDeviceClassificationMapper.selectList(Wrappers.<TrialDeviceClassification>query().lambda().eq(TrialDeviceClassification::getContractId, contractId));
 
         QueryWrapper<TrialDeviceOverhaul> queryWrapper = Condition.getQueryWrapper(dto);
-        if (ObjectUtil.isNotEmpty(dto.getDeviceClassId())) {
-            queryWrapper.lambda().eq(TrialDeviceOverhaul::getDeviceClassId, dto.getDeviceClassId());
+
+        if (ObjectUtil.isEmpty(dto.getDeviceClassId()) || dto.getDeviceClassId() == 0) {
+            List<Long> ids = deviceClassificationList.stream().map(TrialDeviceClassification::getId).collect(Collectors.toList());
+            if (ids.size() > 0) {
+                dto.setDeviceClassId(null);
+                queryWrapper.lambda().in(TrialDeviceOverhaul::getDeviceClassId, ids);
+            }
+        } else {
+            if (ObjectUtil.isNotEmpty(dto.getDeviceClassId())) {
+                queryWrapper.lambda().eq(TrialDeviceOverhaul::getDeviceClassId, dto.getDeviceClassId());
+            }
         }
+
         if (ObjectUtil.isNotEmpty(dto.getQueryValue())) {
-            queryWrapper.lambda().and(wrapper -> wrapper.like(TrialDeviceOverhaul::getDeviceName, dto.getDeviceName()).or().like(TrialDeviceOverhaul::getDeviceModel, dto.getDeviceModel()));
+            queryWrapper.lambda().and(wrapper -> wrapper.like(TrialDeviceOverhaul::getDeviceName, dto.getQueryValue()).or().like(TrialDeviceOverhaul::getDeviceModel, dto.getQueryValue()));
         }
         if (StringUtils.isNotEmpty(dto.getStartTime()) && StringUtils.isNotEmpty(dto.getEndTime())) {
             String endTime = dto.getEndTime();
@@ -203,16 +214,22 @@ public class TrialDeviceOverhaulServiceImpl extends BaseServiceImpl<TrialDeviceO
             for (TrialDeviceOverhaul pdfDatum : pdfData) {
                 PDFUtil.createTableCell(String.valueOf(pdfDatum.getId()), textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(pdfDatum.getDeviceName(), textFont, table, lineHeight, colSpan);
+
+                String className = "";
                 for (TrialDeviceClassification classification : deviceClassificationList) {
                     if (classification.getId().equals(pdfDatum.getDeviceClassId())) {
-                        PDFUtil.createTableCell(classification.getClassName(), textFont, table, lineHeight, colSpan);
+                        className = classification.getClassName();
                         break;
                     }
                 }
+                PDFUtil.createTableCell(className, textFont, table, lineHeight, colSpan);
+
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getDeviceNumber()) ? pdfDatum.getDeviceNumber() : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getDeviceModel()) ? pdfDatum.getDeviceModel() : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getFactoryNumber()) ? pdfDatum.getFactoryNumber() : "", textFont, table, lineHeight, colSpan);
-                PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getOverhaulDate()) ? pdfDatum.getOverhaulDate().toString() : "", textFont, table, lineHeight, colSpan);
+
+                PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getOverhaulDate()) ? DateUtil.format(pdfDatum.getOverhaulDate(), "yyyy-MM-dd") : "", textFont, table, lineHeight, colSpan);
+
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getOverhaulText()) ? pdfDatum.getOverhaulText() : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getManagerName()) ? pdfDatum.getManagerName() : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getRemarks()) ? pdfDatum.getRemarks() : "", textFont, table, lineHeight, colSpan);

+ 71 - 12
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialDeviceUseServiceImpl.java

@@ -15,16 +15,15 @@ import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.time.DateUtils;
 import org.springblade.business.dto.TrialDeviceUseDTO;
 import org.springblade.business.dto.TrialSelfInspectionRecordDTO;
-import org.springblade.business.entity.TrialDeviceClassification;
-import org.springblade.business.entity.TrialDeviceInfo;
+import org.springblade.business.entity.*;
 import org.springblade.business.excel.TrialDeviceUseExcel;
 import org.springblade.business.mapper.TrialDeviceClassificationMapper;
 import org.springblade.business.mapper.TrialDeviceInfoMapper;
 import org.springblade.business.utils.PDFUtil;
 import org.springblade.business.vo.TrialDeviceUsePageVO;
-import org.springblade.business.entity.TrialDeviceUse;
 import org.springblade.business.mapper.TrialDeviceUseMapper;
 import org.springblade.business.service.ITrialDeviceUseService;
+import org.springblade.business.vo.TrialSelfSample;
 import org.springblade.business.wrapper.TrialDeviceUseWarpper;
 import org.springblade.common.utils.CommonUtil;
 import org.springblade.common.utils.SnowFlakeUtil;
@@ -38,6 +37,8 @@ import org.springblade.core.tool.utils.Func;
 import org.springblade.core.tool.utils.ObjectUtil;
 import org.springblade.manager.entity.WbsTreePrivate;
 import org.springblade.resource.feign.NewIOSSClient;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
@@ -46,7 +47,9 @@ import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 @Service
@@ -56,6 +59,8 @@ public class TrialDeviceUseServiceImpl extends BaseServiceImpl<TrialDeviceUseMap
     private final NewIOSSClient newIOSSClient;
     private final TrialDeviceClassificationMapper trialDeviceClassificationMapper;
     private final TrialDeviceInfoMapper trialDeviceInfoMapper;
+    private final TrialSampleInfoServiceImpl trialSampleInfoService;
+    private final JdbcTemplate jdbcTemplate;
 
     @Override
     public TrialDeviceUse useDetail(Long id) {
@@ -87,9 +92,19 @@ public class TrialDeviceUseServiceImpl extends BaseServiceImpl<TrialDeviceUseMap
         List<WbsTreePrivate> wbsTreePrivates = baseMapper.selectTrialTreeAll(String.valueOf(projectId), 2);
 
         QueryWrapper<TrialDeviceUse> queryWrapper = Condition.getQueryWrapper(dto);
-        if (ObjectUtil.isNotEmpty(dto.getDeviceClassId())) {
-            queryWrapper.lambda().eq(TrialDeviceUse::getDeviceClassId, dto.getDeviceClassId());
+
+        if (ObjectUtil.isEmpty(dto.getDeviceClassId()) || dto.getDeviceClassId() == 0) {
+            List<Long> ids = deviceClassificationList.stream().map(TrialDeviceClassification::getId).collect(Collectors.toList());
+            if (ids.size() > 0) {
+                dto.setDeviceClassId(null);
+                queryWrapper.lambda().in(TrialDeviceUse::getDeviceClassId, ids);
+            }
+        } else {
+            if (ObjectUtil.isNotEmpty(dto.getDeviceClassId())) {
+                queryWrapper.lambda().eq(TrialDeviceUse::getDeviceClassId, dto.getDeviceClassId());
+            }
         }
+
         if (ObjectUtil.isNotEmpty(dto.getQueryValue())) {
             queryWrapper.lambda().and(wrapper -> wrapper.like(TrialDeviceUse::getDeviceName, dto.getDeviceName()).or().like(TrialDeviceUse::getDeviceModel, dto.getDeviceModel()));
         }
@@ -101,15 +116,19 @@ public class TrialDeviceUseServiceImpl extends BaseServiceImpl<TrialDeviceUseMap
         IPage<TrialDeviceUse> resultPages = this.page(page, queryWrapper.lambda().orderBy(true, true, TrialDeviceUse::getCreateTime));
         IPage<TrialDeviceUsePageVO> trialDeviceUsePageDTOIPage = TrialDeviceUseWarpper.build().pageVO(resultPages);
         List<TrialDeviceUsePageVO> records = trialDeviceUsePageDTOIPage.getRecords();
+
         for (TrialDeviceUsePageVO record : records) {
             for (TrialDeviceClassification classification : deviceClassificationList) {
                 if (record.getDeviceClassId().equals(classification.getId())) {
                     record.setDeviceClassName(classification.getClassName());
+                    break;
                 }
             }
+
             for (WbsTreePrivate wbsTreePrivate : wbsTreePrivates) {
                 if (ObjectUtil.isNotEmpty(record.getNodeId()) && record.getNodeId().equals(wbsTreePrivate.getPKeyId())) {
                     record.setNodeName(wbsTreePrivate.getNodeName());
+                    break;
                 }
             }
         }
@@ -128,7 +147,7 @@ public class TrialDeviceUseServiceImpl extends BaseServiceImpl<TrialDeviceUseMap
             //获取设备分类数据
             List<TrialDeviceClassification> deviceClassificationList = trialDeviceClassificationMapper.selectList(Wrappers.<TrialDeviceClassification>query().lambda().eq(TrialDeviceClassification::getContractId, contractId));
             //获取当前试验树
-            List<WbsTreePrivate> wbsTreePrivates = baseMapper.selectTrialTreeAll(projectId, 2);
+            List<WbsTreePrivate> wbsTreePrivates = baseMapper.selectTrialTreeAll(String.valueOf(projectId), 2);
 
             //删除旧PDF
             List<String> pdfUrls = pdfData.stream().map(TrialDeviceUse::getPdfUrl).distinct().collect(Collectors.toList());
@@ -208,31 +227,40 @@ public class TrialDeviceUseServiceImpl extends BaseServiceImpl<TrialDeviceUseMap
             document.add(tableTitle);
             document.add(new Paragraph("\n"));
 
-            String[] array = {"序号", "设备名称", "设备分类", "设备编号", "设备型号", "出厂编号", "使用日期(起)", "使用日期(止)",
-                    "检测试验项目", "样品编号", "样品名称", "使用人", "备注"};
+            String[] array = {"序号", "设备名称", "设备分类", "设备编号", "设备型号", "出厂编号", "使用日期(起)", "使用日期(止)", "检测试验项目", "样品编号", "样品名称", "使用人", "备注"};
             for (String s : array) {
                 PDFUtil.createTableCell(s, textFont, table, lineHeight, colSpan);
             }
             for (TrialDeviceUse pdfDatum : pdfData) {
                 PDFUtil.createTableCell(String.valueOf(pdfDatum.getId()), textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(pdfDatum.getDeviceName(), textFont, table, lineHeight, colSpan);
+
+                String className = "";
                 for (TrialDeviceClassification classification : deviceClassificationList) {
                     if (classification.getId().equals(pdfDatum.getDeviceClassId())) {
-                        PDFUtil.createTableCell(classification.getClassName(), textFont, table, lineHeight, colSpan);
+                        className = classification.getClassName();
                         break;
                     }
                 }
+                PDFUtil.createTableCell(className, textFont, table, lineHeight, colSpan);
+
+
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getDeviceNumber()) ? pdfDatum.getDeviceNumber() : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getDeviceModel()) ? pdfDatum.getDeviceModel() : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getFactoryNumber()) ? pdfDatum.getFactoryNumber() : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getStartDate()) ? pdfDatum.getStartDate().toString() : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getEndDate()) ? pdfDatum.getEndDate().toString() : "", textFont, table, lineHeight, colSpan);
+
+                String nodeName = "";
                 for (WbsTreePrivate wbsTreePrivate : wbsTreePrivates) {
                     if (pdfDatum.getNodeId().equals(wbsTreePrivate.getPKeyId())) {
-                        PDFUtil.createTableCell(wbsTreePrivate.getNodeName(), textFont, table, lineHeight, colSpan);
+                        nodeName = wbsTreePrivate.getNodeName();
                         break;
                     }
                 }
+                PDFUtil.createTableCell(nodeName, textFont, table, lineHeight, colSpan);
+
+
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getSpecificationNumber()) ? pdfDatum.getSpecificationNumber() : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getMaterialName()) ? pdfDatum.getMaterialName() : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getManagerName()) ? pdfDatum.getManagerName() : "", textFont, table, lineHeight, colSpan);
@@ -280,7 +308,9 @@ public class TrialDeviceUseServiceImpl extends BaseServiceImpl<TrialDeviceUseMap
     @Override
     public boolean importBatchDeviceUse(List<TrialDeviceUseExcel> list, Long projectId, Long contractId) {
         //获取当前合同段的设备分类
-        List<TrialDeviceClassification> deviceClassifications = trialDeviceClassificationMapper.selectList(Wrappers.<TrialDeviceClassification>query().lambda().eq(TrialDeviceClassification::getContractId, contractId));
+        List<TrialDeviceClassification> deviceClassifications = trialDeviceClassificationMapper.selectList(Wrappers.<TrialDeviceClassification>query().lambda()
+                .select(TrialDeviceClassification::getId, TrialDeviceClassification::getClassName)
+                .eq(TrialDeviceClassification::getContractId, contractId));
         //获取当前项目试验树
         List<WbsTreePrivate> wbsTreePrivates = baseMapper.selectTrialTreeAll(String.valueOf(projectId), 2);
 
@@ -300,7 +330,7 @@ public class TrialDeviceUseServiceImpl extends BaseServiceImpl<TrialDeviceUseMap
             for (WbsTreePrivate wbsTreePrivate : wbsTreePrivates) {
                 if (trialDeviceUseExcel.getNodeName().equals(wbsTreePrivate.getNodeName())) {
                     if (trialDeviceUse != null) {
-                        trialDeviceUse.setNodeId(wbsTreePrivate.getId());
+                        trialDeviceUse.setNodeId(wbsTreePrivate.getPKeyId());
                         break;
                     }
                 }
@@ -310,6 +340,35 @@ public class TrialDeviceUseServiceImpl extends BaseServiceImpl<TrialDeviceUseMap
         return this.saveBatch(listData, 1000);
     }
 
+    @Override
+    public Map<String, String> useSubmitGetSampleInfo(String primaryKeyId) {
+        //获取所有试验记录
+        List<TrialSelfInspectionRecord> trialSelfInspectionRecords = jdbcTemplate.query("select id from u_trial_self_inspection_record where node_id = " + primaryKeyId, new BeanPropertyRowMapper<>(TrialSelfInspectionRecord.class));
+
+        //获取当前节点下所有试验记录下的关联的所有样品信息
+        if (trialSelfInspectionRecords.size() > 0) {
+            List<Long> ids = trialSelfInspectionRecords.stream().map(TrialSelfInspectionRecord::getId).collect(Collectors.toList());
+            if (ids.size() > 0) {
+                List<TrialSelfSample> query = jdbcTemplate.query("select sampling_id from u_trial_self_sample where self_id in(" + StringUtils.join(ids, ",") + ")", new BeanPropertyRowMapper<>(TrialSelfSample.class));
+                List<Long> collect = query.stream().map(TrialSelfSample::getSamplingId).collect(Collectors.toList());
+                if (collect.size() > 0) {
+                    List<TrialSampleInfo> trialSampleInfos = trialSampleInfoService.getBaseMapper().selectList(Wrappers.<TrialSampleInfo>lambdaQuery()
+                            .select(TrialSampleInfo::getSpecificationNumber, TrialSampleInfo::getMaterialName)
+                            .in(TrialSampleInfo::getId, collect));
+                    Map<String, String> map = new HashMap<>();
+                    if (trialSampleInfos.size() > 0) {
+                        List<String> names = trialSampleInfos.stream().map(TrialSampleInfo::getMaterialName).collect(Collectors.toList());
+                        List<String> numbers = trialSampleInfos.stream().map(TrialSampleInfo::getSpecificationNumber).collect(Collectors.toList());
+                        map.put("sampleNames", StringUtils.join(names, "、"));
+                        map.put("sampleNumbers", StringUtils.join(numbers, "、"));
+                        return map;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
     @Async
     public void addDeviceUseInfo(TrialSelfInspectionRecordDTO dto) {
         if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(dto.getDeviceUseIds())) {

+ 1 - 1
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialLaboratoryUserArchivesServiceImpl.java

@@ -71,7 +71,7 @@ public class TrialLaboratoryUserArchivesServiceImpl
         if (StringUtils.isNotEmpty(pageVO.getQueryValue())) {
             queryWrapper.lambda().like(TrialLaboratoryUserArchives::getName, pageVO.getQueryValue());
         }
-        IPage<TrialLaboratoryUserArchives> pages = this.page(page, queryWrapper.lambda().orderBy(true, true, TrialLaboratoryUserArchives::getCreateTime));
+        IPage<TrialLaboratoryUserArchives> pages = this.page(page, queryWrapper.lambda().orderBy(true, false, TrialLaboratoryUserArchives::getCreateTime));
         IPage<TrialLaboratoryUserArchivesPageVO> archivesPageVOIPage = TrialLaboratoryUserArchivesWarpper.build().pageVO(pages);
         List<TrialLaboratoryUserArchivesPageVO> records = archivesPageVOIPage.getRecords();
 

+ 70 - 13
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialMaterialMobilizationServiceImpl.java

@@ -42,10 +42,16 @@ 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.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.stereotype.Service;
 
 import javax.servlet.http.HttpServletResponse;
 import java.io.*;
+import java.math.BigDecimal;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -58,6 +64,7 @@ public class TrialMaterialMobilizationServiceImpl extends BaseServiceImpl<TrialM
     private final TrialSampleInfoMapper trialSampleInfoMapper;
     private final TrialSamplingRecordMapper trialSamplingRecordMapper;
     private final NewIOSSClient newIOSSClient;
+    private final JdbcTemplate jdbcTemplate;
 
     @Override
     public boolean mobilizationVerification(String number, String id) {
@@ -97,6 +104,11 @@ public class TrialMaterialMobilizationServiceImpl extends BaseServiceImpl<TrialM
         }
         List<TrialMaterialMobilization> list = new ArrayList<>();
         for (TrialMaterialMobilizationDTO trialMaterialMobilizationDTO : dto) {
+            List<TrialMaterialMobilization> query = jdbcTemplate.query("select id,material_name from u_trial_material_mobilization where material_number = '" + trialMaterialMobilizationDTO.getMaterialNumber() + "'", new BeanPropertyRowMapper<>(TrialMaterialMobilization.class));
+            if (query.size() > 0) {
+                TrialMaterialMobilization trialMaterialMobilization = query.stream().findAny().orElse(null);
+                throw new ServiceException("材料【" + trialMaterialMobilization.getMaterialName() + "】的编号重复,请重新填写");
+            }
             trialMaterialMobilizationDTO.setId(SnowFlakeUtil.getId());
             list.add(trialMaterialMobilizationDTO);
         }
@@ -145,9 +157,24 @@ public class TrialMaterialMobilizationServiceImpl extends BaseServiceImpl<TrialM
         if (ObjectUtil.isEmpty(SecureUtil.getUserId())) {
             throw new ServiceException("获取用户信息失败");
         }
+
+        //材料类型
+        List<Dict> materialTypes = iDictClient.getList("material_type").getData();
+
         data.forEach(excel -> {
             TrialMaterialMobilization trialMaterialMobilization = BeanUtil.copyProperties(excel, TrialMaterialMobilization.class);
-            if (trialMaterialMobilization != null){
+            if (trialMaterialMobilization != null) {
+                List<TrialMaterialMobilization> query = jdbcTemplate.query("select id,material_name from u_trial_material_mobilization where material_number = '" + trialMaterialMobilization.getMaterialNumber() + "'", new BeanPropertyRowMapper<>(TrialMaterialMobilization.class));
+                if (query.size() > 0) {
+                    TrialMaterialMobilization obj = query.stream().findAny().orElse(null);
+                    throw new ServiceException("材料【" + obj.getMaterialName() + "】的编号重复,导入失败");
+                }
+                for (Dict materialType : materialTypes) {
+                    if (excel.getMaterialType().equals(materialType.getDictValue())) {
+                        trialMaterialMobilization.setMaterialType(Integer.parseInt(materialType.getDictKey()));
+                        break;
+                    }
+                }
                 trialMaterialMobilization.setUserId(SecureUtil.getUserId());
                 trialMaterialMobilization.setContractId(contractId);
                 list.add(trialMaterialMobilization);
@@ -170,13 +197,7 @@ public class TrialMaterialMobilizationServiceImpl extends BaseServiceImpl<TrialM
             //构造数据
             List<TrialMaterialMobilization> list = baseMapper.selectBatchIds(Func.toLongList(ids)).stream()
                     .sorted(Comparator.comparing(TrialMaterialMobilization::getMobilizationDate, Comparator.nullsLast(Date::compareTo))).collect(Collectors.toList());
-            List<TrialMaterialMobilizationVO> pdfData = BeanUtil.copyProperties(list, TrialMaterialMobilizationVO.class);
-
-            //材料类型
-            R<List<Dict>> typeList = iDictClient.getList("material_type");
-
-            //获取所有用户信息
-            List<User> userList = iUserClient.selectUserAll();
+            //List<TrialMaterialMobilization> list = new ArrayList<>(baseMapper.selectBatchIds(Func.toLongList(ids)));
 
             //删除旧PDF
             List<String> pdfUrls = list.stream().map(TrialMaterialMobilization::getPdfUrl).distinct().collect(Collectors.toList());
@@ -255,22 +276,31 @@ public class TrialMaterialMobilizationServiceImpl extends BaseServiceImpl<TrialM
             document.add(tableTitle);
             document.add(new Paragraph("\n"));
 
-            String[] array = {"材料编号", "进场日期", "材料名称", "材料类型", "规格型号", "供应商单位", "材料单价", "材料数量",
-                    "计算单位", "生产批号", "上产地/厂家", "拟用部位", "记录人"};
+            String[] array = {"材料编号", "进场日期", "材料名称", "材料类型", "规格型号", "供应商单位", "材料单价", "材料数量", "计算单位", "生产批号", "上产地/厂家", "拟用部位", "记录人"};
             for (String s : array) {
                 PDFUtil.createTableCell(s, textFont, table, lineHeight, colSpan);
             }
-            for (TrialMaterialMobilizationVO pdfDatum : pdfData) {
+
+            //材料类型
+            R<List<Dict>> typeList = iDictClient.getList("material_type");
+
+            //获取所有用户信息
+            List<User> userList = iUserClient.selectUserAll();
+
+            for (TrialMaterialMobilization pdfDatum : list) {
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getMaterialNumber()) ? pdfDatum.getMaterialNumber() : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getMobilizationDate()) ? DateUtil.formatDate(pdfDatum.getMobilizationDate()) : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getMaterialName()) ? pdfDatum.getMaterialName() : "", textFont, table, lineHeight, colSpan);
 
+                String materialTypeName = "";
                 for (Dict type : typeList.getData()) {
                     if (type.getDictKey().equals(pdfDatum.getMaterialType().toString())) {
-                        PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getMaterialType()) ? pdfDatum.getMaterialType().toString() : type.getDictValue(), textFont, table, lineHeight, colSpan);
+                        materialTypeName = type.getDictValue();
                         break;
                     }
                 }
+                PDFUtil.createTableCell(materialTypeName, textFont, table, lineHeight, colSpan);
+
 
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getSpecificationModel()) ? pdfDatum.getSpecificationModel() : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getSupplierUnit()) ? pdfDatum.getSupplierUnit() : "", textFont, table, lineHeight, colSpan);
@@ -280,12 +310,16 @@ public class TrialMaterialMobilizationServiceImpl extends BaseServiceImpl<TrialM
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getBatchNumber()) ? pdfDatum.getBatchNumber() : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getPlaceOfProduction()) ? pdfDatum.getPlaceOfProduction() : "", textFont, table, lineHeight, colSpan);
                 PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getProposedPosition()) ? pdfDatum.getProposedPosition() : "", textFont, table, lineHeight, colSpan);
+
+                String userName = "";
                 for (User user : userList) {
                     if (pdfDatum.getUserId().equals(user.getId())) {
-                        PDFUtil.createTableCell(ObjectUtil.isNotEmpty(pdfDatum.getUserName()) ? pdfDatum.getUserName() : user.getName(), textFont, table, lineHeight, colSpan);
+                        userName = user.getName();
                         break;
                     }
                 }
+                PDFUtil.createTableCell(userName, textFont, table, lineHeight, colSpan);
+
             }
 
             document.add(table);
@@ -353,5 +387,28 @@ public class TrialMaterialMobilizationServiceImpl extends BaseServiceImpl<TrialM
         return list;
     }
 
+    @Override
+    public boolean uploadFile(String id, Integer type, String url) {
+        if (type == 1) {
+            this.update(Wrappers.<TrialMaterialMobilization>lambdaUpdate()
+                    .set(TrialMaterialMobilization::getProductionCertificate, url)
+                    .eq(TrialMaterialMobilization::getId, id));
+            return true;
+        }
+        if (type == 2) {
+            this.update(Wrappers.<TrialMaterialMobilization>lambdaUpdate()
+                    .set(TrialMaterialMobilization::getQualityInspectionReport, url)
+                    .eq(TrialMaterialMobilization::getId, id));
+            return true;
+        }
+        if (type == 3) {
+            this.update(Wrappers.<TrialMaterialMobilization>lambdaUpdate()
+                    .set(TrialMaterialMobilization::getOtherAccessories, url)
+                    .eq(TrialMaterialMobilization::getId, id));
+            return true;
+        }
+        return false;
+    }
+
 
 }

+ 53 - 18
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialSampleInfoServiceImpl.java

@@ -2,6 +2,7 @@ package org.springblade.business.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.lowagie.text.Document;
 import com.lowagie.text.DocumentException;
@@ -38,6 +39,8 @@ import org.springblade.core.tool.utils.*;
 import org.springblade.resource.feign.NewIOSSClient;
 import org.springblade.system.user.entity.User;
 import org.springblade.system.user.feign.IUserClient;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -57,6 +60,7 @@ public class TrialSampleInfoServiceImpl extends BaseServiceImpl<TrialSampleInfoM
     private final IUserClient iUserClient;
     private final NewIOSSClient newIOSSClient;
     private final TrialSamplingRecordMapper trialSamplingRecordMapper;
+    private final JdbcTemplate jdbcTemplate;
 
     @Override
     public boolean sampleVerification(String specificationNumber, String id) {
@@ -128,20 +132,29 @@ public class TrialSampleInfoServiceImpl extends BaseServiceImpl<TrialSampleInfoM
                     .or().like(TrialSampleInfo::getSpecificationModel, obj.getQueryValue())
                     .or().like(TrialSampleInfo::getSpecificationNumber, obj.getQueryValue()));
         }
-        IPage<TrialSampleInfo> pages = this.page(page, queryWrapper.lambda().orderBy(true, true, TrialSampleInfo::getCreateTime));
+        IPage<TrialSampleInfo> pages = this.page(page, queryWrapper.lambda().orderBy(true, false, TrialSampleInfo::getCreateTime));
         IPage<TrialSampleInfoVO> trialMaterialMobilizationVOIPage = TrialSampleInfoWarpper.build().pageVO(pages);
         List<TrialSampleInfoVO> records = trialMaterialMobilizationVOIPage.getRecords();
         List<TrialSamplingRecord> list = trialSamplingRecordMapper.selectAll();
         List<User> userList = iUserClient.selectUserAll();
         for (TrialSampleInfoVO record : records) {
+            if (ObjectUtils.isEmpty(record.getMaterialCount())) {
+                record.setMaterialCount(0);
+            }
+            if (ObjectUtils.isEmpty(record.getRepresentativeCount())) {
+                record.setRepresentativeCount(0);
+            }
+
             for (User user : userList) {
                 if (record.getUserId().equals(user.getId())) {
                     record.setUserName(user.getName());
+                    break;
                 }
             }
             for (TrialSamplingRecord trialSamplingRecord : list) {
                 if (record.getId().equals(trialSamplingRecord.getSampleInfoId())) {
                     record.setMobilizationId(trialSamplingRecord.getMobilizationId());
+                    break;
                 }
             }
         }
@@ -150,29 +163,32 @@ public class TrialSampleInfoServiceImpl extends BaseServiceImpl<TrialSampleInfoM
 
     @Override
     public boolean sampleSubmit(TrialSampleInfoDTO obj) {
-        if (ObjectUtil.isEmpty(SecureUtil.getUserId())) {
+        /*if (ObjectUtil.isEmpty(SecureUtil.getUserId())) {
             throw new ServiceException("获取用户信息失败");
         }
-        obj.setUserId(SecureUtil.getUserId());
+        obj.setUserId(SecureUtil.getUserId());*/
+
         //如果样品编号为空,那么就自动生成
         if (ObjectUtil.isEmpty(obj.getSpecificationNumber())) {
             this.buildNumber(obj);
         }
 
-        this.saveOrUpdate(obj);
+        TrialSampleInfo trialSampleInfo = BeanUtil.copyProperties(obj, TrialSampleInfo.class);
+        if (trialSampleInfo != null) {
+            if (ObjectUtils.isEmpty(trialSampleInfo.getMaterialCount())) {
+                trialSampleInfo.setMaterialCount(0);
+            }
+            if (ObjectUtils.isEmpty(trialSampleInfo.getRepresentativeCount())) {
+                trialSampleInfo.setRepresentativeCount(0);
+            }
+            this.saveOrUpdate(trialSampleInfo);
 
-        //关联样品取样信息
-        if (obj.getId() != null && obj.getMobilizationId() != null) {
-            //获取当前选择的样品信息
-            TrialSamplingRecord trialSamplingRecord = trialSamplingRecordMapper.selectByMobilizationIdAndSampleInfoId(obj.getMobilizationId(), obj.getId());
-            if (trialSamplingRecord != null) {
-                //存在不新增
-                return true;
-            } else {
-                //删除旧记录
-                trialSamplingRecordMapper.deleteBySampleInfoId(obj.getId());
-                //新增记录
-                trialSamplingRecordMapper.insertRecord(SnowFlakeUtil.getId(), obj.getMobilizationId(), obj.getId());
+            if (obj.getId() != null && obj.getMobilizationId() != null && obj.getMobilizationId() != -1) {
+                TrialSamplingRecord trialSamplingRecord = trialSamplingRecordMapper.selectByMobilizationIdAndSampleInfoId(obj.getMobilizationId(), obj.getId());
+                if (trialSamplingRecord == null) {
+                    trialSamplingRecordMapper.deleteBySampleInfoId(obj.getId());
+                    trialSamplingRecordMapper.insertRecord(SnowFlakeUtil.getId(), obj.getMobilizationId(), obj.getId());
+                }
             }
         }
         return true;
@@ -181,7 +197,11 @@ public class TrialSampleInfoServiceImpl extends BaseServiceImpl<TrialSampleInfoM
     private void buildNumber(TrialSampleInfoDTO obj) {
         StringSPUtils spUtils = new StringSPUtils();
         //获取当前合同段节点下所有样品信息
-        List<TrialSampleInfo> trialSampleInfos = baseMapper.selectList(Wrappers.<TrialSampleInfo>lambdaQuery().eq(TrialSampleInfo::getContractId, obj.getContractId()).eq(TrialSampleInfo::getNodeId, obj.getNodeId()));
+        List<TrialSampleInfo> trialSampleInfos = baseMapper.selectList(Wrappers.<TrialSampleInfo>lambdaQuery()
+                .select(TrialSampleInfo::getSpecificationNumber)
+                .isNotNull(TrialSampleInfo::getSpecificationNumber)
+                .eq(TrialSampleInfo::getContractId, obj.getContractId())
+                .eq(TrialSampleInfo::getNodeId, obj.getNodeId()));
         //获取记录表最大编号
         List<String> recordNosOld = trialSampleInfos.stream().map(TrialSampleInfo::getSpecificationNumber).collect(Collectors.toList());
 
@@ -226,6 +246,11 @@ public class TrialSampleInfoServiceImpl extends BaseServiceImpl<TrialSampleInfoM
         }
         List<TrialSampleInfo> list = new ArrayList<>();
         for (TrialSampleInfoDTO trialSampleInfoDTO : dto) {
+            List<TrialSampleInfo> query = jdbcTemplate.query("select id,material_name from u_trial_sample_info where specification_number = '" + trialSampleInfoDTO.getSpecificationNumber() + "'", new BeanPropertyRowMapper<>(TrialSampleInfo.class));
+            if (query.size() > 0) {
+                TrialSampleInfo trialSampleInfo = query.stream().findAny().orElse(null);
+                throw new ServiceException("材料【" + trialSampleInfo.getMaterialName() + "】的编号重复,请重新填写");
+            }
             trialSampleInfoDTO.setId(SnowFlakeUtil.getId());
             list.add(trialSampleInfoDTO);
         }
@@ -241,6 +266,16 @@ public class TrialSampleInfoServiceImpl extends BaseServiceImpl<TrialSampleInfoM
         data.forEach(excel -> {
             TrialSampleInfo trialSampleInfo = BeanUtil.copyProperties(excel, TrialSampleInfo.class);
             if (trialSampleInfo != null) {
+                List<TrialSampleInfo> query = jdbcTemplate.query("select id,material_name from u_trial_sample_info where specification_number = '" + trialSampleInfo.getSpecificationNumber() + "'", new BeanPropertyRowMapper<>(TrialSampleInfo.class));
+                if (query.size() > 0) {
+                    TrialSampleInfo obj = query.stream().findAny().orElse(null);
+                    throw new ServiceException("材料【" + obj.getMaterialName() + "】的编号重复,请重新填写后导入");
+                }
+                if ("是".equals(excel.getIsOutsourcing())) {
+                    trialSampleInfo.setIsOutsourcing(1);
+                } else {
+                    trialSampleInfo.setIsOutsourcing(0);
+                }
                 trialSampleInfo.setUserId(SecureUtil.getUserId());
                 trialSampleInfo.setContractId(contractId);
                 trialSampleInfo.setNodeId(nodeId);
@@ -282,7 +317,7 @@ public class TrialSampleInfoServiceImpl extends BaseServiceImpl<TrialSampleInfoM
                 for (User user : userList) {
                     if (trialSampleInfo.getUserId().equals(user.getId())) {
                         TrialSampleInfoVO trialSampleInfoVO = BeanUtil.copyProperties(trialSampleInfo, TrialSampleInfoVO.class);
-                        if (trialSampleInfoVO != null){
+                        if (trialSampleInfoVO != null) {
                             trialSampleInfoVO.setUserName(user.getName());
                             pdfData.add(trialSampleInfoVO);
                         }

+ 77 - 66
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialSelfInspectionRecordServiceImpl.java

@@ -593,58 +593,64 @@ public class TrialSelfInspectionRecordServiceImpl extends BaseServiceImpl<TrialS
         if (ObjectUtil.isNotEmpty(obj.getParallelProcessInstanceId())) {
             String sql = "select process_instance_id from u_task_parallel where parallel_process_instance_id = '" + obj.getParallelProcessInstanceId() + "'";
             TaskParallel taskParallel = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(TaskParallel.class)).stream().findAny().orElse(null);
-            if (taskParallel != null && ObjectUtil.isNotEmpty(taskParallel.getProcessInstanceId()) && (new Integer(1).equals(taskParallel.getEVisaStatus()))) {
-                String trialSelfInspectionRecordId = baseMapper.selectTaskByTaskId(taskParallel.getProcessInstanceId());
-                if (StringUtils.isNotEmpty(trialSelfInspectionRecordId)) {
-                    this.update(Wrappers.<TrialSelfInspectionRecord>lambdaUpdate()
-                            .set(TrialSelfInspectionRecord::getTaskStatus, "已审批")
-                            .set(TrialSelfInspectionRecord::getPdfUrl, pdfUrlEVisa) //pdfUrlEVisa=电签后的pdf
-                            .eq(TrialSelfInspectionRecord::getId, trialSelfInspectionRecordId)
-                    );
-
-                    TrialSelfInspectionRecord record = baseMapper.selectById(trialSelfInspectionRecordId);
-                    //此时的record.getPdfUrl()为电签后的pdf信息
-                    if (("已审批").equals(record.getTaskStatus()) && (new Integer(1)).equals(record.getDetectionResult()) && (new Integer(1)).equals(record.getDetectionCategory())) {
-                        /**
-                         * 在资料填报工序-预览全部pdf时再拼接合并显示,当前只做储存(如果当前资料填报工序节点有其他多个试验记录pdf关联信息,那么合并存储,否则直接存储)
-                         */
-                        if (StringUtils.isNotEmpty(record.getProjectPosition())) {
-                            //有pdf的节点
-                            String sqlNodeAll = "select wbs_id from u_information_query where wbs_id in(" + record.getProjectPosition() + ") and contract_id = " + record.getContractId();
-                            List<Long> collect = jdbcTemplate.query(sqlNodeAll, new BeanPropertyRowMapper<>(InformationQuery.class)).stream().map(InformationQuery::getWbsId).collect(Collectors.toList());
-                            if (collect.size() > 0) {
-                                //删除当前记录关联记录
-                                baseMapper.delSelfQuality(record.getId());
-                                for (Long pKeyId : collect) {
-                                    //新增当前记录关联信息
-                                    baseMapper.saveSelfQuality(SnowFlakeUtil.getId(), record.getId(), pKeyId);
-
-                                    //获取当前工程部位节点最新的关联试验记录ids
-                                    List<String> trialRecordIds = baseMapper.selectTrialIdByNodeId(pKeyId);
-
-                                    //如果当前工程部位节点的关联试验记录id只有一条,且等于当前关联试验记录id,那么不合并,直接存储该条试验记录的pdf
-                                    if (trialRecordIds.size() == 1 && trialRecordIds.get(0).equals(record.getId().toString())) {
-                                        //修改当前试验pdf到质检树节点的pdf_trial_url_position上存储
-                                        baseMapper.updateInformationQuery(pKeyId, record.getContractId(), record.getPdfUrl());
-                                        continue;
-                                    }
+            if (taskParallel != null && ObjectUtil.isNotEmpty(taskParallel.getProcessInstanceId())) {
+                //获取当前任务的状态为以已审批status=2,再修改试验状态以及关联的pdf
+                Task task = jdbcTemplate.query("select status from u_task where process_instance_id = '" + taskParallel.getProcessInstanceId() + "'", new BeanPropertyRowMapper<>(Task.class)).stream().findAny().orElse(null);
+                if (ObjectUtils.isNotEmpty(task) && new Integer(2).equals(task.getStatus())) {
 
-                                    //如果当前工程部位节点的关联试验记录id有多条,那么合并
-                                    List<TrialSelfInspectionRecord> pdfUrlList = baseMapper.selectList(Wrappers.<TrialSelfInspectionRecord>lambdaQuery().select(TrialSelfInspectionRecord::getPdfUrl).in(TrialSelfInspectionRecord::getId, trialRecordIds));
-                                    List<String> pdfS = pdfUrlList.stream().filter(f -> StringUtils.isNotEmpty(f.getPdfUrl())).map(TrialSelfInspectionRecord::getPdfUrl).collect(Collectors.toList());
+                    //试验状态
+                    String trialSelfInspectionRecordId = baseMapper.selectTaskByTaskId(taskParallel.getProcessInstanceId());
+                    if (StringUtils.isNotEmpty(trialSelfInspectionRecordId)) {
+                        this.update(Wrappers.<TrialSelfInspectionRecord>lambdaUpdate()
+                                .set(TrialSelfInspectionRecord::getTaskStatus, "已审批")
+                                .set(TrialSelfInspectionRecord::getPdfUrl, pdfUrlEVisa) //pdfUrlEVisa=电签后的pdf
+                                .eq(TrialSelfInspectionRecord::getId, trialSelfInspectionRecordId)
+                        );
 
-                                    String filePath = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
-                                    String listPdf = filePath + "/pdf/" + pKeyId + ".pdf";
-                                    File tabPDF = ResourceUtil.getFile(listPdf);
-                                    if (tabPDF.exists()) {
-                                        tabPDF.delete();
-                                    }
+                        TrialSelfInspectionRecord record = baseMapper.selectById(trialSelfInspectionRecordId);
 
-                                    FileUtils.mergePdfPublicMethods(pdfS, listPdf);
-                                    BladeFile bladeFile = this.newIOSSClient.uploadFile(pKeyId + ".pdf", listPdf);
-                                    if (bladeFile != null) {
-                                        //修改合并的试验pdf到质检树节点的pdf_trial_url_position上存储
-                                        baseMapper.updateInformationQuery(pKeyId, record.getContractId(), bladeFile.getLink());
+                        /**
+                         * 在资料填报工序-预览全部pdf时再拼接合并显示,当前只做储存(如果当前资料填报工序节点有其他多个试验记录pdf关联信息,那么合并存储,否则直接存储)
+                         */
+                        if (("已审批").equals(record.getTaskStatus()) && (new Integer(1)).equals(record.getDetectionResult()) && (new Integer(1)).equals(record.getDetectionCategory())) {
+                            if (StringUtils.isNotEmpty(record.getProjectPosition())) {
+                                //有pdf的节点
+                                String sqlNodeAll = "select wbs_id from u_information_query where wbs_id in(" + record.getProjectPosition() + ") and contract_id = " + record.getContractId();
+                                List<Long> collect = jdbcTemplate.query(sqlNodeAll, new BeanPropertyRowMapper<>(InformationQuery.class)).stream().map(InformationQuery::getWbsId).collect(Collectors.toList());
+                                if (collect.size() > 0) {
+                                    //删除当前记录关联记录
+                                    baseMapper.delSelfQuality(record.getId());
+                                    for (Long pKeyId : collect) {
+                                        //新增当前记录关联信息
+                                        baseMapper.saveSelfQuality(SnowFlakeUtil.getId(), record.getId(), pKeyId);
+
+                                        //获取当前工程部位节点最新的关联试验记录ids
+                                        List<String> trialRecordIds = baseMapper.selectTrialIdByNodeId(pKeyId);
+
+                                        //如果当前工程部位节点的关联试验记录id只有一条,且等于当前关联试验记录id,那么不合并,直接存储该条试验记录的pdf
+                                        if (trialRecordIds.size() == 1 && trialRecordIds.get(0).equals(record.getId().toString())) {
+                                            //修改当前试验pdf到质检树节点的pdf_trial_url_position上存储
+                                            baseMapper.updateInformationQuery(pKeyId, record.getContractId(), record.getPdfUrl());
+                                            continue;
+                                        }
+
+                                        //如果当前工程部位节点的关联试验记录id有多条,那么合并
+                                        List<TrialSelfInspectionRecord> pdfUrlList = baseMapper.selectList(Wrappers.<TrialSelfInspectionRecord>lambdaQuery().select(TrialSelfInspectionRecord::getPdfUrl).in(TrialSelfInspectionRecord::getId, trialRecordIds));
+                                        List<String> pdfS = pdfUrlList.stream().filter(f -> StringUtils.isNotEmpty(f.getPdfUrl())).map(TrialSelfInspectionRecord::getPdfUrl).collect(Collectors.toList());
+
+                                        String filePath = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
+                                        String listPdf = filePath + "/pdf/" + pKeyId + ".pdf";
+                                        File tabPDF = ResourceUtil.getFile(listPdf);
+                                        if (tabPDF.exists()) {
+                                            tabPDF.delete();
+                                        }
+
+                                        FileUtils.mergePdfPublicMethods(pdfS, listPdf);
+                                        BladeFile bladeFile = this.newIOSSClient.uploadFile(pKeyId + ".pdf", listPdf);
+                                        if (bladeFile != null) {
+                                            //修改合并的试验pdf到质检树节点的pdf_trial_url_position上存储
+                                            baseMapper.updateInformationQuery(pKeyId, record.getContractId(), bladeFile.getLink());
+                                        }
                                     }
                                 }
                             }
@@ -656,19 +662,26 @@ public class TrialSelfInspectionRecordServiceImpl extends BaseServiceImpl<TrialS
     }
 
     @Override
+    @Async
     public void updateTrialSelfInspectionRecordStatusFC(TaskApprovalVO obj) {
         if (ObjectUtil.isNotEmpty(obj.getParallelProcessInstanceId())) {
             String sql = "select process_instance_id from u_task_parallel where parallel_process_instance_id = '" + obj.getParallelProcessInstanceId() + "'";
             TaskParallel taskParallel = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(TaskParallel.class)).stream().findAny().orElse(null);
             if (taskParallel != null && ObjectUtil.isNotEmpty(taskParallel.getProcessInstanceId())) {
-                String trialSelfInspectionRecordId = baseMapper.selectTaskByTaskId(taskParallel.getProcessInstanceId());
-                if (StringUtils.isNotEmpty(trialSelfInspectionRecordId)) {
-                    this.update(Wrappers.<TrialSelfInspectionRecord>lambdaUpdate()
-                            .set(TrialSelfInspectionRecord::getTaskStatus, "已废除")
-                            .eq(TrialSelfInspectionRecord::getId, trialSelfInspectionRecordId)
-                    );
-                    //废除后修改电签为null
-                    jdbcTemplate.execute("update u_information_query set e_visa_pdf_url = null where wbs_id = " + trialSelfInspectionRecordId);
+
+                //获取当前任务的状态为已废除status=3,再修改试验状态
+                Task task = jdbcTemplate.query("select status from u_task where process_instance_id = '" + taskParallel.getProcessInstanceId() + "'", new BeanPropertyRowMapper<>(Task.class)).stream().findAny().orElse(null);
+                if (ObjectUtils.isNotEmpty(task) && new Integer(3).equals(task.getStatus())) {
+
+                    String trialSelfInspectionRecordId = baseMapper.selectTaskByTaskId(taskParallel.getProcessInstanceId());
+                    if (StringUtils.isNotEmpty(trialSelfInspectionRecordId)) {
+                        this.update(Wrappers.<TrialSelfInspectionRecord>lambdaUpdate()
+                                .set(TrialSelfInspectionRecord::getTaskStatus, "已废除")
+                                .eq(TrialSelfInspectionRecord::getId, trialSelfInspectionRecordId)
+                        );
+                        //废除后修改电签为null
+                        jdbcTemplate.execute("update u_information_query set e_visa_pdf_url = null where wbs_id = " + trialSelfInspectionRecordId);
+                    }
                 }
             }
         }
@@ -882,6 +895,7 @@ public class TrialSelfInspectionRecordServiceImpl extends BaseServiceImpl<TrialS
     }
 
     @Async
+    @Transactional(rollbackFor = Exception.class)
     public boolean recordSampleSubmit(TrialSelfInspectionRecordDTO dto1, TrialSelfInspectionRecord obj) {
         RecordSampleSubmitDTO dto = new RecordSampleSubmitDTO();
         dto.setId(obj.getId());
@@ -899,37 +913,34 @@ public class TrialSelfInspectionRecordServiceImpl extends BaseServiceImpl<TrialS
             }
 
             //取样信息
-            List<TrialSampleInfo> trialSampleInfos = trialSampleInfoMapper.selectList(Wrappers.<TrialSampleInfo>lambdaQuery().in(TrialSampleInfo::getId, ids));
+            List<TrialSampleInfo> trialSampleInfos = trialSampleInfoMapper.selectList(Wrappers.<TrialSampleInfo>lambdaQuery()
+                    .isNotNull(TrialSampleInfo::getSamplingLocation)
+                    .isNotNull(TrialSampleInfo::getSupplierUnit)
+                    .isNotNull(TrialSampleInfo::getSpecificationNumber)
+                    .isNotNull(TrialSampleInfo::getSpecificationModel)
+                    .in(TrialSampleInfo::getId, ids));
             List<String> samplingLocations = trialSampleInfos.stream().map(TrialSampleInfo::getSamplingLocation).collect(Collectors.toList());
             String samplingLocation = samplingLocations.stream().findAny().orElse(null);
             if (samplingLocations.size() > 1 && StringUtils.isNotEmpty(samplingLocation)) {
                 samplingLocation = samplingLocation + "等" + samplingLocations.size() + "个取样地点";
-            } else if (StringUtils.isEmpty(samplingLocation)) {
-                samplingLocation = "取样地点为空";
             }
 
             List<String> supplierUnits = trialSampleInfos.stream().map(TrialSampleInfo::getSupplierUnit).collect(Collectors.toList());
             String supplierUnit = supplierUnits.stream().findAny().orElse(null);
             if (supplierUnits.size() > 1 && StringUtils.isNotEmpty(supplierUnit)) {
                 supplierUnit = supplierUnit + "等" + supplierUnits.size() + "个单位";
-            } else if (StringUtils.isEmpty(supplierUnit)) {
-                supplierUnit = "单位为空";
             }
 
             List<String> specificationNumbers = trialSampleInfos.stream().map(TrialSampleInfo::getSpecificationNumber).collect(Collectors.toList());
             String specificationNumber = supplierUnits.stream().findAny().orElse(null);
             if (specificationNumbers.size() > 1 && StringUtils.isNotEmpty(specificationNumber)) {
                 specificationNumber = specificationNumber + "等" + specificationNumbers.size() + "个样品编号";
-            } else if (StringUtils.isEmpty(specificationNumber)) {
-                specificationNumber = "样品编号为空";
             }
 
             List<String> specificationModels = trialSampleInfos.stream().map(TrialSampleInfo::getSpecificationModel).collect(Collectors.toList());
             String specificationModel = supplierUnits.stream().findAny().orElse(null);
             if (specificationModels.size() > 1 && StringUtils.isNotEmpty(specificationModel)) {
                 specificationModel = specificationModel + "等" + specificationModels.size() + "个规格类型";
-            } else if (StringUtils.isEmpty(specificationModel)) {
-                specificationModel = "规格类型为空";
             }
 
             //更新

+ 1228 - 0
blade-service/blade-business/src/main/java/org/springblade/business/utils/DateUtils.java

@@ -0,0 +1,1228 @@
+package org.springblade.business.utils;
+
+
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import lombok.extern.slf4j.Slf4j;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAdjusters;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author
+ * @version 1.0
+ * @description 日期工具类
+ */
+@Slf4j
+public class DateUtils {
+    private static Calendar calendar = Calendar.getInstance();
+    private static String PATTERN = "yyyy-MM-dd HH:mm:ss";
+//    static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+//    static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+    /**
+     * 一年时间的分钟数
+     */
+    public static final int ONE_YEAR_MINUTES = 52560000;
+
+    private final static String FORMAT = "yyyy-MM-dd HH:mm";
+
+    /**
+     * 时间戳转日期
+     *
+     * @param timestamp
+     * @return date
+     */
+    public static Date timestampToDate(long timestamp) {
+
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        String d = format.format(timestamp);
+        Date date = null;
+        try {
+            date = format.parse(d);
+        } catch (ParseException e) {
+            throw new RuntimeException(e);
+        }
+        return date;
+    }
+
+    /**
+     * 获取日期时间字符串
+     *
+     * @param date
+     * @return yyyy-MM-dd HH:mm:ss
+     */
+    public static String getTimeStr(Date date) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        return format.format(date);
+    }
+
+    public static String getTimeStr(LocalDateTime date) {
+        return date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+    }
+
+
+    public static String getTimeStr(Date date, String pattern) {
+        SimpleDateFormat format = new SimpleDateFormat(pattern);
+        return format.format(date);
+    }
+
+
+    /**
+     * 获取当天日期字符串
+     *
+     * @param date
+     * @return yyyy-MM-dd
+     */
+    public static String getDateStr(Date date) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
+        return format.format(date);
+    }
+
+    /**
+     * 字符串转日期
+     *
+     * @param timeStr
+     * @return
+     */
+    public static Date strToDate(String timeStr, String pattern) {
+        if (StringUtils.isEmpty(pattern)) {
+            pattern = PATTERN;
+        }
+        SimpleDateFormat format = new SimpleDateFormat(pattern);
+        try {
+            return format.parse(timeStr);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return new Date();
+    }
+
+
+    /**
+     * 获取指定日期的前一天
+     *
+     * @param currentDate
+     * @return
+     */
+    public static String getDateYesterday(String currentDate) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
+        try {
+            Date current = format.parse(currentDate);
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTime(current);
+            calendar.add(Calendar.DAY_OF_MONTH, -1);
+            Date yesterday = calendar.getTime();
+            return format.format(yesterday);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return currentDate;
+    }
+
+    /**
+     * 获取指定日期的前一天
+     *
+     * @param currentDate
+     * @return
+     */
+    public static String getDateYesterdays(String currentDate) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
+        try {
+            Date current = format.parse(currentDate);
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTime(current);
+            calendar.add(Calendar.DAY_OF_MONTH, 0);
+            Date yesterday = calendar.getTime();
+            return format.format(yesterday);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return currentDate;
+    }
+
+
+    /**
+     * 获取指定日期的前一天
+     *
+     * @param currentDate
+     * @return
+     */
+    public static String getDateYesterday(Date currentDate) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(currentDate);
+        calendar.add(Calendar.DAY_OF_MONTH, -1);
+        Date yesterday = calendar.getTime();
+        return format.format(yesterday);
+    }
+
+    /**
+     * 获取指定日期的后(正)/前(负)X天的时间
+     *
+     * @param currentDate
+     * @return
+     */
+    public static DateTime getDateAdd(Date currentDate, Integer add) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(currentDate);
+        calendar.add(Calendar.DAY_OF_MONTH, add);
+        return DateTime.of(calendar.getTime());
+    }
+
+
+    /**
+     * 获取两个日期的年份差
+     *
+     * @param date1
+     * @param date2
+     * @return
+     */
+    public static String getTwoDateYears(String date1, String date2) {
+        Calendar bef = null;
+        Calendar aft = null;
+        try {
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+            bef = Calendar.getInstance();
+            aft = Calendar.getInstance();
+            bef.setTime(sdf.parse(date1));
+            aft.setTime(sdf.parse(date2));
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        int surplus = aft.get(Calendar.DATE) - bef.get(Calendar.DATE);
+        int result = aft.get(Calendar.MONTH) - bef.get(Calendar.MONTH);
+        int year = aft.get(Calendar.YEAR) - bef.get(Calendar.YEAR);
+        if (result < 0) {
+            result = 1;
+        } else if (result == 0) {
+            result = surplus <= 0 ? 1 : 0;
+        } else {
+            result = 0;
+        }
+        return String.valueOf(year + result);
+    }
+
+    /**
+     * 获取日期的月和日,并用汉字表示
+     * 如2019-10-17 输出 10月17日
+     *
+     * @param dateString
+     * @return
+     */
+    public static String getChineseDateMonthAndDay(String dateString) {
+        //判断日期如果长度不符合,则返回错误null
+        if (dateString.length() != 10) {
+            return null;
+        }
+        //获取月
+        String dateMonth = dateString.substring(5, 7);
+        //获取日
+        String dateDay = dateString.substring(8, 10);
+        String chineseDate = dateMonth + "月" + dateDay + "日";
+        return chineseDate;
+    }
+
+    /**
+     * 获取日期的月和日,并用汉字表示
+     * 如2019-10-17 输出 2019年10月17日
+     *
+     * @param dateString
+     * @return
+     */
+    public static String getChineseDateYearAndMonthAndDay(String dateString) {
+        //判断日期如果长度不符合,则返回错误null
+        if (StringUtils.isEmpty(dateString) || dateString.length() != 10) {
+            return null;
+        }
+        //获取年
+        String year = dateString.substring(0, 4);
+        //获取月
+        String dateMonth = dateString.substring(5, 7);
+        //获取日
+        String dateDay = dateString.substring(8, 10);
+        String chineseDate = year + "年" + dateMonth + "月" + dateDay + "日";
+        return chineseDate;
+    }
+
+
+    /**
+     * 获取日期的月和日,并用汉字表示
+     * 如2019-10-17 输出 10月
+     *
+     * @param date
+     * @return
+     */
+    public static String getChineseDateMonth(Date date) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        String dateString = format.format(date);
+        //获取月
+        String dateMonth = dateString.substring(5, 7);
+        String chineseDate = dateMonth + "月";
+        return chineseDate;
+    }
+
+    /**
+     * 获取本年最后一天
+     *
+     * @return
+     */
+    public static String getYearEnd() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.MONTH, calendar.getActualMaximum(Calendar.MONTH));
+        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
+        Date currYearLast = calendar.getTime();
+        return new SimpleDateFormat("yyyy-MM-dd").format(currYearLast);
+    }
+
+    /**
+     * 获取指定年最后一天
+     *
+     * @return
+     */
+    public static Date getYearEnd(Date endDate) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(endDate);
+        calendar.set(Calendar.MONTH, calendar.getActualMaximum(Calendar.MONTH));
+        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
+        calendar.set(Calendar.HOUR_OF_DAY, 23);
+        calendar.set(Calendar.MINUTE, 59);
+        calendar.set(Calendar.SECOND, 59);
+        calendar.set(Calendar.MILLISECOND, 0);
+        return calendar.getTime();
+    }
+
+
+    /**
+     * 计算两个日期的间隔天数
+     *
+     * @param startTime
+     * @param endTime
+     * @return
+     */
+    public static int cacTwoDateDays(String startTime, String endTime) {
+        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
+        Date date1 = null;
+        Date date = null;
+        Long l = 0L;
+        try {
+            date = formatter.parse(startTime);
+            long ts = date.getTime();
+            date1 = formatter.parse(endTime);
+            long ts1 = date1.getTime();
+
+            l = (ts - ts1) / (1000 * 60 * 60 * 24);
+
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return l.intValue();
+    }
+
+    /**
+     * 计算两个日期的间隔小时数
+     *
+     * @param startTime
+     * @param endTime
+     * @return
+     */
+    public static int cacTwoDateHours(String startTime, String endTime) {
+        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH");
+        Date date1 = null;
+        Date date = null;
+        Long l = 0L;
+        try {
+            date = formatter.parse(startTime);
+            long ts = date.getTime();
+            date1 = formatter.parse(endTime);
+            long ts1 = date1.getTime();
+
+            l = (ts - ts1) / (1000 * 60 * 60);
+
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return l.intValue();
+    }
+
+    /**
+     * 获取下一个生日
+     *
+     * @param todayTime    当前日期
+     * @param birthdayTime 生日日期
+     * @return
+     */
+    public static String getNextBirthday(String todayTime, String birthdayTime) {
+        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
+        Date date1 = null;
+        Date date = null;
+        Long l = 0L;
+        try {
+            date = formatter.parse(todayTime);
+            long ts = date.getTime();
+            date1 = formatter.parse(birthdayTime);
+            long ts1 = date1.getTime();
+            //如果生日日期在当天日期之前,则生日变为明年
+            if (ts > ts1) {
+                Calendar calendar = Calendar.getInstance();
+                calendar.setTime(date1);
+                calendar.add(Calendar.YEAR, +1);
+                Date nextBirthday = calendar.getTime();
+                return getDateStr(nextBirthday);
+            }
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return birthdayTime;
+    }
+
+
+    /**
+     * 判断当前日期是星期几
+     *
+     * @param pTime 修要判断的时间
+     * @return dayForWeek 判断结果
+     * @Exception 发生异常
+     */
+    public static int dayForWeek(String pTime) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
+        try {
+            Calendar c = Calendar.getInstance();
+            c.setTime(format.parse(pTime));
+            int dayForWeek = 0;
+            if (c.get(Calendar.DAY_OF_WEEK) == 1) {
+                dayForWeek = 7;
+            } else {
+                dayForWeek = c.get(Calendar.DAY_OF_WEEK) - 1;
+            }
+            return dayForWeek;
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return 0;
+    }
+
+    public static String int2chineseNum(int src) {
+        final String num[] = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"};
+        final String unit[] = {"", "十", "百", "千", "万", "十", "百", "千", "亿", "十", "百", "千"};
+        String dst = "";
+        int count = 0;
+        while (src > 0) {
+            dst = (num[src % 10] + unit[count]) + dst;
+            src = src / 10;
+            count++;
+        }
+        return dst.replaceAll("零[千百十]", "零").replaceAll("零+万", "万")
+                .replaceAll("零+亿", "亿").replaceAll("亿万", "亿零")
+                .replaceAll("零+", "零").replaceAll("零$", "");
+    }
+
+
+    /**
+     * 获取日期对应的今年的月和日
+     *
+     * @param lunarDate 如传入2015-06-10,今年是2019,得到2019-06-10
+     * @return
+     */
+    public static String getThisYearMonthAndDay(String lunarDate) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
+        //获取当前公历日期
+        String today = getDateStr(new Date());
+        //截取公历日期的年份加上传入日期的月和日
+        String year = today.substring(0, 5);
+        String date = lunarDate.substring(5, lunarDate.length());
+        String thisYearDay = year + date;
+        return thisYearDay;
+    }
+
+    /**
+     * 获取数组日期对应的日期String
+     *
+     * @param dateArray
+     * @return
+     */
+    public static String getStringDate(int[] dateArray) {
+        int year = dateArray[0];
+        int month = dateArray[1];
+        int date = dateArray[2];
+        Calendar cal = Calendar.getInstance();
+        cal.set(year, month - 1, date);
+        Date yesterday = cal.getTime();
+        return getDateStr(yesterday);
+    }
+
+
+    /**
+     * 获取过去第几天的日期
+     *
+     * @param past
+     * @return
+     */
+    public static Date getPastDate(int past) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) - past);
+        Date today = calendar.getTime();
+        return today;
+    }
+
+
+    /**
+     * 获取时间多少分钟之后的时间
+     *
+     * @param date
+     * @param minutes
+     * @return
+     */
+    public static Date getDateAfterMinutes(Date date, int minutes) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        calendar.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE) + minutes);
+        Date afterDate = calendar.getTime();
+        return afterDate;
+    }
+
+    /**
+     * 获取时间多少秒之后的时间
+     *
+     * @param date
+     * @param minutes
+     * @return
+     */
+    public static Date getDateAfterSecond(Date date, int minutes) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        calendar.set(Calendar.SECOND, calendar.get(Calendar.SECOND) + minutes);
+        Date afterDate = calendar.getTime();
+        return afterDate;
+    }
+
+    public static Date getDayEnd(Date endDate) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(endDate);
+        // calendar.setTimeInMillis(endDate.getTime());
+        calendar.set(Calendar.HOUR_OF_DAY, 23);
+        calendar.set(Calendar.MINUTE, 59);
+        calendar.set(Calendar.SECOND, 59);
+        Date end = calendar.getTime();
+        return end;
+    }
+
+    public static Date getDayStart(Date startDate) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(startDate);
+        // calendar.setTimeInMillis(startDate.getTime());
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        Date start = calendar.getTime();
+        return start;
+    }
+
+    public static Date getMonthStart(Date startDate) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(startDate);
+        // calendar.setTimeInMillis(startDate.getTime());
+        calendar.set(Calendar.DAY_OF_MONTH, 1);
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        Date start = calendar.getTime();
+        return start;
+    }
+
+    public static Date getYearStart(Date startDate) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(startDate);
+        // calendar.setTimeInMillis(startDate.getTime());
+        calendar.set(Calendar.MONTH, 0);
+        calendar.set(Calendar.DAY_OF_MONTH, 1);
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        Date start = calendar.getTime();
+        return start;
+    }
+
+
+    /**
+     * 一年前的下个月开始日期
+     */
+    public static Date getOneYearTimeNextMonth(Date now) {
+        Calendar c = Calendar.getInstance();
+        c.setTime(now);
+        //年份减1
+        c.add(Calendar.YEAR, -1);
+        c.add(Calendar.MONTH, 1);
+        c.set(Calendar.DAY_OF_MONTH, 1);
+        c.set(Calendar.HOUR, 0);
+        c.set(Calendar.MINUTE, 0);
+        c.set(Calendar.SECOND, 0);
+        return c.getTime();
+    }
+
+    /**
+     * 获取固定值之前的时间
+     *
+     * @param now
+     * @param sec
+     * @return {@link Date}
+     **/
+    public static Date getLastTime(Date now, int sec) {
+        Calendar c = Calendar.getInstance();
+        c.setTime(now);
+        c.add(Calendar.SECOND, -sec);
+        return c.getTime();
+    }
+
+
+    public static Long dateDiff(Date startTime, Date endTime) {
+        long diff;
+        long min = 0;
+        // 获得两个时间的毫秒时间差异
+        diff = endTime.getTime() - startTime.getTime();
+        min = diff / 60 / 1000;
+        return min;
+    }
+
+    /**
+     * 获取指定周的周一日期
+     *
+     * @param year        年
+     * @param month       月
+     * @param weekOfMonth 当月第n周
+     * @return {@link Date}
+     **/
+    public static Date getMonthOfWeekDate(int year, int month, int weekOfMonth) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.YEAR, year);
+        calendar.set(Calendar.MONTH, month - 1);
+        calendar.set(Calendar.WEEK_OF_MONTH, weekOfMonth);
+        calendar.set(Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek() + 1);
+        return calendar.getTime();
+    }
+
+    /**
+     * 获取当前时间上一月 时间 YYYYMM
+     *
+     * @return
+     */
+    public static String getUpMonth() {
+        return getAddMonth(-1);
+    }
+
+    /**
+     * 获取某个月的时间 YYYYMM
+     *
+     * @return
+     */
+    public static String getAddMonth(int months) {
+        Calendar cal = Calendar.getInstance();
+        cal.add(Calendar.MONTH, months);
+
+        SimpleDateFormat formats = new SimpleDateFormat("yyyyMM");
+        formats.format(cal.getTime());
+        return formats.format(cal.getTime());
+    }
+
+    /**
+     * 获取当前时间上一年 时间 YYYYMM
+     *
+     * @return
+     */
+    public static String getUpYear() {
+        return getAddYear(-1);
+    }
+
+    /**
+     * 获取当前时间上一年 时间 YYYYMM
+     *
+     * @return
+     */
+    public static String getAddYear(int year) {
+        Calendar cal = Calendar.getInstance();
+        cal.add(Calendar.YEAR, year);
+
+        SimpleDateFormat formats = new SimpleDateFormat("yyyy");
+
+
+        return formats.format(cal.getTime());
+    }
+
+    /**
+     * 获取当年的最后一天
+     *
+     * @param year
+     * @return
+     */
+    public static String getCurrYearLast(int year) {
+
+
+        SimpleDateFormat formats = new SimpleDateFormat("yyyy-MM-dd");
+
+        Calendar calendar = Calendar.getInstance();
+        calendar.clear();
+        calendar.set(Calendar.YEAR, year);
+        calendar.roll(Calendar.DAY_OF_YEAR, -1);
+        Date currYearLast = calendar.getTime();
+        return formats.format(currYearLast);
+    }
+
+    public static Date getYesterdayDayEnd() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH) - 1,
+                23, 59, 59);
+        Date end = calendar.getTime();
+        return end;
+    }
+
+    /**
+     * 判断时间远程时间是否大于缓存时间
+     *
+     * @param theRemoteTime 远程时间
+     * @param cacheTime     缓存时间
+     * @return
+     */
+    public static boolean twoTimeJudgment(String theRemoteTime, String cacheTime) {
+        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+        try {
+            Date sd1 = df.parse(theRemoteTime);
+            Date sd2 = df.parse(cacheTime);
+            long long1 = sd1.getTime();
+            long long2 = sd2.getTime();
+            if (long1 > long2) {
+                return true;
+            }
+            return false;
+        } catch (ParseException e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 指定月份最后一天 并且加上指定天数
+     *
+     * @param month
+     * @return
+     */
+    public static String getMaxDateMonth(String month, int num) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM");
+        try {
+            Date nowDate = format.parse(month);
+            calendar = Calendar.getInstance();
+            calendar.setTime(nowDate);
+            calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
+            calendar.add(Calendar.DATE, num);// num为增加的天数,可以改变的
+            return sdf.format(calendar.getTime());
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 指定月份第一天 并且加上指定天数
+     *
+     * @param month
+     * @return
+     */
+    public static String getMinDateMonth(String month, int num) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM");
+        try {
+            Date nowDate = format.parse(month);
+            calendar = Calendar.getInstance();
+            calendar.setTime(nowDate);
+            calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
+            calendar.add(Calendar.DATE, -num);// num为增加的天数,可以改变的
+            return sdf.format(calendar.getTime());
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+    /**
+     * 时间向下取整,分钟数
+     *
+     * @param timestamp 传入毫秒级时间戳
+     * @param interval  分钟向下取整周期
+     * @return
+     */
+    public static String getLowIntervalMinuetStr(Long timestamp, Integer interval) {
+        LocalDateTime dateTime;
+        if (timestamp != null) {
+            dateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault());
+        } else {
+            dateTime = LocalDateTime.now(ZoneId.systemDefault());
+        }
+        int minute = dateTime.getMinute();
+        int lowerIntervalMinute = minute / interval * interval % 60;
+        String headTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH").withZone(ZoneId.systemDefault()).format(dateTime);
+        if (lowerIntervalMinute < 10) {
+            return new StringBuilder(headTime).append(":0").append(lowerIntervalMinute).append(":00").toString();
+        }
+        return new StringBuilder(headTime).append(":").append(lowerIntervalMinute).append(":00").toString();
+    }
+
+    /**
+     * @param timestamp
+     * @param interval
+     * @return
+     */
+    public static LocalDateTime getLowIntervalMinuetTime(Long timestamp, Integer interval) {
+        LocalDateTime dateTime;
+        if (timestamp != null) {
+            dateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault());
+        } else {
+            dateTime = LocalDateTime.now(ZoneId.systemDefault());
+        }
+        int minute = dateTime.getMinute();
+        int lowerIntervalMinute = minute / interval * interval % 60;
+        return dateTime.withMinute(lowerIntervalMinute).withSecond(0).withNano(0);
+    }
+
+    /**
+     * @param dateTime
+     * @param interval
+     * @return
+     */
+    public static DateTime getLowIntervalMinuetTime(Date dateTime, Integer interval) {
+        LocalDateTime localDateTime = DateUtil.toLocalDateTime(dateTime);
+        int minute = localDateTime.getMinute();
+        int lowerIntervalMinute = minute / interval * interval % 60;
+        LocalDateTime lowInterval = localDateTime.withMinute(lowerIntervalMinute).withSecond(0).withNano(0);
+        return DateUtil.parse(DateUtil.formatLocalDateTime(lowInterval));
+    }
+
+
+    /**
+     * @param localDateTime
+     * @param interval
+     * @return
+     */
+    public static DateTime getLowIntervalMinuetTime(LocalDateTime localDateTime, Integer interval) {
+        int minute = localDateTime.getMinute();
+        int lowerIntervalMinute = minute / interval * interval % 60;
+        LocalDateTime lowInterval = localDateTime.withMinute(lowerIntervalMinute).withSecond(0).withNano(0);
+        return DateUtil.parse(DateUtil.formatLocalDateTime(lowInterval));
+    }
+
+    /**
+     * 获取下一个分钟级别周期时间
+     *
+     * @param currentTime
+     * @param interval
+     * @param formatter
+     * @return
+     */
+    public static String getNextIntervalTime(String currentTime, long interval, String formatter) {
+        LocalDateTime dateTime = LocalDateTime.parse(currentTime, DateTimeFormatter.ofPattern(formatter));
+        dateTime = dateTime.plusMinutes(interval);
+        return DateTimeFormatter.ofPattern(formatter).withZone(ZoneId.systemDefault()).format(dateTime);
+    }
+
+
+    /***
+     * 获取某一时间 所在 月份 的第一天
+     *  比如 : 2020-01-20
+     *     结果为: 2020-01-01 00:00:00
+     * */
+    public static Date getFirstDateOfMonth(Date date) {
+        Calendar firstDate = Calendar.getInstance();
+        firstDate.setTime(date);
+        final int last = firstDate.getActualMinimum(Calendar.DAY_OF_MONTH);
+        firstDate.set(Calendar.DAY_OF_MONTH, last);
+        firstDate.set(Calendar.HOUR, 00);
+        firstDate.set(Calendar.MINUTE, 00);
+        firstDate.set(Calendar.SECOND, 00);
+        //当前日期 的 月份的 第一天)
+        return firstDate.getTime();
+    }
+
+    /***
+     * 获取某一时间 所在 月份 的最后一天
+     *  比如 : 2020-01-20
+     *     结果为: 2020-01-31 00:00:00
+     * */
+    public static Date getEndDayOfMonth(Date date) {
+
+        Calendar lastDateMonth = Calendar.getInstance();
+        lastDateMonth.setTime(date);
+        final int lastDay = lastDateMonth.getActualMaximum(Calendar.DAY_OF_MONTH);
+        lastDateMonth.set(Calendar.DAY_OF_MONTH, lastDay);
+        lastDateMonth.set(Calendar.HOUR, 23);
+        lastDateMonth.set(Calendar.MINUTE, 59);
+        lastDateMonth.set(Calendar.SECOND, 59);
+        //当前日期 的月份的最后一天
+        return lastDateMonth.getTime();
+    }
+
+
+    /**
+     * 获取上个月开始时间
+     *
+     * @return
+     */
+    public static String getLastMonthStartTime() {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        //上个月
+        Calendar calendar = Calendar.getInstance();
+        calendar.add(Calendar.MONTH, 1);
+        calendar.set(Calendar.DAY_OF_MONTH, 1);
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        return format.format(calendar.getTime());
+    }
+
+    /**
+     * 获取上个月结束时间
+     *
+     * @return
+     */
+    public static String getNextMonthEndTime() {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.DAY_OF_MONTH, 1);
+        calendar.add(Calendar.DATE, 0);
+        calendar.set(Calendar.HOUR_OF_DAY, 23);
+        calendar.set(Calendar.MINUTE, 59);
+        calendar.set(Calendar.SECOND, 59);
+        return format.format(calendar.getTime());
+    }
+
+
+    /**
+     * 获取本月开始时间
+     *
+     * @return xxxx-xx-01 00:00:59
+     */
+    public static String getStartTimeOfThisMonth() {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        //上个月
+        Calendar calendar = Calendar.getInstance();
+        calendar.add(Calendar.MONTH, 0);
+        calendar.set(Calendar.DAY_OF_MONTH, 1);
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        return format.format(calendar.getTime());
+    }
+
+    /**
+     * 获取本月结束时间
+     *
+     * @return xxxx-xx-xx 23:59:59
+     */
+    public static String getLastDayOfTheMonth() {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
+        calendar.set(Calendar.HOUR_OF_DAY, 23);
+        calendar.set(Calendar.MINUTE, 59);
+        calendar.set(Calendar.SECOND, 59);
+        return format.format(calendar.getTime());
+    }
+
+
+    public static Date clearMs(Date date) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        return calendar.getTime();
+    }
+
+    public static Date clearS(Date date) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        return calendar.getTime();
+    }
+
+
+    public static String getStartTimes() {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        //获取当天开始时间
+        String StartTime = sdf.format(getStartTime());
+        return StartTime;
+    }
+
+    public static Date getYear(int year) {
+        Calendar c = Calendar.getInstance();
+        c.set(year, 1, 1);
+        return c.getTime();
+    }
+
+    /**
+     * 开始时间
+     *
+     * @return
+     */
+    public static String getStartTime() {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Calendar todayStart = Calendar.getInstance();
+        todayStart.set(Calendar.HOUR_OF_DAY, 0);
+        todayStart.set(Calendar.MINUTE, 0);
+        todayStart.set(Calendar.SECOND, 0);
+        todayStart.set(Calendar.MILLISECOND, 0);
+        return format.format(todayStart.getTime());
+    }
+
+    /**
+     * 结束时间
+     *
+     * @return
+     */
+    public static String getEndTime() {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Calendar todayEnd = Calendar.getInstance();
+        todayEnd.set(Calendar.HOUR_OF_DAY, 23);
+        todayEnd.set(Calendar.MINUTE, 59);
+        todayEnd.set(Calendar.SECOND, 59);
+        todayEnd.set(Calendar.MILLISECOND, 59);
+        return format.format(todayEnd.getTime());
+    }
+
+    private final static String YEAR = "year";
+    private final static String MOUTH = "mouth";
+    private final static String DAY = "day";
+    private final static String HOUR = "hour";
+
+    /**
+     * @return
+     * @description {
+     * hour: startTime = 2022-04-15 00:00:00  、2022-04-15 01:00:00 、2022-04-15 02:00:00
+     * day: startTime = 2022-04-15 00:00:00   、2022-04-16 00:00:00 、2022-04-17 00:00:00
+     * mouth: startTime = 2022-04-01 00:00:00   、2022-05-01 00:00:00 、2022-06-01 00:00:00
+     * year: startTime = 2022-01-01 00:00:00   、2023-01-01 00:00:00 、2024-01-01 00:00:00
+     * }
+     */
+    public static Date getStartTime(String date, Date time) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(time);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        if (YEAR.equals(date)) {
+            calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) - 1);
+            calendar.set(Calendar.MONTH, 0);
+            calendar.set(Calendar.DATE, 1);
+            calendar.set(Calendar.HOUR_OF_DAY, 0);
+        }
+        if (MOUTH.equals(date)) {
+            calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR));
+            calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) - 1);
+            calendar.set(Calendar.DATE, 1);
+            calendar.set(Calendar.HOUR_OF_DAY, 0);
+        }
+        if (DAY.equals(date)) {
+            calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR));
+            calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
+            calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) - 1);
+            calendar.set(Calendar.HOUR_OF_DAY, 0);
+        }
+        if (HOUR.equals(date)) {
+            calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR));
+            calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
+            calendar.set(Calendar.DATE, calendar.get(Calendar.DATE));
+            calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) - 1);
+        }
+        return calendar.getTime();
+    }
+
+    /**
+     * @return
+     * @description {
+     * hour: endTime = 2022-04-15 00:59:59  、2022-04-15 01:59:59 、2022-04-15 02:59:59
+     * day: endTime = 2022-04-15 23:59:59   、2022-04-16 23:59:59 、2022-04-17 23:59:59
+     * mouth: endTime = 2022-04-max 23:59:59   、2022-05-max 23:59:59 、2022-06-max 23:59:59
+     * year: endTime = 2022-12-31 23:59:59   、2023-12-31 23:59:59 、2024-12-31 23:59:59
+     * }
+     */
+    public static Date getEndTime(String date, Date time) {
+
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(time);
+        calendar.set(Calendar.MINUTE, 59);
+        calendar.set(Calendar.SECOND, 59);
+        if (YEAR.equals(date)) {
+            calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) - 1);
+            calendar.set(Calendar.MONTH, 11);
+            calendar.set(Calendar.DATE, 1);
+            calendar.set(Calendar.HOUR_OF_DAY, 23);
+        }
+        if (MOUTH.equals(date)) {
+            calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR));
+            calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) - 1);
+            calendar.set(Calendar.DATE, 1);
+            calendar.set(Calendar.HOUR_OF_DAY, 23);
+        }
+        if (DAY.equals(date)) {
+            calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR));
+            calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
+            calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) - 1);
+            calendar.set(Calendar.HOUR_OF_DAY, 23);
+        }
+        if (HOUR.equals(date)) {
+            calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR));
+            calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
+            calendar.set(Calendar.DATE, calendar.get(Calendar.DATE));
+            calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) - 1);
+        }
+        LocalDateTime localDateTime = calendar.getTime().toInstant()
+                .atZone(ZoneId.systemDefault())
+                .toLocalDateTime();
+        if (YEAR.equals(date) || MOUTH.equals(date)) {
+            localDateTime = localDateTime.with(TemporalAdjusters.lastDayOfMonth());
+        }
+        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
+    }
+
+
+
+    /**
+     * 获取两个日期之间的所有日期 (年月日)
+     *
+     * @param startTime
+     * @param endTime
+     * @return
+     */
+    public static List<String> getBetweenDate(String startTime, String endTime) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        // 声明保存日期集合
+        List<String> list = new ArrayList<String>();
+        try {
+            // 转化成日期类型
+            Date startDate = sdf.parse(startTime);
+            Date endDate = sdf.parse(endTime);
+
+            //用Calendar 进行日期比较判断
+            Calendar calendar = Calendar.getInstance();
+            while (startDate.getTime() <= endDate.getTime()) {
+                // 把日期添加到集合
+                list.add(sdf.format(startDate));
+                // 设置日期
+                calendar.setTime(startDate);
+                //把日期增加一天
+                calendar.add(Calendar.DATE, 1);
+                // 获取增加后的日期
+                startDate = calendar.getTime();
+            }
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return list;
+    }
+
+    /**
+     * 获取两个日期之间的所有日期 (年月日)
+     *
+     * @param startTime
+     * @param endTime
+     * @return
+     */
+    public static List<String> getBetweenMonth(String startTime, String endTime) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
+        // 声明保存日期集合
+        List<String> list = new ArrayList<String>();
+        try {
+            // 转化成日期类型
+            Date startDate = sdf.parse(startTime);
+            Date endDate = sdf.parse(endTime);
+
+            //用Calendar 进行日期比较判断
+            Calendar calendar = Calendar.getInstance();
+            while (startDate.getTime() <= endDate.getTime()) {
+                // 把日期添加到集合
+                list.add(sdf.format(startDate));
+                // 设置日期
+                calendar.setTime(startDate);
+                //把日期增加一天
+                calendar.add(Calendar.MONTH, 1);
+                // 获取增加后的日期
+                startDate = calendar.getTime();
+            }
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return list;
+    }
+
+    /**
+     * 获取指定年月的第一天
+     *
+     * @param year
+     * @param month
+     * @return
+     */
+    public static String getFirstDayOfMonth(int year, int month) {
+        Calendar cal = Calendar.getInstance();
+        //清除可能存在的缓存
+        cal.clear();
+        //设置年份
+        cal.set(Calendar.YEAR, year);
+        //设置月份
+        cal.set(Calendar.MONTH, month - 1);
+        //获取某月最小天数
+        int firstDay = cal.getMinimum(Calendar.DATE);
+        //设置日历中月份的最小天数
+        cal.set(Calendar.DAY_OF_MONTH, firstDay);
+        //格式化日期
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        return sdf.format(cal.getTime());
+    }
+
+    /**
+     * 获取指定年月的最后一天
+     *
+     * @param year
+     * @param month
+     * @return
+     */
+    public static String getLastDayOfMonth(int year, int month) {
+        Calendar cal = Calendar.getInstance();
+        //清除可能存在的缓存
+        cal.clear();
+        //设置年份
+        cal.set(Calendar.YEAR, year);
+        //设置月份
+        cal.set(Calendar.MONTH, month-1);
+        //获取某月最大天数
+        int lastDay = cal.getActualMaximum(Calendar.DATE);
+        //设置日历中月份的最大天数
+        cal.set(Calendar.DAY_OF_MONTH, lastDay);
+        //格式化日期
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        return sdf.format(cal.getTime());
+    }
+
+
+    /**
+     * 解析 HH:mm 格式的字符串,获得分钟数
+     *
+     * @param
+     */
+    public static Integer getMinuteValueByStr(String str) {
+        String[] split = str.split(":");
+        return Integer.parseInt(split[0]) * 60 + Integer.parseInt(split[1]);
+    }
+
+}

+ 26 - 3
blade-service/blade-manager/src/main/java/com/jfireel/expression/node/impl/MinusNode.java

@@ -2,6 +2,7 @@ package com.jfireel.expression.node.impl;
 
 import com.jfireel.expression.token.Operator;
 import com.jfireel.expression.util.number.SubtractUtil;
+import com.mixsmart.utils.CustomFunction;
 import com.mixsmart.utils.StringUtils;
 
 import java.math.BigDecimal;
@@ -15,20 +16,42 @@ public class MinusNode extends OperatorResultNode {
 	@Override
 	public Object calculate(Map<String, Object> variables) {
 		Object leftValue = leftOperand.calculate(variables);
+		Object rightValue = rightOperand.calculate(variables);
+		String reg="[0-9.-]+(\\*[0-9.-]+)+";
+        if(StringUtils.handleNull(leftValue).matches(reg)&&StringUtils.handleNull(rightValue).matches(reg)){
+        	return CustomFunction.dXd(rightValue,leftValue);
+		}
 		if(leftValue instanceof String && StringUtils.isNumber(leftValue)) {
 			leftValue = new BigDecimal(leftValue.toString());
 		}
-		if (leftValue instanceof Number == false) {
+		if (!(leftValue instanceof Number)) {
 			return null;
 		}
-		Object rightValue = rightOperand.calculate(variables);
 		if(rightValue instanceof String && StringUtils.isNumber(rightValue)) {
 			rightValue = new BigDecimal(rightValue.toString());
 		}
-		if (rightValue instanceof Number == false) {
+		if (!(rightValue instanceof Number)) {
 			return null;
 		}
 		return SubtractUtil.calculate((Number) leftValue, (Number) rightValue);
 	}
 
+//	public Object calculateOld(Map<String, Object> variables) {
+//		Object leftValue = leftOperand.calculate(variables);
+//		if(leftValue instanceof String && StringUtils.isNumber(leftValue)) {
+//			leftValue = new BigDecimal(leftValue.toString());
+//		}
+//		if (!(leftValue instanceof Number)) {
+//			return null;
+//		}
+//		Object rightValue = rightOperand.calculate(variables);
+//		if(rightValue instanceof String && StringUtils.isNumber(rightValue)) {
+//			rightValue = new BigDecimal(rightValue.toString());
+//		}
+//		if (!(rightValue instanceof Number)) {
+//			return null;
+//		}
+//		return SubtractUtil.calculate((Number) leftValue, (Number) rightValue);
+//	}
+
 }

+ 18 - 3
blade-service/blade-manager/src/main/java/com/jfireel/expression/node/impl/MutliNode.java

@@ -2,10 +2,13 @@ package com.jfireel.expression.node.impl;
 
 import com.jfireel.expression.token.Operator;
 import com.jfireel.expression.util.number.MultiplyUtil;
+import com.mixsmart.utils.CustomFunction;
 import com.mixsmart.utils.StringUtils;
 
 import java.math.BigDecimal;
+import java.util.Collections;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 public class MutliNode extends OperatorResultNode {
 
@@ -16,17 +19,29 @@ public class MutliNode extends OperatorResultNode {
 	@Override
 	public Object calculate(Map<String, Object> variables) {
 		Object leftValue = leftOperand.calculate(variables);
+		Object rightValue = rightOperand.calculate(variables);
+		String reg="[0-9.-]+(\\*[0-9.-]+)+";
+		if(StringUtils.handleNull(leftValue).matches(reg)&&StringUtils.handleNull(rightValue).matches(reg)){
+			return CustomFunction.dXd(rightValue,leftValue);
+		}else if(StringUtils.handleNull(leftValue).matches(reg)){
+			int n= StringUtils.handleNull(leftValue).trim().split("[*]").length;
+			String rightValueStr=Collections.nCopies(n,rightValue).stream().map(StringUtils::handleNull).collect(Collectors.joining("*"));
+			return  CustomFunction.dXd(rightValueStr,leftValue,1,1);
+		}else if(StringUtils.handleNull(rightValue).matches(reg)){
+			int n= StringUtils.handleNull(rightValue).trim().split("[*]").length;
+			String leftValueStr=Collections.nCopies(n,leftValue).stream().map(StringUtils::handleNull).collect(Collectors.joining("*"));
+			return  CustomFunction.dXd(rightValue,leftValueStr,1,1);
+		}
 		if(leftValue instanceof String && StringUtils.isNumber(leftValue)) {
 			leftValue = new BigDecimal(leftValue.toString());
 		}
-		if (leftValue instanceof Number == false) {
+		if (!(leftValue instanceof Number)) {
 			return null;
 		}
-		Object rightValue = rightOperand.calculate(variables);
 		if(rightValue instanceof String && StringUtils.isNumber(rightValue)) {
 			rightValue = new BigDecimal(rightValue.toString());
 		}
-		if (rightValue instanceof Number == false) {
+		if (!(rightValue instanceof Number)) {
 			return null;
 		}
 		return MultiplyUtil.calculate((Number) leftValue, (Number) rightValue);

+ 1 - 1
blade-service/blade-manager/src/main/java/com/jfireel/expression/util/number/SubtractUtil.java

@@ -63,7 +63,7 @@ public class SubtractUtil {
 	private static Object calculate(BigDecimal a, BigDecimal b) {
 		int aScale = new BigDecimal(a.toString()).scale();
 		int bScale = new BigDecimal(b.toString()).scale();
-		return a.subtract(b).setScale(aScale > bScale ? aScale : bScale, BigDecimal.ROUND_HALF_UP);
+		return a.subtract(b).setScale(Math.max(aScale, bScale), BigDecimal.ROUND_HALF_UP);
 	}
 	
 	public static Object calculate(Number a, Number b) {

+ 23 - 51
blade-service/blade-manager/src/main/java/com/mixsmart/utils/CustomFunction.java

@@ -436,7 +436,7 @@ public class CustomFunction {
 
 	public static Object dateMin(Object range){
 		if(StringUtils.isNotEmpty(range)){
-			String[] s= Func.toStr(range).replaceAll("[[|]]","").split(",");
+			String[] s= Func.toStr(range).replaceAll("[|]","").split(",");
 			return dateCp(s[0],s[1],true);
 		}
 		return StringPool.EMPTY;
@@ -2683,24 +2683,25 @@ public class CustomFunction {
 
 
 	public  static Object dXd(Object design,Object data){
-		return dXd(design,data,1,getScale(design,data));
+		return dXd(design,data,1,0);
 	}
-	public  static Object dXd(Object design,Object data,Object xN){
+	public  static Object dXd(Object design,Object data,Object xN,Integer mode){
 		int scale=0;
 		if(StringUtils.isNotEmpty(design,data,xN)){
 			 scale=getScale(design,data);
 			 scale= (int) (scale-Math.log10(Double.parseDouble(xN.toString())));
 		}
-		return dXd(design,data,xN,scale);
+		if(StringUtils.isEmpty(mode)){mode=0;}
+		return dXd(design,data,xN,scale,mode);
 	}
 	/**
 	 * @Description 求偏差公式  支持AXA-BXB=DXD或者A-B=D的格式
-	 * @Param [design:设计值, data:实测值, xN:倍率, scale:保留小数位]
+	 * @Param [design:设计值, data:实测值, xN:倍率, scale:保留小数位,mode:1乘法,其它默认减法]
 	 * @return java.lang.Object
 	 * @Author yangyj
 	 * @Date 2022.01.20 09:45
 	 **/
-	public  static Object dXd(Object design,Object data,Object xN,Object scale){
+	public  static Object dXd(Object design,Object data,Object xN,Object scale,Integer mode){
 		if(StringUtils.isNotEmpty(design,data)){
 			if(StringUtils.isEmpty(xN)){
 				xN=1;
@@ -2718,7 +2719,12 @@ public class CustomFunction {
 			for(int n=0;n<dArr.length;n++){
 				BigDecimal a = new BigDecimal(dArr[n]);
 				BigDecimal b = new BigDecimal(bArr[n]);
-				String _data=b.subtract(a).multiply(new BigDecimal(xN.toString())).setScale(Integer.parseInt(scale.toString()), ROUND_HALF_UP).toString();
+				String _data;
+				if(StringUtils.isEquals(1,mode)){
+					_data= b.multiply(a).multiply(new BigDecimal(xN.toString())).setScale(Integer.parseInt(scale.toString()), ROUND_HALF_UP).toString();
+				}else{
+					_data=	b.subtract(a).multiply(new BigDecimal(xN.toString())).setScale(Integer.parseInt(scale.toString()), ROUND_HALF_UP).toString();
+				}
 				if(StringUtils.isNotEmpty(_dx)){
 					_dx=StringUtils.join(_dx,_data,delimiter);
 				}else{
@@ -2731,49 +2737,9 @@ public class CustomFunction {
 	}
 
 
-	public  static Object over10(Object C82 ,Object C81 ,Object xmm, Object remark){
-         List<Object> list = obj2List(C82);
-         if(ListUtils.isNotEmpty(list)){
-         	if(list.stream().map(StringUtils::handleNull).anyMatch(e->e.contains(xmm.toString()))){
-				return remark;
-			}
-		 }
-		List<Object> list2 =obj2List(C81);
-		if(ListUtils.isNotEmpty(list2)){
-			return list2.stream().filter(StringUtils::isNotEmpty).map(StringUtils::handleNull).collect(Collectors.joining("、"));
-		}else{
-			return "";
-		}
-	}
 
-	/**
-	 * @Description 字符串连接
-	 * @Param [obs]
-	 * @return java.lang.Object
-	 * @Author yangyj
-	 * @Date 2022.02.12 17:21
-	 **/
-	public  static Object _concat(Object ...obs){
-		StringBuilder sb  = new StringBuilder();
-		if(obs!=null){
-			for(Object ob:obs){
-				sb.append(handleNull(ob));
-			}
-		}
-        return sb.toString();
-	}
-	public  static Object concat(Object o1,Object o2,Object o3,Object o4){
-		return _concat(o1,o2,o3,o4);
-	}
-	public  static Object concat(Object o1,Object o2,Object o3){
-		return _concat(o1,o2,o3);
-	}
-	public  static Object concat(Object o1,Object o2){
-		return _concat(o1,o2);
-	}
-	public  static Object concat(Object o1){
-		return _concat(o1);
-	}
+
+
 
 
 	/**
@@ -2797,8 +2763,14 @@ public class CustomFunction {
 	}
 
 	public static void main(String[] args) {
-		String s="边坡或仰坡坡度_不大于设计_尺量:每洞口检查10处_实测";
-		System.out.println(s.split("[((].+[))]|_")[0]);
+		Map<String,Object> map =new HashMap<>();
+		map.put("A","13.3");
+		map.put("B","13.5");
+//		map.put("A","17*20");
+//		map.put("B","18*18");
+//		Expression.parse("(A-B)*10").calculate(map);
+		System.out.println(Expression.parse("(A-B)*10").calculate(map).toString());
+
 	}
 
 

+ 158 - 1
blade-service/blade-manager/src/main/java/com/mixsmart/utils/FormulaUtils.java

@@ -1,6 +1,9 @@
 package com.mixsmart.utils;
 
 
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import org.springblade.manager.bean.TableInfo;
 import org.springblade.manager.dto.Coords;
 import org.springblade.manager.dto.ElementData;
 import org.springblade.manager.dto.FormData;
@@ -62,9 +65,12 @@ public class FormulaUtils {
         return result;
     }
 
-    public  static void write(FormData fd, Object data){
+    public  static void write(FormData fd, Object data,Boolean nullOrBlank ){
         if(data instanceof List){
             List<Object> values = (List<Object>) data;
+            if(!nullOrBlank){
+               values=values.stream().filter(StringUtils::isNotEmpty).collect(Collectors.toList());
+            }
             if(values.size()>fd.getValues().size()){
                 /*当生成的数据超过实际容量的时候,会自动追加页数*/
                 if(fd.getCoordsList().size()==1){
@@ -111,7 +117,158 @@ public class FormulaUtils {
         }
 
     }
+    public static  List<TableInfo> getTableInfoList(JSONArray dataArray) {
+        if (dataArray != null && !dataArray.isEmpty()) {
+            List<TableInfo> result = new ArrayList<>();
+            for (int m = 0; m < dataArray.size(); m++) {
+                TableInfo tableInfo = new TableInfo();
+                JSONObject dataInfo2 = dataArray.getJSONObject(m);
+                //
+                tableInfo.setContractId(dataInfo2.getString("contractId"));
+                tableInfo.setPkeyId(dataInfo2.getString("pkeyId"));
+                tableInfo.setProjectId(dataInfo2.getString("projectId"));
+                //huangjn 填报的类型,施工或监理
+                tableInfo.setClassify(dataInfo2.getString("classify"));
+
+                //设置首件信息
+                setFirstData(dataInfo2, tableInfo);
+//                //设置日志信息
+                setTheLogData(dataInfo2, tableInfo);
+
+                dataInfo2.fluentRemove("contractId")
+                        .fluentRemove("pkeyId")
+                        .fluentRemove("p_key_id")
+                        .fluentRemove("projectId")
+                        .fluentRemove("classify")
+                        .fluentRemove("pickerKey")
+                        .fluentRemove("id")
+                        .fluentRemove("isFirst")
+                        .fluentRemove("firstNodeId")
+                        .fluentRemove("isTheLog")
+                        .fluentRemove("theLogId")
+                        .fluentRemove("linkTabIds")
+                        .fluentRemove("recordTime")
+                        .fluentRemove("businessId")
+                        .fluentRemove("sourceUrl")
+                        .fluentRemove("pdfUrl")
+                        .fluentRemove("firstFileName")
+                        .fluentRemove("");
+                // 计算数据
+                LinkedHashMap<String, List<String>> dataMap = dataInfo2.keySet().stream().filter(e -> e.contains("__")).collect(Collectors.groupingBy(e -> e.split("__")[0], LinkedHashMap<String, List<String>>::new, Collectors.toList()));
+                LinkedHashMap<String, String> dataMap2 = new LinkedHashMap<>();
+                // 字段组合
+                for (String k : dataMap.keySet()) {
+                    if (dataMap.get(k).size() > 1 && !dataMap.get(k).contains("000Z")) {
+                        String[] ziduan = dataMap.get(k).toArray(new String[]{});
+                        String temp = "";
+                        for (int i = 0; i < ziduan.length - 1; i++) {
+                            for (int j = 0; j < ziduan.length - i - 1; j++) {
+                                Integer tr = Integer.parseInt((ziduan[j].split("__")[1]).split("_")[0]);
+                                Integer td = Integer.parseInt(ziduan[j].split("__")[1].split("_")[1]);
 
+                                Integer tr_1 = Integer.parseInt(ziduan[j + 1].split("__")[1].split("_")[0]);
+                                Integer td_1 = Integer.parseInt(ziduan[j + 1].split("__")[1].split("_")[1]);
+
+                                if (tr > tr_1 && td == td_1) { //纵向排序
+                                    temp = ziduan[j];
+                                    ziduan[j] = ziduan[j + 1];
+                                    ziduan[j + 1] = temp;
+                                }
+                            }
+                        }
 
+                        String lastStr = dataInfo2.getString(ziduan[0]) + "_^_" + ziduan[0].split("__")[1];
+                        for (int i = 1; i < ziduan.length; i++) {
+                            String keyData = dataInfo2.getString(ziduan[i]);
+                            if (!keyData.equals("")) {
+                                lastStr += "☆" + dataInfo2.getString(ziduan[i]) + "_^_" + ziduan[i].split("__")[1];
+                            }
 
+                        }
+                        dataMap2.put(k, lastStr);
+                    } else {
+                        String dataVal = dataInfo2.getString(dataMap.get(k).get(0));
+                        dataMap2.put(k, dataVal + "_^_" + dataMap.get(k).get(0).split("__")[1]);
+                    }
+                }
+                dataMap2.put("p_key_id", tableInfo.getPkeyId());
+                tableInfo.setDataMap(dataMap2);
+                result.add(tableInfo);
+            }
+            return result;
+        }
+        return null;
+    }
+
+    public static void setFirstData(JSONObject dataInfo2, TableInfo tableInfo) {
+        //huangjn 判断是否是首件
+        if (dataInfo2.containsKey("isFirst")) {
+            tableInfo.setIsFirst(dataInfo2.getString("isFirst"));
+        }
+        //huangjn 判断是否是首件
+
+        //首件资料绑定的节点
+        if (dataInfo2.containsKey("firstNodeId")) {
+            tableInfo.setFirstNodeId(dataInfo2.getString("firstNodeId"));
+        }
+        //首件ID(编辑时有值,新增时为空)
+        if (dataInfo2.containsKey("firstId")) {
+            tableInfo.setFirstId(dataInfo2.getString("firstId"));
+        }
+        //源文件
+        if (dataInfo2.containsKey("sourceUrl")) {
+            tableInfo.setSourceUrl(dataInfo2.getString("sourceUrl"));
+        }
+        //pdfUrl
+        if (dataInfo2.containsKey("pdfUrl")) {
+            tableInfo.setPdfUrl(dataInfo2.getString("pdfUrl"));
+        }
+        //文件名称
+        if (dataInfo2.containsKey("firstFileName")) {
+            tableInfo.setFirstFileName(dataInfo2.getString("firstFileName"));
+        }
+        //关联的信息
+        if (dataInfo2.containsKey("linkProcessList")) {
+            tableInfo.setLinkProcessList(dataInfo2.getJSONArray("linkProcessList"));
+        }
+    }
+
+    /**
+     * 设置日志信息
+     */
+    public static void setTheLogData(JSONObject dataInfo2, TableInfo tableInfo) {
+        //huangjn 判断是否是日志
+        if (dataInfo2.containsKey("isTheLog")) {
+            tableInfo.setIsTheLog(dataInfo2.getString("isTheLog"));
+        }
+        //huangjn 判断是否是日志
+
+        //huangjn 日志ID
+        if (dataInfo2.containsKey("theLogId")) {
+            tableInfo.setTheLogId(dataInfo2.getString("theLogId"));
+        }
+        //huangjn 日志ID
+
+        //huangjn 日志勾选的工序
+        if (dataInfo2.containsKey("linkTabIds")) {
+            tableInfo.setLinkTabIds(dataInfo2.getJSONArray("linkTabIds"));
+        }
+        //huangjn 日志勾选的工序
+
+        //huangjn 日志所选时间
+        if (dataInfo2.containsKey("recordTime")) {
+            tableInfo.setRecordTime(dataInfo2.getString("recordTime"));
+        }
+        //huangjn 日志所选时间
+        //huangjn 每份填报数据的id,目前日志专用
+        if (dataInfo2.containsKey("id")) {
+            tableInfo.setBusinessId(dataInfo2.getString("id"));
+        }
+        //huangjn 每份填报数据的id,目前日志专用
+    }
+
+    /*从元素名称中解析项目名称*/
+    public static  String parseItemName(String eName){
+        return StringUtils.handleNull(eName).replaceAll("^[^\\u4e00-\\u9fa5\\s]+","").split("[((].+[))]|_")[0];
+    }
 }

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

@@ -209,9 +209,9 @@ public class ArchiveTreeController extends BladeController {
     @ApiOperationSupport(order = 8)
     @ApiOperation(value = "保存立卷规则设置", notes = "传入archiveAutoType规则类型,nodeIds逗号拼接选择节点id")
     public R saveArchiveAutoRule(@ApiParam(value = "立卷规则", required = true) @RequestParam Integer archiveAutoType,
-                                 @ApiParam(value = "主键集合", required = true) @RequestParam String nodeIds,
+                                 @ApiParam(value = "主键集合", required = true) @RequestParam String selectNodeIds,
                                  @ApiParam(value = "是否wbs节点", required = true) @RequestParam Boolean iswbsNode) {
-        return R.status(archiveTreeService.saveArchiveAutoRule(archiveAutoType,nodeIds,iswbsNode));
+        return R.status(archiveTreeService.saveArchiveAutoRule(archiveAutoType,selectNodeIds,iswbsNode));
     }
 
 
@@ -236,8 +236,8 @@ public class ArchiveTreeController extends BladeController {
      * 查看立卷规则设置
      */
     @PostMapping("/getArchiveAutoRule")
-    public R getArchiveAutoRule(Long id,boolean iswbsNode) {
-        Map<String, Object> ruleMap=archiveTreeService.getArchiveAutoRule(id,iswbsNode);
+    public R getArchiveAutoRule(Long nodeId,boolean iswbsNode) {
+        Map<String, Object> ruleMap=archiveTreeService.getArchiveAutoRule(nodeId,iswbsNode);
         return R.data(ruleMap);
     }
 

+ 49 - 28
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java

@@ -1,6 +1,5 @@
 package org.springblade.manager.controller;
 
-
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -10,8 +9,10 @@ import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
-
-import com.spire.xls.*;
+import com.spire.xls.CellRange;
+import com.spire.xls.ExcelPicture;
+import com.spire.xls.Workbook;
+import com.spire.xls.Worksheet;
 import com.spire.xls.core.spreadsheet.HTMLOptions;
 import io.swagger.annotations.*;
 import lombok.AllArgsConstructor;
@@ -24,8 +25,6 @@ import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
 import org.jsoup.nodes.Element;
 import org.jsoup.select.Elements;
-import org.springblade.business.dto.TrialSelfInspectionRecordDTO;
-import org.springblade.business.entity.TrialSelfInspectionRecord;
 import org.springblade.business.feign.ContractLogClient;
 import org.springblade.business.feign.InformationQueryClient;
 import org.springblade.business.vo.SaveContractLogVO;
@@ -34,8 +33,9 @@ import org.springblade.common.utils.CommonUtil;
 import org.springblade.common.utils.MathUtil;
 import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.core.boot.ctrl.BladeController;
-import org.springblade.core.excel.util.ExcelUtil;
+import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
 import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.secure.BladeUser;
 import org.springblade.core.secure.utils.AuthUtil;
@@ -44,7 +44,6 @@ import org.springblade.core.tool.constant.BladeConstant;
 import org.springblade.core.tool.utils.*;
 import org.springblade.manager.bean.TableInfo;
 import org.springblade.manager.entity.*;
-import org.springblade.manager.excel.WbsFormElementBatchExcel;
 import org.springblade.manager.mapper.WbsTreePrivateMapper;
 import org.springblade.manager.service.*;
 import org.springblade.manager.utils.FileUtils;
@@ -57,32 +56,23 @@ import org.springblade.resource.feign.IOSSClient;
 import org.springblade.resource.feign.NewIOSSClient;
 import org.springblade.resource.vo.NewBladeFile;
 import org.springblade.system.cache.ParamCache;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
-import org.springblade.core.mp.support.Query;
-import org.springblade.core.log.exception.ServiceException;
 import org.springframework.web.multipart.MultipartFile;
 
 import javax.imageio.ImageIO;
-import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 import java.awt.*;
 import java.awt.image.BufferedImage;
 import java.io.*;
 import java.net.URLEncoder;
-import java.util.*;
 import java.util.List;
+import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
-import static com.baomidou.mybatisplus.core.toolkit.Wrappers.lambdaQuery;
-import static com.baomidou.mybatisplus.core.toolkit.Wrappers.query;
-
 
 /**
  * 清表基础数据表 控制器
@@ -1358,7 +1348,7 @@ public class ExcelTabController extends BladeController {
             @ApiImplicitParam(name = "pkeyId", value = "pkeyId", required = true)
     })
     public R getBussDataInfo(Long pkeyId) throws FileNotFoundException {
-        return excelTabService.getBussDataInfo(pkeyId);
+        return excelTabService.getBussDataInfo(pkeyId,0);
     }
 
 
@@ -1382,20 +1372,19 @@ public class ExcelTabController extends BladeController {
             @ApiImplicitParam(name = "pkeyId", value = "pkeyId", required = true)
     })
     public R copeBussTab(Long pkeyId) {
-        WbsTreeContract wbsTreeContract = wbsTreeContractService.getBaseMapper().selectOne(Wrappers.<WbsTreeContract>query().lambda()
+        WbsTreeContract wbsInfo = wbsTreeContractService.getBaseMapper().selectOne(Wrappers.<WbsTreeContract>query().lambda()
                 .eq(WbsTreeContract::getPKeyId, pkeyId));
 
         List<WbsTreeContract> wbsTreeContractList = wbsTreeContractService.getBaseMapper().selectList(Wrappers.<WbsTreeContract>query().lambda()
-                .eq(WbsTreeContract::getId, wbsTreeContract.getId())
-                .eq(WbsTreeContract::getContractId, wbsTreeContract.getContractId())
-                .eq(WbsTreeContract::getParentId, wbsTreeContract.getParentId()));
+                .eq(WbsTreeContract::getId, wbsInfo.getId())
+                .eq(WbsTreeContract::getContractId, wbsInfo.getContractId())
+                .eq(WbsTreeContract::getParentId, wbsInfo.getParentId()));
         List<WbsTreeContract> wbsTreeContractList2 = wbsTreeContractList.stream().sorted(Comparator.comparing(WbsTreeContract::getCreateTime).reversed()).collect(Collectors.toList());
         long tabGroupId = SnowFlakeUtil.getId();
-        // 添加所有
-        wbsTreeContractList2.forEach(WbsTreeContract -> WbsTreeContract.setTabGroupId(tabGroupId));
-
 
         long newPkId = SnowFlakeUtil.getId();
+        WbsTreeContract wbsTreeContract = new WbsTreeContract();
+        BeanUtil.copy(wbsInfo,wbsTreeContract);
         wbsTreeContract.setPKeyId(newPkId);
         wbsTreeContract.setCreateTime(new Date());
         wbsTreeContract.setTabGroupId(tabGroupId);
@@ -1424,8 +1413,14 @@ public class ExcelTabController extends BladeController {
 
         String querySql = "insert into " + tabName + " (id,p_key_id," + colkeys + ") select '" + newPkId + "','" + newPkId + "'," + colkeys + " from " + tabName + " where p_key_id=" + pkeyId;
         jdbcTemplate.execute(querySql);
-        wbsTreeContractService.saveBatch(wbsTreeContractList2);
         wbsTreeContractService.save(wbsTreeContract);
+        for(WbsTreeContract wbsTreeCont:wbsTreeContractList2){
+
+            UpdateWrapper<WbsTreeContract> updateWrapper = new UpdateWrapper<>();
+            updateWrapper.in("p_key_id", wbsTreeCont.getPKeyId() + "");
+            updateWrapper.set("tab_group_id", tabGroupId);
+            wbsTreeContractService.update(updateWrapper);
+        }
         return R.data("成功");
     }
 
@@ -1632,6 +1627,7 @@ public class ExcelTabController extends BladeController {
             groupIds += "," + jsonObject.getString("tabGroupId");
             ;
         }
+        /*
         if (StringUtils.isNotEmpty(groupIds)) {
             List<WbsTreeContract> wbsTreeContractList = this.wbsTreeContractService.getBaseMapper().selectList(
                     Wrappers.<WbsTreeContract>lambdaQuery()
@@ -1641,14 +1637,39 @@ public class ExcelTabController extends BladeController {
             );
             if (wbsTreeContractList != null && wbsTreeContractList.size() >= 1) {
                 for (WbsTreeContract data : wbsTreeContractList) {
-                    R bussDataInfo = this.getBussDataInfo(data.getPKeyId());
+                    R bussDataInfo = this.excelTabService.getBussDataInfo(data.getPKeyId(),1);
                     Object data1 = bussDataInfo.getData();
                     dataArray.add(data1);
                 }
             }
         }
-
+       */
+        /*全加载,或者可以优化成依赖加载*/
         List<TableInfo> tableInfoList = this.excelTabService.getTableInfoList(dataArray);
+        if(tableInfoList!=null){
+            List<AppWbsTreeContractVO> tableAll = wbsTreeContractService.searchNodeAllTable(nodeid, "1", contractId, projectId);
+            List<Long> tableAllIds=tableAll.stream().map(AppWbsTreeContractVO::getPKeyId).collect(Collectors.toList());
+            if(tableAll.size()>tableInfoList.size()){
+                List<Long> exclude=tableInfoList.stream().map(TableInfo::getPkeyId).map(Long::parseLong).collect(Collectors.toList());
+                JSONArray extra =new JSONArray();
+                for(Long pk:tableAllIds){
+                    if(!exclude.contains(pk)) {
+                        R bussDataInfo = this.excelTabService.getBussDataInfo(pk, 1);
+                        Map<String, Object>  jo = (Map<String, Object>) bussDataInfo.getData();
+                        jo.put("pkeyId",pk);
+                        extra.add(jo);
+                    }
+                }
+                List<TableInfo> tableInfoExtra = this.excelTabService.getTableInfoList(extra);
+                /*默认额外加载的默认不更新,除非有元素数据变动*/
+                tableInfoExtra.removeIf(e->e.getPkeyId()==null);
+                TableInfo example=tableInfoList.get(0);
+                tableInfoExtra.forEach(e->{e.setToBeUpdated(false);e.setBusinessId(null);e.setContractId(example.getContractId());e.setClassify(example.getClassify());e.setProjectId(example.getProjectId());e.setGroupId(example.getGroupId());});
+                tableInfoList.addAll(tableInfoExtra);
+                tableInfoList.sort(Comparator.comparingInt(a -> tableAllIds.indexOf(Long.parseLong(a.getPkeyId()))));
+            }
+        }
+
         try {
             this.excelTabService.formulaFillData(tableInfoList, Long.parseLong(nodeid));
             // 保存数据到数据库

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

@@ -198,7 +198,7 @@ public class FirstController extends BladeController {
 
             //获取配置的路径
             String file_path = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
-            //String file_path = "/Users/hongchuangyanfa/Desktop/";//ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
+            //String file_path = "/Users/hongchuangyanfa/Desktop/";
 
 
             //获取数据

+ 19 - 23
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/FormulaController.java

@@ -53,6 +53,9 @@ public class FormulaController {
     private final IContractInfoService contractInfoService;
     private final ITextdictInfoService textdictInfoService;
     private final IFormulaOptionService formulaOptionService;
+
+    // 合同段服务-
+    private final IWbsTreeContractService wbsTreeContractService;
     /**
      * 新增或修改
      */
@@ -162,28 +165,19 @@ public class FormulaController {
     public R<FormulaBean> detail(FormulaBean f) {
         if(f.getElementId()!=null){
             StringBuilder sb = new StringBuilder("select b.* from m_element_formula_mapping a INNER JOIN m_formula b on a.formula_id=b.id where a.element_id="+f.getElementId()+" and b.is_deleted=0 and a.scope ="+f.getScope());
-            if(Func.isNotEmpty(f.getNodeId())){
-                sb.append(" and a.node_id=").append(f.getNodeId());
-            }
-            if(Func.isNotEmpty(f.getProjectId())){
-                sb.append(" and a.project_id=").append(f.getProjectId());
-            }
+           if(StringUtils.isEquals(0,f.getScale())){
+               if(Func.isNotEmpty(f.getNodeId())){
+                   sb.append(" and a.node_id=").append(f.getNodeId());
+               }
+               if(Func.isNotEmpty(f.getProjectId())){
+                   sb.append(" and a.project_id=").append(f.getProjectId());
+               }
+           }
             List<Map<String,Object>> listMap = this.jdbcTemplate.queryForList(sb.toString());
             if(Func.isNotEmpty(listMap)){
                 Map<String,Object> map =listMap.get(0);
                 String rely = StringUtils.handleNull(map.get("rely"));
                 FormulaBean fb=BeanUtil.toBean(map,FormulaBean.class);
-//                if(StringUtils.isNotEmpty(rely)){
-//                    String[] relyArr = rely.split(StringPool.COMMA);
-//                   List<Map<String,Object>> mapList =this.jdbcTemplate.queryForList("select CONCAT(a.tab_en_name,':',b.e_key) ekey,a.tab_ch_name tableName,b.e_name ename  ,b.e_length elength,c.dict_value type f" +
-//                           "rom m_table_info a JOIN m_wbs_form_element b on a.id=b.f_id  " +
-//                           "LEFT JOIN (select dict_key, dict_value from blade_dict where code ='data_type' and parent_id > 0 and is_sealed = 0 and is_deleted = 0 )c on b.e_type=c.dict_key" +
-//                           " where  a.tab_en_name in( "+ Arrays.stream(relyArr).map(e->e.split(StringPool.COLON)[0]).distinct().collect(Collectors.joining(StringPool.COMMA,"'","'"))+")");
-//                   if(ListUtils.isNotEmpty(mapList)){
-//                       fb.setDict(mapList.stream().filter(e-> Arrays.stream(relyArr).anyMatch(c->StringUtils.isEquals(e.get("ekey"),c))).collect(Collectors.toMap(e->StringUtils.handleNull(e.get("ekey")), e->e)));
-//                   }
-//
-//                }
                 fb.setDict(this.service.getElementInfoByCodes(rely));
                 return R.data(fb);
             }
@@ -304,8 +298,10 @@ public class FormulaController {
                         break;
                     }
                 }
-                if(data.size()>dw.length-start){
-                    result.put("more",data.stream().skip(dw.length-start).map(StringUtils::handleNull).collect(Collectors.joining(StringPool.SEMICOLON)));
+                if(data.size()>dw.length){
+                  //  String moreData = data.stream().skip(dw.length).map(StringUtils::handleNull).collect(Collectors.joining(StringPool.SEMICOLON));
+                    // 频率添加表单
+                    this.wbsTreeContractService.addTabInfoByRan(info,data,dw.length);
                 }
             }
             /*保存实测值参数*/
@@ -332,11 +328,11 @@ public class FormulaController {
             "'value': [\n" +
             "{\n" +
             "'label': '是',\n" +
-            "'value': 1\n" +
+            "'value': '1'" +
             "},\n" +
             "{\n" +
-            "'label': '否',\n" +
-            "'value': 0\n" +
+            "'label': '否'," +
+            "'value': '0'" +
             "}\n" +
             "]\n" +
             "}\n" +
@@ -349,7 +345,7 @@ public class FormulaController {
              Map<String,Object> result = new LinkedHashMap<>();
              String  key=fo.getKey().replaceAll("__[\\d_]+","");
               ContractInfo contract = this.contractInfoService.getById(fo.getContractId());
-              List<KeyMapper> kms =  this.service.getKeyMapperList(Collections.singletonList(fo.getPkeyId()),contract.getPId());
+              List<KeyMapper> kms =  this.service.getKeyMapperList(Collections.singletonList(fo.getPkeyId()),contract.getPId(),"");
               KeyMapper keyMapper=null;
               if(Func.isNotEmpty(kms)){
                 Optional<KeyMapper> optionalKeyMapper=  kms.stream().filter(e->StringUtils.isEquals(e.getField(),key)).findFirst();

+ 2 - 10
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ProjectInfoController.java

@@ -1,27 +1,20 @@
 package org.springblade.manager.controller;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.google.common.collect.Lists;
 import io.swagger.annotations.*;
 import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
 import lombok.AllArgsConstructor;
 
 import javax.validation.Valid;
 
-import org.apache.commons.lang.StringUtils;
-import org.springblade.core.log.exception.ServiceException;
 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.Func;
-import org.springblade.manager.dto.SaveUserInfoByProjectDTO;
 import org.springblade.manager.dto.WbsTreeContractDTO;
 import org.springblade.manager.dto.ProjectInfoDTO;
 import org.springblade.manager.entity.ContractInfo;
-import org.springblade.manager.entity.WbsTreePrivate;
 import org.springblade.manager.service.*;
 import org.springblade.manager.vo.*;
-import org.springframework.context.annotation.Bean;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.web.bind.annotation.*;
@@ -30,10 +23,8 @@ import org.springblade.manager.entity.ProjectInfo;
 import org.springblade.manager.wrapper.ProjectInfoWrapper;
 import org.springblade.core.boot.ctrl.BladeController;
 
-import java.rmi.ServerException;
 import java.util.List;
 import java.util.Map;
-import java.util.stream.Collectors;
 
 @RestController
 @AllArgsConstructor
@@ -202,7 +193,8 @@ public class ProjectInfoController extends BladeController {
      * 项目、合同段私有库wbs节点Tree加载
      * (项目私有wbs设置界面,左侧加载可用,
      * 项目分配wbs初始化时,右侧展示当前项目id的私有节点,左侧则展示的是分配wbs树保存后引用的哪个项目id下的私有树
-     * 合同段分配wbs时进入默认加载左侧节点树可用)
+     * 合同段分配wbs时进入默认加载左侧节点树可用
+     * 试验设备使用管理中,检测项目使用)
      */
     @GetMapping("/tree")
     @ApiOperationSupport(order = 11)

+ 15 - 15
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsParamController.java

@@ -20,12 +20,8 @@ import org.springblade.core.tool.utils.RegexUtil;
 import org.springblade.manager.dto.FormulaBean;
 import org.springblade.manager.dto.ParamElements;
 import org.springblade.manager.dto.WbsParamBean;
-import org.springblade.manager.entity.ElementFormulaMapping;
-import org.springblade.manager.entity.Formula;
-import org.springblade.manager.entity.WbsParam;
-import org.springblade.manager.service.IElementFormulaMappingService;
-import org.springblade.manager.service.IFormulaService;
-import org.springblade.manager.service.IWbsParamService;
+import org.springblade.manager.entity.*;
+import org.springblade.manager.service.*;
 import org.springblade.manager.vo.ParamBean;
 import org.springblade.manager.vo.ParamSearch;
 import org.springblade.manager.wrapper.WbsParamWrapper;
@@ -51,6 +47,7 @@ public class WbsParamController {
     private final JdbcTemplate jdbcTemplate;
     private final IFormulaService formulaService;
     private final IElementFormulaMappingService elementFormulaMappingService;
+    private final IWbsTreeService wbsTreeService;
 
     /**
      * 保存或修改
@@ -114,7 +111,7 @@ public class WbsParamController {
                         }else if(pb.isPrivate()){
                             elementMap= this.jdbcTemplate.queryForList(
                                     "select c.e_name as name ,c.id from m_wbs_tree_private a " +
-                                            "inner join m_wbs_tree_private b on a.id=b.parent_id " +
+                                            "inner join m_wbs_tree_private b on (a.id=b.parent_id and a.wbs_id=b.wbs_id) " +
                                             "inner join m_wbs_form_element c on  b.init_table_id=c.f_id " +
                                             "where  b.project_id="+pb.getProjectId()+" and a.p_key_id="+pb.getNodeId()+"  and b.is_deleted=0 and c.is_deleted=0 ");
                         }
@@ -129,7 +126,7 @@ public class WbsParamController {
                                 keyMap.put("name",e.getName());
                                 keyMap.put("id",e.getId().toString());
                                 tmpMap.put(e.getK(),keyMap);
-                                if(RegexUtil.match(ParamElements.LEVEL_REG,e.getV())){
+                                if(RegexUtil.match(ParamElements.LEVEL_REG,e.getV().trim())){
                                     /*取层级*/
                                     formula.setFormula("FC.tree(trees,WP["+e.getK()+"])");
                                 }else{
@@ -140,7 +137,7 @@ public class WbsParamController {
                                 this.formulaService.save(formula);
                                 tmpMap.clear();
                                 finalElementMap.forEach(m->{
-                                    if(m.get("name").toString().contains(e.getName())){
+                                    if(StringUtils.handleNull(m.get("name")).contains(e.getName())){
                                         ElementFormulaMapping efm = new ElementFormulaMapping();
                                         efm.setScope(FormulaBean.PARAM);
                                         efm.setParamId(e.getId());
@@ -262,6 +259,8 @@ public class WbsParamController {
                             "where c.is_deleted=0 and a.is_deleted=0 and a.parent_id="+ps.getNodeId()+" and c.param_id ="+ps.getParamId()+")as BB " +
                             "on AA.id=BB.id"));
         }else if(ParamSearch.PRI.equals(ps.getScopeType())){
+           List<Map<String,Object>> listMaps=  this.jdbcTemplate.queryForList("select b.wbs_id wbsId from m_wbs_param a join m_wbs_tree_private b on a.node_id=b.p_key_id where a.id= "+ps.getParamId());
+            String wbsId = StringUtils.handleNull(listMaps.get(0).get("wbsId"));
             return R.data(this.jdbcTemplate.queryForList(
                     "select AA.id,AA.tableName,BB.elementName,BB.mappingId from (" +
                     "        select id ,node_name AS tableName,init_table_id" +
@@ -270,8 +269,9 @@ public class WbsParamController {
                     "          AND is_deleted = 0" +
                     "          AND parent_id = " +ps.getNodeId()+
                     "          AND project_id = " +ps.getProjectId()+
+                    "          AND wbs_id= "+wbsId+
                     "        ORDER BY wt.sort, wt.node_name, wt.create_time) as AA left join (select a.id as id, b.e_name as elementName ,c.id as mappingId,c.is_deleted from m_wbs_tree_private a inner join m_wbs_form_element b on b.f_id=a.init_table_id inner join  m_element_formula_mapping  c on c.element_id=b.id " +
-                            "where  a.project_id="+ps.getProjectId()+" and c.is_deleted=0 and a.is_deleted=0 and a.parent_id="+ps.getNodeId()+" and c.param_id ="+ps.getParamId()+")as BB on AA.id=BB.id"));
+                            "where  a.project_id="+ps.getProjectId()+" and c.is_deleted=0 and a.is_deleted=0 and a.parent_id="+ps.getNodeId()+" and c.scope=35 and c.param_id ="+ps.getParamId()+" and a.wbs_id="+wbsId+" )as BB on AA.id=BB.id"));
         }
         return R.fail("暂无数据");
     }
@@ -299,7 +299,7 @@ public class WbsParamController {
             keyMap.put("name",param.getName());
             keyMap.put("id",param.getId().toString());
             tmpMap.put(param.getK(),keyMap);
-            if(RegexUtil.match(ParamElements.LEVEL_REG,param.getV())){
+            if(RegexUtil.match(ParamElements.LEVEL_REG,param.getV().trim())){
                 /*取层级*/
                 formula.setFormula("FC.tree(trees,WP["+param.getK()+"])");
             }else{
@@ -340,12 +340,12 @@ public class WbsParamController {
                     /*project*/
                     elementMap= this.jdbcTemplate.queryForList(
                             "select c.e_name as name ,c.id from m_wbs_tree_private a " +
-                                    "inner join m_wbs_tree_private b on a.id=b.parent_id " +
+                                    "inner join m_wbs_tree_private b on (a.id=b.parent_id and a.wbs_id=b.wbs_id) " +
                                     "inner join m_wbs_form_element c on  b.init_table_id=c.f_id " +
                                     "where  b.project_id="+projectId+" and a.p_key_id="+nodeId+"  and b.is_deleted=0 and c.is_deleted=0 ");
                 }
 
-                List<Long> longList=this.jdbcTemplate.queryForList("select element_id from m_element_formula_mapping where param_id in("+paramList.stream().map(WbsParam::getId).map(String::valueOf).collect(Collectors.joining(","))+")",Long.class);
+                List<Long> longList=this.jdbcTemplate.queryForList("select element_id from m_element_formula_mapping where is_deleted=0 and scope=35 and param_id in("+paramList.stream().map(WbsParam::getId).map(String::valueOf).collect(Collectors.joining(","))+")",Long.class);
                 if(Func.isNotEmpty(elementMap)){
                     Map<String,Object> tmpMap=new HashMap<>();
                     List<Map<String, Object>> finalElementMap = elementMap;
@@ -359,7 +359,7 @@ public class WbsParamController {
                             keyMap.put("name",e.getName());
                             keyMap.put("id",e.getId().toString());
                             tmpMap.put(e.getK(),keyMap);
-                            if(RegexUtil.match(ParamElements.LEVEL_REG,e.getV())){
+                            if(RegexUtil.match(ParamElements.LEVEL_REG,e.getV().trim())){
                                 /*取层级*/
                                 formula.setFormula("FC.tree(trees,WP["+e.getK()+"])");
                             }else{
@@ -373,7 +373,7 @@ public class WbsParamController {
                         Formula finalFormula = formula;
                         String name=e.getName().replace("【水】","").trim();
                         finalElementMap.forEach(m->{
-                            if(m.get("name").toString().contains(name)){
+                            if(StringUtils.handleNull(m.get("name")).contains(name)){
                                 /*匹配名称,且该元素没有绑定任何节点参数公式*/
                                 if(longList.stream().noneMatch(k->StringUtils.isEquals(k,m.get("id")))){
                                     ElementFormulaMapping efm = new ElementFormulaMapping();

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

@@ -382,6 +382,18 @@ public class WbsTreePrivateController extends BladeController {
     }
 
 
+    @PostMapping("/self/trial/getMixRatioTestTree")
+    @ApiOperationSupport(order = 5)
+    @ApiOperation(value = "获取当前节点的试验配合比树", notes = "传入当前节点的pKeyId")
+    public R<List<WbsTreePrivateVO>> getMixRatioTestTree(String pKeyId) {
+        List<WbsTreePrivateVO> tree = wbsTreePrivateService.getMixRatioTestTree(pKeyId);
+        if (tree != null && tree.size() > 0) {
+            return R.data(tree);
+        }
+        return R.fail(200, "未查询到信息");
+    }
+
+
     /**
      * 获取当前节点详情
      */

+ 19 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/formula/ITurnPointCalculator.java

@@ -1,8 +1,11 @@
 package org.springblade.manager.formula;
 
+import com.mixsmart.utils.CustomFunction;
 import com.mixsmart.utils.ListUtils;
 import com.mixsmart.utils.StringUtils;
 import org.springblade.core.tool.utils.Func;
+import org.springblade.manager.formula.impl.TableElementConverter;
+
 import java.math.BigDecimal;
 import java.util.*;
 import java.util.stream.Collectors;
@@ -16,7 +19,7 @@ import static org.springblade.manager.formula.TurnPoint.*;
 public interface ITurnPointCalculator {
 
 
-     static List<Object> create( List<Map<String,Object>> data, LinkedHashMap<String,String> configMap){
+     static List<Object> create( List<Map<String,Object>> data, LinkedHashMap<String,String> configMap,Map<String,Object> g8){
         if(Func.isNotEmpty(data)&&configMap!=null){
                 LevelInfo levelInfo = new LevelInfo();
                 List<TurnPoint> tmp =new ArrayList<>();
@@ -24,6 +27,8 @@ public interface ITurnPointCalculator {
                     Map<String,Object>dm = data.get(i);
                     Map<String,Object> dataMap = new HashMap<>(configMap.size()*2);
                     TurnPoint tp = new TurnPoint(levelInfo,dataMap);
+                    /*V判断*/
+                    tp.setVertical(StringUtils.isEquals(1,dm.get("vertical")));
                     for(Map.Entry<String,String> kv:configMap.entrySet()){
                         String key =kv.getKey();
                         String field =kv.getValue();
@@ -86,6 +91,8 @@ public interface ITurnPointCalculator {
                 }
                 List<TurnPoint> result=fill(tmp);
                 if(ListUtils.isNotEmpty(result)){
+                    /*V判断*/
+                    forG8(result,g8);
                     return result.stream().map(TurnPoint::getDataMap).flatMap(m->{
                         List<String> list =new ArrayList<>();
                         for(String key:configMap.keySet()){
@@ -197,5 +204,16 @@ public interface ITurnPointCalculator {
         }
         return Collections.emptyList();
     }
+     static void forG8(List<TurnPoint> data,Map<String,Object> g8){
+             g8.put("dx",data.stream().filter(e->TurnPoint.CE.equals(e.getType())).map(tp-> CustomFunction.xN(tp.getDx(),1000)).collect(Collectors.toList()));
+             g8.put("dxv",data.stream().filter(e->TurnPoint.CE.equals(e.getType())&&e.getVertical()).map(tp-> CustomFunction.xN(tp.getDx(),1000)).collect(Collectors.toList()));
+             g8.put("dxnv",data.stream().filter(e->TurnPoint.CE.equals(e.getType())&&!e.getVertical()).map(tp-> CustomFunction.xN(tp.getDx(),1000)).collect(Collectors.toList()));
+             g8.put("sc",data.stream().filter(e->TurnPoint.CE.equals(e.getType())).map(TurnPoint::getSc).collect(Collectors.toList()));
+             g8.put("scv",data.stream().filter(e->TurnPoint.CE.equals(e.getType())&&e.getVertical()).map(TurnPoint::getSc).collect(Collectors.toList()));
+             g8.put("scnv",data.stream().filter(e->TurnPoint.CE.equals(e.getType())&&!e.getVertical()).map(TurnPoint::getSc).collect(Collectors.toList()));
+             g8.put("sj",data.stream().filter(e->TurnPoint.CE.equals(e.getType())).map(TurnPoint::getSj).collect(Collectors.toList()));
+             g8.put("sjv",data.stream().filter(e->TurnPoint.CE.equals(e.getType())&&e.getVertical()).map(TurnPoint::getSj).collect(Collectors.toList()));
+             g8.put("sjnv",data.stream().filter(e->TurnPoint.CE.equals(e.getType())&&!e.getVertical()).map(TurnPoint::getSj).collect(Collectors.toList()));
+     }
 
 }

+ 11 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/formula/TurnPoint.java

@@ -67,6 +67,9 @@ public class TurnPoint {
 
     private Map<String,Object> dataMap;
 
+    /**垂直方向*/
+    private Boolean vertical;
+
 
     public TurnPoint(LevelInfo levelInfo, Map<String, Object> dataMap) {
         this.levelInfo = levelInfo;
@@ -76,6 +79,7 @@ public class TurnPoint {
     public TurnPoint() {
     }
 
+
     public String getName() {
         return name;
     }
@@ -334,4 +338,11 @@ public class TurnPoint {
         return StringUtils.isEquals(CE,this.type);
   }
 
+    public Boolean getVertical() {
+        return vertical;
+    }
+
+    public void setVertical(Boolean vertical) {
+        this.vertical = vertical;
+    }
 }

+ 11 - 10
blade-service/blade-manager/src/main/java/org/springblade/manager/formula/impl/FormulaMileage.java

@@ -1,26 +1,22 @@
 package org.springblade.manager.formula.impl;
 
 import com.jfireel.expression.Expression;
-import com.mixsmart.utils.CustomFunction;
 import com.mixsmart.utils.FormulaUtils;
 import com.mixsmart.utils.ListUtils;
 import com.mixsmart.utils.StringUtils;
 import lombok.Data;
 import org.springblade.business.feign.MileageClient;
-import org.springblade.common.utils.BaseUtils;
 import org.springblade.core.tool.utils.Func;
-import org.springblade.core.tool.utils.StringPool;
-import org.springblade.manager.bean.TableInfo;
 import org.springblade.manager.dto.ElementData;
 import org.springblade.manager.dto.FormData;
 import org.springblade.manager.entity.Formula;
+import org.springblade.manager.entity.WbsTreeContract;
 import org.springblade.manager.formula.FormulaStrategy;
 import org.springblade.manager.formula.KeyMapper;
 import org.springblade.manager.formula.Mileage;
 import org.springframework.stereotype.Component;
 
 import java.util.*;
-import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
@@ -75,7 +71,6 @@ public class FormulaMileage implements FormulaStrategy {
                 mileage.setValue(0, ed.stringValue());
                 Long pkeyId=tableInfoIds.get(ed.getIndex());
                 String findStr="OP['"+cur.getTableName()+"']['"+pkeyId+"@"+cur.getKey()+"__"+ed.getY()+"_"+ed.getX()+"']['TF']";
-                String flag=StringUtils.handleNull(Expression.parse(findStr).calculate(tec.getConstantMap()));
                 mileage.setVertical(StringUtils.isEquals(1,StringUtils.handleNull(Expression.parse(findStr).calculate(tec.getConstantMap()))));
                 row.put(line0.getCode(), ed);
                 for (int j = 1; j < relyList.size(); j++) {
@@ -90,14 +85,13 @@ public class FormulaMileage implements FormulaStrategy {
 
                 }
                 mileageList.add(mileage);
-
             }
+
         }
         if(Func.isNotEmpty(mileageList)){
               List<String>  zhpw =mileageList.stream().filter(Mileage::isChecked).map(Mileage::getZhPw).collect(Collectors.toList());
             Map<String,String[]> coordinateMap  =  mileageClient.mileage2Coordinate(zhpw,Func.toLong(tec.getConstantMap().get("contractId")));
             /*G10缓存对象*/
-            tec.getConstantMap().put("G10",new Object());
             if(coordinateMap.size()>0){
                 mileageList.forEach(m->{
                     String[] coordinate = coordinateMap.get(m.getZhPw());
@@ -118,7 +112,7 @@ public class FormulaMileage implements FormulaStrategy {
                     }
                 });
                 data.forEach(e->{e.setUpdate(1);e.setFinished(Boolean.TRUE);});
-
+                forG10(mileageList,tec);
             }
 
         }
@@ -126,7 +120,14 @@ public class FormulaMileage implements FormulaStrategy {
     }
     public static final Pattern MILE_P = Pattern.compile("(?<=T\\(com.mixsmart.utils.CustomFunction\\).MILE\\()([^,]+),([^,]+)(?=,)");
 
-
+    public void forG10(List<Mileage> data,TableElementConverter tec){
+          if(Func.isNotEmpty(data)){
+              Map<String,Object> g10 = (Map<String, Object>) tec.getConstantMap().computeIfAbsent("G10", k->new HashMap<>());
+              g10.put("dx",data.stream().map(Mileage::getDx).collect(Collectors.toList()));
+              g10.put("dxnv",data.stream().filter(e->!e.getVertical()).map(Mileage::getDx).collect(Collectors.toList()));
+              g10.put("dxv",data.stream().filter(Mileage::getVertical).map(Mileage::getDx).collect(Collectors.toList()));
+          }
+    }
 
     public void write( LinkedHashMap<String,ElementData> row,List<Object>data,List<String> keys,List<String> scale3){
               if(ListUtils.isNotEmpty(data)){

+ 13 - 9
blade-service/blade-manager/src/main/java/org/springblade/manager/formula/impl/FormulaTurnPoint.java

@@ -1,6 +1,7 @@
 package org.springblade.manager.formula.impl;
 
 import cn.hutool.core.util.ReUtil;
+import com.jfireel.expression.Expression;
 import com.mixsmart.utils.FormulaUtils;
 import com.mixsmart.utils.StringUtils;
 import lombok.Data;
@@ -8,8 +9,7 @@ import org.springblade.core.tool.utils.Func;
 import org.springblade.manager.dto.ElementData;
 import org.springblade.manager.dto.FormData;
 import org.springblade.manager.entity.Formula;
-import org.springblade.manager.formula.FormulaStrategy;
-import org.springblade.manager.formula.ITurnPointCalculator;
+import org.springblade.manager.formula.*;
 import org.springframework.stereotype.Component;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -60,6 +60,7 @@ public class FormulaTurnPoint implements FormulaStrategy {
             for(int i=0;i<KEYS.size();i++){
                 configMap.put(KEYS.get(i),this.args.get(i));
             }
+            List<Long> tableInfoIds= tec.getKeyMappers().stream().filter(k->k.getTableName().equals(cur.getTableName())).map(KeyMapper::getPkId).distinct().collect(Collectors.toList());
             while (cda.hasNext()) {
                 LinkedHashMap<String, ElementData> map = cda.next();
                 if(!map.get(configMap.get(KEYS.get(0))).isEmpty()){
@@ -67,25 +68,28 @@ public class FormulaTurnPoint implements FormulaStrategy {
                     KEYS.forEach(k->{
                         ElementData ed = map.get(c(k));
                         tmp.put(configMap.get(k),ed.stringValue());
+                        /*V判断*/
+                        if(CD.equals(k)){
+                            Long pkeyId=tableInfoIds.get(ed.getIndex());
+                            String findStr="OP['"+cur.getTableName()+"']['"+pkeyId+"@"+cur.getKey()+"__"+ed.getY()+"_"+ed.getX()+"']['TF']";
+                            tmp.put("vertical",StringUtils.handleNull(Expression.parse(findStr).calculate(tec.getConstantMap())));
+                        }
+
                     });
                     tableData.add(tmp);
                 }
             }
-           List<Object> data= ITurnPointCalculator.create(tableData,configMap);
+            Map<String,Object> g8 = (Map<String, Object>) tec.getConstantMap().computeIfAbsent("G8", k->new HashMap<>());
+           List<Object> data= ITurnPointCalculator.create(tableData,configMap,g8);
             if(Func.isNotEmpty(data)){
                 AtomicInteger ai = new AtomicInteger();
                 Map<Integer,List<Object>> dataMap = data.stream().collect(Collectors.groupingBy(e->ai.getAndAdd(1)%configMap.size()));
                 ai.set(0);
                 dataSourceMap.forEach((k,v)->{
                     List<Object> dl =dataMap.get(ai.getAndIncrement());
-//                    List<ElementData> list = v.getValues();
                     v.setUpdate(1);
                     v.setFinished(Boolean.TRUE);
-                    FormulaUtils.write(v,dl);
-//                    for(int n=0;n<dl.size();n++){
-//                        ElementData ed = list.get(n);
-//                        ed.setValue(dl.get(n));
-//                    }
+                    FormulaUtils.write(v,dl,true);
                 });
             }
 

+ 82 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/formula/impl/SubTable.java

@@ -0,0 +1,82 @@
+package org.springblade.manager.formula.impl;
+
+import com.mixsmart.utils.FormulaUtils;
+import com.mixsmart.utils.StringUtils;
+import lombok.Data;
+import org.springblade.manager.dto.ElementData;
+import org.springblade.manager.dto.FormData;
+
+import java.util.*;
+import java.util.logging.Handler;
+import java.util.stream.Collectors;
+
+/**
+ * @author yangyj
+ * @Date 2023/3/25 10:58
+ * @description TODO
+ */
+@Data
+public class SubTable {
+    public static  final String ITEM="检查项目";
+    public static  final String DESIGN="设计值";
+    public static  final String DATA="检验结果";
+    public static  final Integer[] STEP=new Integer[]{15,15,1};
+    public static final  List<String> KEYS= Arrays.asList(ITEM,DESIGN,DATA);
+    public static final  Integer ROW_SIZE=15;
+    private LinkedHashMap<String, List<String>> group=new LinkedHashMap<>();
+    private FormData itemName;
+    private FormData design;
+    private FormData data;
+
+
+    public SubTable() {
+    }
+    public SubTable(List<FormData> source) {
+        if(source!=null&&source.size()>0){
+            source.stream().filter(e->KEYS.contains(e.getEName().trim())).forEach(fd->{
+                fd.getValues().forEach(e->e.setValue(null));
+                switch (KEYS.indexOf(fd.getEName().trim())){
+                    case 0:itemName=fd;break;
+                    case 1:design=fd;break;
+                    case 2:data=fd;break;
+                    default:break;
+                }
+            });
+        }
+    }
+    public boolean checked(){
+        return itemName != null && design != null && data != null;
+    }
+
+   public void put(String key, List<ElementData> data){
+        if(data!=null&&data.size()>0){
+            group.put(key,data.stream().map(ElementData::stringValue).filter(StringUtils::isNotEmpty).collect(Collectors.toList()));
+        }
+   }
+
+   public void flush(){
+           if(group.size()>0){
+               List<String> itemNameList=new ArrayList<>();
+               List<String> designList=new ArrayList<>();
+               List<String> dataList = new ArrayList<>();
+               for(Map.Entry<String,List<String>> entry:group.entrySet()){
+                   String key = entry.getKey();
+                   String[] nameAndDesign=key.split("@");
+                   List<String> values=entry.getValue();
+                   int count = (int)Math.ceil((double)values.size()/(double)ROW_SIZE);
+                   int count2=count/STEP[0];
+                   itemNameList.addAll(Collections.nCopies(count2,nameAndDesign[0]));
+                   designList.addAll(Collections.nCopies(count2,nameAndDesign[1]));
+                   dataList.addAll(values);
+                   if(count>values.size()){
+                       dataList.addAll(Collections.nCopies(count-values.size(),""));
+                   }
+               }
+               /*写入元素*/
+               FormulaUtils.write(itemName,itemNameList,true);
+               FormulaUtils.write(design,designList,true);
+               FormulaUtils.write(data,dataList,true);
+           }
+   }
+
+}

+ 1 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/formula/impl/TableElementConverter.java

@@ -37,6 +37,7 @@ public class TableElementConverter implements ITableElementConverter {
 
     private List<TableInfo> tableInfoList;
     private Long contractId;
+    private Long projectId;
     private Long nodeId;
     private Long wbsTreeId;
     List<KeyMapper> keyMappers;

+ 5 - 3
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ArchiveTreeMapper.java

@@ -25,7 +25,7 @@ public interface ArchiveTreeMapper extends BaseMapper<ArchiveTree> {
 
     /**
      * 自动组卷规则设置节点下所有子节点
-     * @param tree
+     * @param
      * @return
      */
     int updateAllSonNodeIdsForArchiveAutoRule(@Param("archiveAutoType") Integer archiveAutoType,
@@ -35,7 +35,7 @@ public interface ArchiveTreeMapper extends BaseMapper<ArchiveTree> {
 
     /**
      * 删除立卷规则设置
-     * @param tree
+     * @param
      * @return
      */
     int removeAllSonNodeIdsForArchiveAutoRule_1(@Param("archiveAutoType") Integer archiveAutoType,
@@ -51,6 +51,8 @@ public interface ArchiveTreeMapper extends BaseMapper<ArchiveTree> {
      * @param groupId
      * @return
      */
-    List<ArchiveTreeAutoRuleVO> getAllSonNodeforGroupView(@Param("ancestors")String ancestors, @Param("groupId")Long groupId);
+    List<ArchiveTreeAutoRuleVO> getAllSonNodeforGroupView(@Param("ancestors")String ancestors,
+                                                          @Param("groupId")Long groupId,
+                                                          @Param("bigNodeID")Long bigNodeID);
 
 }

+ 6 - 5
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ArchiveTreeMapper.xml

@@ -293,20 +293,20 @@
 
         update m_archive_tree
         set
-        archive_auto_type= #{archiveAutoType},
+        archive_auto_type= #{archiveAutoType}
         <if test="archiveAutoType ==2 ">
-            archive_auto_group_id=#{archiveAutoGroupId},
+            ,archive_auto_group_id=#{archiveAutoGroupId},
             archive_auto_group_select=0
         </if>
         where
         is_deleted = 0 and ancestors like concat('', #{ancestors}, '%')
         /*最高并卷规则不能覆盖 分类并卷规则,单独组卷规则*/
         <if test="archiveAutoType ==1 ">
-            and archive_auto_type != 2 and archive_auto_type != 3
+            and (archive_auto_type != 2 and archive_auto_type != 3 or archive_auto_type is null)
         </if>
         /*分类并卷规则不能覆盖单独组卷规则*/
         <if test="archiveAutoType ==2 ">
-            and archive_auto_type != 3
+            and (archive_auto_type != 3 or archive_auto_type is null)
         </if>
     </update>
 
@@ -379,10 +379,11 @@
         FROM m_archive_tree
         where is_deleted = 0
           and ancestors like concat('', #{ancestors}, '%')
-          and archive_auto_type !=3
+          and (archive_auto_type !=3 or archive_auto_type is null)
           and id not in (
                 select id from m_archive_tree where archive_auto_type=2 and archive_auto_group_id != #{groupId}
             )
+          or id=#{bigNodeID}
         order by ancestors asc,sort asc
     </select>
 

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

@@ -217,7 +217,7 @@
         SET sort = #{sort}
         WHERE p_key_id = #{pKeyId}
           AND type = 2
-          AND status = 1
+          -- AND status = 1
           AND is_deleted = 0
     </update>
 

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

@@ -73,5 +73,4 @@ public interface IContractInfoService extends BaseService<ContractInfo> {
     Map<String, Object> trialRelationTree(String wbsId, String projectId, String contractId, String selfId);
 
     Map<Long, List<WbsTreeContractTreeAllVO>> treeAllJL(String contractId, Integer type);
-
 }

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

@@ -106,7 +106,7 @@ public interface IExcelTabService extends BaseService<ExcelTab> {
     Map<String, String> getTablbCols(String pkeyid, String colkey) throws FileNotFoundException;
 
     // 获取用户端 单个表单接口数据
-    R getBussDataInfo(Long pkeyId);
+    R getBussDataInfo(Long pkeyId,int type);
 
     // 单个pdf 生成
     R getBussPdfInfo(Long pkeyId) throws Exception;

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

@@ -34,6 +34,6 @@ public interface IFormulaService extends BaseService<Formula> {
     void format();
 
     List<Formula> getFormulaList(List<KeyMapper> keyMapperList);
-    List<KeyMapper> getKeyMapperList(List<Long> ids,String projectId);
+    List<KeyMapper> getKeyMapperList(List<Long> ids,String projectId,String nodeId);
     Map<String,Object> getElementInfoByCodes(String codes);
 }

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

@@ -18,6 +18,7 @@ package org.springblade.manager.service;
 
 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.TextdictDataInfoVO;
 import org.springblade.manager.vo.TextdictInfoVO;
@@ -42,7 +43,4 @@ public interface ITextdictInfoService extends IService<TextdictInfo> {
 	IPage<TextdictInfoVO> selectTextdictInfoPage(IPage<TextdictInfoVO> page, TextdictInfoVO textdictInfo);
 
 	void deleDataInfoById(String id);
-
-
-
 }

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

@@ -1,6 +1,7 @@
 package org.springblade.manager.service;
 
 import org.springblade.core.mp.base.BaseService;
+import org.springblade.manager.dto.RangeInfo;
 import org.springblade.manager.dto.WbsTreeContractDTO;
 import org.springblade.manager.dto.WbsTreeContractDTO2;
 import org.springblade.manager.entity.ContractRelationJlyz;
@@ -9,6 +10,7 @@ import org.springblade.manager.entity.WbsTreePrivate;
 import org.springblade.manager.vo.*;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.List;
 import java.util.Map;
@@ -51,4 +53,7 @@ public interface IWbsTreeContractService extends BaseService<WbsTreeContract> {
 
     // 查询隐蔽工程节点
     List<WbsContractNodeVo> appSearchConcealedNodes(long primaryKeyId, Long contractId);
+
+    // 频率设计值  添加表单
+    boolean addTabInfoByRan(RangeInfo info,List<Object> moreData,Integer excLenght) throws FileNotFoundException;
 }

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

@@ -82,4 +82,6 @@ public interface IWbsTreePrivateService extends BaseService<WbsTreePrivate> {
     //批量重新保存文件htmlUrl
     void batchResetHtmlUrl(List<WbsTreePrivate> wbsTreePrivateList) throws IOException, InterruptedException;
 
+    List<WbsTreePrivateVO> getMixRatioTestTree(String pKeyId);
+
 }

+ 46 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ArchiveAutoRuleWbsServiceImpl.java

@@ -38,4 +38,50 @@ public class ArchiveAutoRuleWbsServiceImpl extends BaseServiceImpl<ArchiveAutoRu
 		return page.setRecords(baseMapper.selectArchiveAutoRuleWbsPage(page, archiveAutoRuleWbs));
 	}
 
+	public void archiveAutoMethod(){
+		//步骤一:把项目下未锁定的案卷拆卷。
+		//步骤二:查询归档树节点。存在未归档文件的节点。
+		//步骤三:遍历归档树节点整理出 默认规则节点,分类并卷节点,单独组卷节点 三个集合。
+		//步骤四:按照单独,分类,默认的顺序执行组卷流程。
+	}
+
+	/**
+	 * 单租组卷流程  节点下的文件只在当前节点下组卷
+	 */
+	private void archiveAutoMethod3(){
+		//步骤1:遍历节点集合
+		//步骤2:获取当前节点的案卷规格
+		//步骤3:查询节点下的未归档文件
+		//步骤4:遍历未归档文件
+		//步骤5:判断文件是否存在分盒设置-》走分盒组卷流程
+		//步骤6:计算和判断待组卷文件集合是否达到组卷要求,达到要求创建案卷,案卷归属当前节点,案卷下文件改为已组卷
+	}
+
+	/**
+	 * 分类并卷组卷  设置分类的节点下只有一个案卷,节点下的所有文件都组成这个案卷。如果设置分类节点(select=1的)多个,案卷归属排序第一个节点。
+	 */
+	private void archiveAutoMethod2(){
+		//步骤1:遍历节点集合
+		//步骤2:查询节点下的未归档文件
+		//步骤4:遍历未归档文件
+		//步骤5:判断文件是否存在分盒设置-》走分盒组卷流程
+		//步骤6:将文件按照<groupId,List<文件>>放入集合
+		//步骤7:将文件按照<groupId,List<文件>>放入集合
+		//步骤8:按集合创建案卷,每个group类的案卷归属顺序排第一个节点
+	}
+
+	/**
+	 * 默认组卷流程 文件可以跨节点组卷,受最高并卷节点限制范围,跨节点文件组卷时,案卷规格按照第一个文件所在的节点规格 组卷。
+	 */
+	private void archiveAutoMethod1(){
+		//步骤1:遍历节点集合
+		//步骤2:保存当前节点的最高并卷节点archiveAutoNodeId到变量A,用来限制向上级跨节点组卷。
+		//步骤3:判断变量A是否与当前节点archiveAutoNodeId相同,不同的话(相当于当前节点已跳出最高并卷节点)直接将内存中文件集合List中的文件组卷(这些是属于上一个最高并卷节点的文件),并清空list文件集合
+		//步骤4:获取当前节点的组卷规格
+		//步骤5:查询节点下的未归档文件
+		//步骤6:遍历未归档文件
+		//步骤7:判断文件是否存在分盒设置-》走分盒组卷流程
+		//步骤8:计算和判断文件集合list里是否达到组卷规格,达到创建案卷 并清空集合list。 跨节点文件组卷,案卷归属于当前list中第一个文件所在节点
+	}
+
 }

+ 24 - 13
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ArchiveTreeServiceImpl.java

@@ -379,6 +379,7 @@ public class ArchiveTreeServiceImpl extends BaseServiceImpl<ArchiveTreeMapper, A
             ArchiveTreeVO2 archiveTree = new ArchiveTreeVO2();
             archiveTree.setTitle(wbsTreeVO2.getTitle());
 
+            archiveTree.setIswbsNode(true);
             archiveTree.setId(wbsTreeVO2.getId());
             archiveTree.setParentId(wbsTreeVO2.getParentId());
             archiveTree.setExtId(wbsTreeVO2.getId());
@@ -434,7 +435,7 @@ public class ArchiveTreeServiceImpl extends BaseServiceImpl<ArchiveTreeMapper, A
             //分类并卷规则的需要生成个随机数,作为同一个分类赋值archiveAutoNodeId
             if(archiveAutoType==2){
                 double v = Math.random() * 10000;
-                int ran = (int)v;
+                long ran = (long)v;
                 archiveAutoGroupId=Long.parseLong(System.currentTimeMillis()+""+ran);
             }
 
@@ -459,7 +460,7 @@ public class ArchiveTreeServiceImpl extends BaseServiceImpl<ArchiveTreeMapper, A
                         archiveTree.getArchiveAutoType(),
                         archiveTree.getArchiveAutoNodeId(),
                         archiveTree.getArchiveAutoGroupId(),
-                        archiveTree.getAncestors()
+                        archiveTree.getAncestors()+","+archiveTree.getId()
                 );
             }
 
@@ -482,7 +483,8 @@ public class ArchiveTreeServiceImpl extends BaseServiceImpl<ArchiveTreeMapper, A
             Long archiveAutoGroupId=null;
             //分类并卷规则的需要生成个随机数,作为同一个分类赋值archiveAutoNodeId
             if(archiveAutoType==2){
-                double ran=(Math.random()*100000000) + 1;
+                double v = Math.random() * 10000;
+                long ran = (long)v;
                 archiveAutoGroupId=Long.parseLong(System.currentTimeMillis()+""+ran);
             }
 
@@ -531,7 +533,7 @@ public class ArchiveTreeServiceImpl extends BaseServiceImpl<ArchiveTreeMapper, A
                 if(archiveAutoType==2){
                     Long groupId = dto.getArchiveAutoGroupId();
                     String selectNodeIds = dto.getSelectNodeIds();
-                    List<String> selectNodeIdlist = Arrays.asList(selectNodeIds);
+                    List<String> selectNodeIdlist = Arrays.asList(selectNodeIds.split(","));
                     //先将同一分组的节点删除配置,。
                     baseMapper.removeNodeForArchiveAutoRule_Group(groupId);
                     //然后再按照选择节点保存新的设置
@@ -548,7 +550,7 @@ public class ArchiveTreeServiceImpl extends BaseServiceImpl<ArchiveTreeMapper, A
                                 archiveTree.getArchiveAutoType(),
                                 archiveTree.getArchiveAutoNodeId(),
                                 archiveTree.getArchiveAutoGroupId(),
-                                archiveTree.getAncestors()
+                                archiveTree.getAncestors()+","+archiveTree.getId()
                         );
                     }
                 }
@@ -626,9 +628,10 @@ public class ArchiveTreeServiceImpl extends BaseServiceImpl<ArchiveTreeMapper, A
                             // 因为分类并卷规则影响范围包括下面所有子节点,如果给archive_auto_group_select=0的节点也就是范围内的子节点单独取消规则,会造成案卷归属节点错乱。
                             // (不理那么多,就这样限制先 。如业务非要发神经就要 TODO 验证节点的父节点是否为分类并卷规则,如是则取消。若无其他兄弟节点,继续往上验证。)
                             baseMapper.removeAllSonNodeIdsForArchiveAutoRule_2(node.getArchiveAutoType(),node.getAncestors());
+                        }else{
+                            returnMap.put("code","0");
+                            returnMap.put("msg","只能取消设置的节点,不能取消设置节点范围下节点");
                         }
-                        returnMap.put("code","0");
-                        returnMap.put("msg","只能取消设置的节点,不能取消设置节点范围下节点");
                     }
                     //删除节点及所有子节点 单独并卷规则
                     if(archiveAutoType==3){
@@ -653,9 +656,9 @@ public class ArchiveTreeServiceImpl extends BaseServiceImpl<ArchiveTreeMapper, A
     public Map<String,Object> getArchiveAutoRule(Long id,boolean iswbsNode) {
 
         if(iswbsNode){
-            return getArchiveAutoRule_ArchiveTreeNode(id);
-        }else{
             return getArchiveAutoRule_WbsTreeNode(id);
+        }else{
+            return getArchiveAutoRule_ArchiveTreeNode(id);
         }
     }
 
@@ -678,6 +681,9 @@ public class ArchiveTreeServiceImpl extends BaseServiceImpl<ArchiveTreeMapper, A
                     String ancestors = archiveAutoNode.getAncestors();
                     String[] ancestorssplit = ancestors.split(",");//全路径ID
                     for(String pId:ancestorssplit){
+                        if(pId.equals("0")){
+                            continue;
+                        }
                         long pIdLong = Long.parseLong(pId);
                         ArchiveTree pIdNode = baseMapper.selectById(pIdLong);
                         allName.append(pIdNode.getNodeName()+"/");
@@ -696,9 +702,10 @@ public class ArchiveTreeServiceImpl extends BaseServiceImpl<ArchiveTreeMapper, A
                     //找出当前节点大类
                     String ancestors = archiveTree.getAncestors();
                     String[] ancestorssplit = ancestors.split(",");//全路径ID
-                    String nodeAncestors = ancestorssplit[0]+","+ancestorssplit[1]; //大类的ancestors
+                    String nodeAncestors = ancestorssplit[0]+","+ancestorssplit[1]+","+ancestorssplit[2]; //大类的ancestors
+                    Long bigNodeID =Long.parseLong(ancestorssplit[2]); //大类节点ID
                     //获取大类下所有节点,过滤单独规则,其他分类并卷规则组节点
-                    List<ArchiveTreeAutoRuleVO> nodetree = ForestNodeMerger.merge(baseMapper.getAllSonNodeforGroupView(nodeAncestors, archiveTree.getArchiveAutoNodeId()));
+                    List<ArchiveTreeAutoRuleVO> nodetree = ForestNodeMerger.merge(baseMapper.getAllSonNodeforGroupView(nodeAncestors, archiveTree.getArchiveAutoNodeId(),bigNodeID));
                     //获取与当前节点设置同一分类分组的节点
                     List<ArchiveTree> listGroup= baseMapper.selectList(Wrappers.<ArchiveTree>lambdaQuery()
                             .eq(ArchiveTree::getArchiveAutoGroupId, archiveTree.getArchiveAutoGroupId())
@@ -709,9 +716,10 @@ public class ArchiveTreeServiceImpl extends BaseServiceImpl<ArchiveTreeMapper, A
                     for(ArchiveTree node:listGroup){
                         nodeSelect.append(node.getId()+",");
                     }
-                    map.put("type",archiveAutoType);
+                    map.put("archiveAutoType",archiveAutoType);
+                    map.put("archiveAutoGroupId",archiveTree.getArchiveAutoGroupId());
                     map.put("tree",nodetree);
-                    map.put("data",nodeSelect.toString());
+                    map.put("selectNodeIds",nodeSelect.toString());
                     return map;
                 }
                 if(archiveAutoType==3){
@@ -720,6 +728,9 @@ public class ArchiveTreeServiceImpl extends BaseServiceImpl<ArchiveTreeMapper, A
                     String ancestors = archiveTree.getAncestors();
                     String[] ancestorssplit = ancestors.split(",");//全路径ID
                     for(String pId:ancestorssplit){
+                        if(pId.equals("0")){
+                            continue;
+                        }
                         long pIdLong = Long.parseLong(pId);
                         ArchiveTree pIdNode = baseMapper.selectById(pIdLong);
                         allName.append(pIdNode.getNodeName()+"/");

+ 28 - 25
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ExcelTabServiceImpl.java

@@ -18,7 +18,6 @@ package org.springblade.manager.service.impl;
 
 import cn.hutool.core.date.StopWatch;
 import cn.hutool.log.StaticLog;
-import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -27,22 +26,21 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.mixsmart.utils.ListUtils;
 import com.mixsmart.utils.RegexUtils;
-import com.spire.xls.*;
 import com.spire.xls.CellRange;
 import com.spire.xls.Workbook;
+import com.spire.xls.*;
 import lombok.AllArgsConstructor;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang3.ObjectUtils;
-import org.apache.poi.ss.usermodel.*;
 import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.*;
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.util.IOUtils;
 import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
 import org.jsoup.nodes.Element;
 import org.jsoup.select.Elements;
-import org.springblade.business.dto.TrialSelfInspectionRecordDTO;
 import org.springblade.business.entity.InformationQuery;
 import org.springblade.business.entity.TrialSelfInspectionRecord;
 import org.springblade.business.feign.ContractLogClient;
@@ -60,8 +58,8 @@ import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.secure.utils.AuthUtil;
 import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.node.ForestNodeMerger;
-import org.springblade.core.tool.utils.*;
 import org.springblade.core.tool.utils.DateUtil;
+import org.springblade.core.tool.utils.*;
 import org.springblade.manager.bean.TableInfo;
 import org.springblade.manager.entity.*;
 import org.springblade.manager.formula.KeyMapper;
@@ -79,14 +77,9 @@ import org.springframework.jdbc.datasource.DataSourceTransactionManager;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.TransactionDefinition;
 import org.springframework.transaction.TransactionStatus;
-import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.support.DefaultTransactionDefinition;
-import org.springframework.web.bind.annotation.RequestParam;
 
 import javax.imageio.ImageIO;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.awt.*;
 import java.awt.Color;
 import java.awt.image.BufferedImage;
 import java.io.*;
@@ -343,7 +336,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
             /*每次都是部分表单提交,保证跨节点跨表取数正常,其次是反向依赖的被动刷新*/
             List<AppWbsTreeContractVO> tableAll = wbsTreeContractService.searchNodeAllTable(nodeId.toString(), "1", tableInfoList.get(0).getContractId(), tableInfoList.get(0).getProjectId());
             StopWatch stopWatch = new StopWatch();
-            List<KeyMapper> keyMappers = this.formulaService.getKeyMapperList(tableInfoList.stream().map(TableInfo::getPkeyId).filter(Func::isNotEmpty).map(Long::parseLong).collect(Collectors.toList()), tableInfoList.get(0).getProjectId());
+            List<KeyMapper> keyMappers = this.formulaService.getKeyMapperList(tableInfoList.stream().map(TableInfo::getPkeyId).filter(Func::isNotEmpty).map(Long::parseLong).collect(Collectors.toList()), tableInfoList.get(0).getProjectId(),String.valueOf(nodeId));
             if (Func.isNotEmpty(keyMappers)) {
                 Map<String, Map<String, String>> coordinateMap = new HashMap<>(keyMappers.size() * 2);
                 keyMappers.forEach(e -> {
@@ -382,6 +375,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
 
     public CurrentNode createCurrentNode(WbsTreeContract wtc) {
         if (wtc != null) {
+            /*当前工序节点*/
             CurrentNode currentNode = new CurrentNode();
             currentNode.setPkId(wtc.getPKeyId());
             currentNode.setParentId(wtc.getParentId());
@@ -396,7 +390,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
                 } else {
                     currentNode.setRelateId(wtc.getId());
                 }
-                List<Long> privateIds = this.jdbcTemplate.queryForList("select p_key_id from m_wbs_tree_private where id=" + id + " and  project_id=" + wtc.getProjectId(), Long.class);
+                List<Long> privateIds = this.jdbcTemplate.queryForList("select p_key_id from m_wbs_tree_private where id=" + id + " and  project_id=" + wtc.getProjectId()+" and wbs_id="+wtc.getWbsId(), Long.class);
                 if (Func.isNotEmpty(privateIds)) {
                     currentNode.setPrivateId(privateIds.get(0));
                     return currentNode;
@@ -863,7 +857,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
     }
 
     @Override
-    public R getBussDataInfo(Long pkeyId) {
+    public R getBussDataInfo(Long pkeyId,int type) {
 
         Map<String, Object> reData = new HashMap<>();
 
@@ -1065,20 +1059,25 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
         }
 
         // 移除Id 和 p_key_id
-        reData.remove("id");
-        reData.remove("p_key_id");
-        reData.remove("classify");
-        reData.remove("contractId");
-        reData.remove("pkeyId");
-        reData.remove("projectId");
+        if(type==0){
+            reData.remove("id");
+            reData.remove("p_key_id");
+            reData.remove("classify");
+            reData.remove("contractId");
+            reData.remove("pkeyId");
+            reData.remove("projectId");
+        }
+        if(type==1){
+            reData.put("pkeyId",reData.get("p_key_id"));
+        }
         reData.put("tabGroupId", wbsTreeContract.getTabGroupId());
         return R.data(reData);
     }
 
     @Override
     public R getBussPdfInfo(Long pkeyId) throws Exception {
-        String file_path = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
-        // String file_path = "/Users/hongchuangyanfa/Desktop/";
+        //String file_path = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
+        String file_path = "/Users/hongchuangyanfa/Desktop/";
         WbsTreeContract wbsTreeContract = wbsTreeContractService.getBaseMapper().selectOne(Wrappers.<WbsTreeContract>query().lambda()
                 .eq(WbsTreeContract::getPKeyId, pkeyId));
 
@@ -1103,7 +1102,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
             return R.fail("失败");
         }
 
-        Map<String, Object> DataInfo = (Map<String, Object>) getBussDataInfo(pkeyId).getData();
+        Map<String, Object> DataInfo = (Map<String, Object>) getBussDataInfo(pkeyId,0).getData();
 
         // 获取excel流 和 html流
         InputStream exceInp = CommonUtil.getOSSInputStream(excelTab.getFileUrl());
@@ -1287,6 +1286,10 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
                                 Elements tdsx = ytzData.select("td");
                                 if (Integer.parseInt(trtd[1]) < tdsx.size()) {
                                     Element data = ytzData.select("td").get(Integer.parseInt(trtd[1]));
+                                    if(data.html().indexOf("el-tooltip") >= 0){
+                                        data = data.children().get(0);
+                                    }
+
                                     int x1 = Integer.parseInt(data.children().get(0).attr("x1"));
                                     if (x1 == 0) {
                                         x1 = 1;
@@ -1324,7 +1327,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
         //输出流
         FileOutputStream outputStream = new FileOutputStream(excelPath);
         workbook.write(outputStream);
-        FileUtils.excelToPdf(excelPath, pdfPath);
+        FileUtils.setExcelScaleToPdf(excelPath, pdfPath);
         BladeFile bladeFile = newIOSSClient.uploadFile(pkeyId + ".pdf", pdfPath);
         //
         TableFile tableFile1 = tableFileService.getBaseMapper().selectOne(Wrappers.<TableFile>query().lambda()
@@ -1378,8 +1381,8 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
 
     @Override
     public void getBussPdfs(String nodeId, String classify, String contractId, String projectId) throws Exception {
-        String file_path = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
-        //String file_path = "/Users/hongchuangyanfa/Desktop/";
+        //String file_path = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
+        String file_path = "/Users/hongchuangyanfa/Desktop/";
         // 获取有权限的节点信息
         List<AppWbsTreeContractVO> wbsTreeContractList = wbsTreeContractService.searchNodeAllTable(nodeId, classify, contractId, projectId);
         List<String> data = new ArrayList<>();

+ 397 - 29
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/FormulaServiceImpl.java

@@ -4,12 +4,19 @@ package org.springblade.manager.service.impl;
 import cn.hutool.core.util.HashUtil;
 import cn.hutool.log.StaticLog;
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.jfireel.expression.Expression;
 import com.mixsmart.utils.*;
 import lombok.RequiredArgsConstructor;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
 import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.core.mp.base.BaseServiceImpl;
+import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.utils.*;
 import org.springblade.manager.bean.TableInfo;
 import org.springblade.manager.dto.*;
@@ -17,6 +24,7 @@ import org.springblade.manager.entity.*;
 import org.springblade.manager.formula.FormulaStrategyFactory;
 import org.springblade.manager.formula.KeyMapper;
 import org.springblade.manager.formula.impl.CompositeDataAccess;
+import org.springblade.manager.formula.impl.SubTable;
 import org.springblade.manager.formula.impl.TableElementConverter;
 import org.springblade.manager.mapper.FormulaMapper;
 import org.springblade.manager.service.*;
@@ -24,6 +32,10 @@ import org.springblade.manager.vo.AppWbsTreeContractVO;
 import org.springblade.manager.vo.CurrentNode;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.regex.Matcher;
@@ -46,8 +58,13 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
     private final IContractInfoService contractInfoService;
     private final IProjectInfoService projectInfoService;
     private final IWbsTreeContractService wbsTreeContractService;
+    private final IWbsTreePrivateService wbsTreePrivateService;
+    private final IElementFormulaMappingService elementFormulaMappingService;
+    private final IWbsTreeService wbsTreeService;
     private final JdbcTemplate jdbcTemplate;
     private final IFormulaOptionService formulaOptionService;
+    private final ITextdictInfoService textdictInfoService;
+
     /**  private final Container env;*/
     private   TableElementConverter tec;
     private   Map<String,Object> constantMap;
@@ -106,7 +123,9 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
         /*合同段信息*/
         this.constantMap.put(CTI,info);
         /*项目信息*/
-        this.constantMap.put(PJI,this.projectInfoService.getById(info.getPId()));
+        ProjectInfo pji=this.projectInfoService.getById(info.getPId());
+        tec.setProjectId(pji.getId());
+        this.constantMap.put(PJI,pji);
         /*wbs节点链*/
         List<WbsTreeContract> nodes = wpService.chain(contractId,id,primaryKeyId,null);
         if(Func.isEmpty(nodes)){
@@ -126,7 +145,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
         /*检查是否有跨节点数据*/
         /*获取type=1的检验单或者type=4的监表*/
         List<Map<String,Object>>  inspectionElementMaps = new ArrayList<>();
-        Optional<AppWbsTreeContractVO> wop=tableList.stream().filter(e->e.getFullName().contains("检验单")).findAny();
+        Optional<AppWbsTreeContractVO> wop=tableList.stream().filter(e->e.getFullName().contains("检验单")||e.getNodeName().contains("检验单")).findAny();
         if(wop.isPresent()){
             /*检验单或者监表的*/
             inspectionElementMaps=  this.jdbcTemplate.queryForList(" select c.e_name name ,b.tab_en_name tableName,c.e_key ekey from m_wbs_tree_contract a join m_table_info b on a.init_table_name=b.tab_en_name join m_wbs_form_element c on c.f_id= b.id where a.p_key_id=" + wop.get().getPKeyId());
@@ -186,7 +205,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
             for(String s:cki){
                 FormData fdTmp=this.formDataMap.get(s);
                 if(fdTmp!=null&&fdTmp.getValues().stream().map(ElementData::getValue).anyMatch(e->StringUtils.isNotEmpty(e)&&StringUtils.isNotEquals("/",e))){
-                    sb.append(fdTmp.getEName().replaceAll("^[^\\u4e00-\\u9fa5]+","").split("[((].+[))]|_")[0]).append(",");
+                    sb.append(FormulaUtils.parseItemName(fdTmp.getEName())).append(",");
                 }
             }
             if(sb.length()>1){
@@ -423,9 +442,17 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                     fd.setFinished(Boolean.TRUE);
                     continue;
                 }
-                String tmp =fd.getFormula().getFormula();
+                String tmp =fd.getFormula().getFormula().replaceAll("[\\s]+","");
+                /*G8G10指令脱壳*/
+                if(tmp.contains("G8@")||tmp.contains("G10@")){
+                  Matcher mg=  RegexUtils.matcher("FC.shell\\d{3}\\([^(FC.)]+,(G\\d+@\\w+)\\)",tmp);
+                  while (mg.find()){
+                      String[] ka= mg.group(1).split("@");
+                      tmp=tmp.replace(mg.group(),ka[0]+"['"+ka[1]+"']");
+                  }
+                }
                 /*假如是直接取数,则补充上非空过滤*/
-                if(tmp.matches("^E\\[m__[0-9]{14}_[0-9]{19}:key_[0-9]{0,3}]$")){
+                if(tmp.matches("^E\\[m_\\d{14}_\\d{19}:key_\\d{0,3}]$")){
                     tmp="FC.removeEmpty("+tmp+")";
                 }
                 tmp = tmp.replace(FC, CustomFunction.CLASS_CALL);
@@ -542,12 +569,107 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                 fd.setUpdate(1);
             }
         }
+
+/*###############################附表的处理##################################*/
+        if(true) {
+            try {
+                /*检验单附表处理*/
+                List<FormData> inspectionList = new ArrayList<>();
+                this.tec.getTableAll().stream().filter(e -> e.getNodeName().contains("检验单") || e.getNodeName().contains("评定表")).forEach(e -> {
+                    /*获取所有挂在表里的元素映射关系*/
+                    this.tec.getKeyMappers().stream().filter(p -> p.getPkId().equals(e.getPKeyId())).forEach(k -> {
+                        /*元素长度筛选超页的元素*/
+                        List<FormData> target = this.formDataMap.values().stream().filter(f -> f.getCode().equals(k.getCode()) && f.getAddPages() > 0).collect(Collectors.toList());
+                        if (Func.isNotEmpty(target)) {
+                            inspectionList.addAll(target);
+                        }
+                    });
+                });
+                if (Func.isNotEmpty(inspectionList)) {
+                    /*检查是否存在附表,不存在挂载*/
+                    List<AppWbsTreeContractVO> subTabList = this.tec.getTableAll().stream().filter(e -> e.getNodeName().contains("附表")).collect(Collectors.toList());
+                    if (subTabList.size() == 0) {
+                        boolean pd=tec.getTableAll().stream().anyMatch(e->e.getNodeName().contains("评定表")||e.getFullName().contains("评定表"));
+                        WbsTreePrivate sub = wbsTreePrivateService.getOne(Wrappers.<WbsTreePrivate>lambdaQuery().and(e->e.eq(WbsTreePrivate::getNodeName, pd?"质量检验评定表(附表)":"质量检验表(附表)").or().eq(WbsTreePrivate::getFullName, pd?"质量检验评定表(附表)":"质量检验表(附表)")).eq(WbsTreePrivate::getProjectId, tec.getProjectId()));
+                        if (sub == null) {
+                            this.tec.getLog().append("该项目没有挂有附表信息");
+                        } else {
+                            this.wbsTreePrivateService.addWbsTreeContractInfo(this.tec.getCurrentNode().getPkId().toString(), sub.getPKeyId().toString(), tec.getContractId());
+                            AppWbsTreeContractVO one = this.tec.getTableAll().get(0);
+                            WbsTreeContract wtc = this.wbsTreeContractService.getOne(Wrappers.<WbsTreeContract>lambdaQuery().eq(WbsTreeContract::getParentId, one.getParentId()).eq(WbsTreeContract::getWbsId, one.getWbsId()).and(e->e.eq(WbsTreeContract::getNodeName, pd?"质量检验评定表(附表)":"质量检验表(附表)").or().eq(WbsTreeContract::getFullName, pd?"质量检验评定表(附表)":"质量检验表(附表)")));
+                            if (wtc != null) {
+                                /*只需要挂载一张*/
+                                AppWbsTreeContractVO obj = BeanUtil.copy(wtc, AppWbsTreeContractVO.class);
+                                this.tec.getTableAll().add(obj);
+                                subTabList.add(obj);
+                            }
+                        }
+                    }
+                    AppWbsTreeContractVO first = subTabList.get(0);
+                    if (tec.getTableInfoList().stream().noneMatch(e -> StringUtils.isEquals(e.getPkeyId(), first.getPKeyId()))) {
+                        /*找不到附表表单数据,则从数据库加载*/
+                        JSONArray dataArray = new JSONArray();
+                        for (WbsTreeContract data : subTabList) {
+                            R bussDataInfo = this.getBussDataInfo(data.getPKeyId(), 1);
+                            Object data1 = bussDataInfo.getData();
+                            dataArray.add(data1);
+                        }
+                        List<TableInfo> subTableInfo = FormulaUtils.getTableInfoList(dataArray);
+                        tec.getTableInfoList().addAll(subTableInfo);
+                        tec.getCoordinateMap().put(subTabList.get(0).getInitTableName(), CustomFunction.getElementCell(first.getHtmlUrl()));
+                        List<Map<String, Object>> elementMaps = this.jdbcTemplate.queryForList("select b.e_name name , CONCAT(a.tab_en_name,':',b.e_key) code , b.e_key ekey ,b.id fieldId,a.tab_en_name tableName from m_table_info a join m_wbs_form_element b on a.id = b.f_id where a.tab_en_name='" + first.getInitTableName() + "' and b.is_deleted=0 ");
+                        if (Func.isNotEmpty(elementMaps)) {
+                            elementMaps.forEach(e->{
+                                /*生成附表元素*/
+                                String values=subTableInfo.stream().map(TableInfo::getDataMap).map(m->m.get(StringUtils.handleNull(e.get("ekey")))).filter(StringUtils::isNotEmpty).collect(Collectors.joining(";;"));
+                                FormData tmp=  createFormDataFast(StringUtils.handleNull(e.get("ename")),StringUtils.handleNull(e.get("code")),values);
+                                if(tmp!=null){
+                                    this.formDataMap.put(tmp.getCode(),tmp);
+                                    this.formDataList.add(tmp);
+                                }
+                            });
+                            /*生成元素数据*/
+                            subTabList.forEach(s->{
+                                elementMaps.forEach(e->{
+                                    KeyMapper km = new KeyMapper();
+                                     km.setPkId(s.getPKeyId());
+                                     km.setField(StringUtils.handleNull(e.get("ekey")));
+                                     km.setFieldId(Func.toLong(e.get("fieldId")));
+                                     km.setTableName(StringUtils.handleNull(e.get("tableName")));
+                                     this.tec.getKeyMappers().add(km);
+                                });
+                            });
+
+                        }
+                    }
+                    List<FormData> subTableFds=this.formDataList.stream().filter(e->StringUtils.isEquals(first.getInitTableName(),e.getTableName())).collect(Collectors.toList());
+                    SubTable sta=new SubTable(subTableFds);
+                    /*检验单或者评定表存在超页数据*/
+                    inspectionList.forEach(f -> {
+                           List<ElementData> overList = f.getValues().stream().skip(f.getCoordsList().size()).collect(Collectors.toList());
+                           String itemName=FormulaUtils.parseItemName(f.getEName());
+                           String key=itemName.trim();
+                           Optional<FormData> designFdOp=  this.formDataMap.values().stream().filter(o->o.getTableName().equals(f.getTableName())&&StringUtils.isEquals(itemName,FormulaUtils.parseItemName(o.getEName()))).findAny();
+                           if(designFdOp.isPresent()){
+                               key+="@"+designFdOp.get().getValues().stream().map(ElementData::stringValue).filter(StringUtils::isNotEmpty).findAny().orElse("");
+                           }
+                           sta.put(key,overList);
+                    });
+                    if(sta.checked()){
+                        sta.flush();
+                    }
+                }
+            } catch (Exception e) {
+                this.tec.getLog().append("|=|").append("附表异常").append("|=|");
+                e.printStackTrace();
+            }
+        }
         return this;
     }
 
     public  void write(FormData fd,Object data){
         /*如果需要向额外元素或对象输出数据,在此处修改*/
-               FormulaUtils.write(fd,data);
+               FormulaUtils.write(fd,data,false);
     }
 
     /**加页增容*/
@@ -599,6 +721,17 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
            }
            //enlarge(fd,pageAdd);
        }
+       /*复制只有一个单元格的元素*/
+       this.formDataMap.values().stream().filter(e->StringUtils.isEquals(e.getTableName(),fd.getTableName())&&fd.getCoordsList().size()==1).forEach(t->{
+           ElementData data=t.getValues().get(t.getValues().size()-1);
+           int start =data.getIndex();
+           for(int i=0;i<pageAdd;i++){
+               ElementData ed =new ElementData();
+               BeanUtil.copy(data,ed);
+               ed.setIndex(++start);
+               t.getValues().add(ed);
+           }
+       });
    }
 
 
@@ -621,25 +754,6 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                 }
             }
         }
-
-         try {
-             /*检验单附表处理*/
-             List<FormData>  inspectionList= new ArrayList<>();
-             this.tec.getTableAll().stream().filter(e->e.getNodeName().contains("检验单")).forEach(e->{
-                 this.tec.getKeyMappers().stream().filter(p->p.getPkId().equals(e.getPKeyId())).forEach(k->{
-                     this.formDataMap.values().stream().filter(f->f.getCode().equals(k.getCode())&&f.getAddPages()>0).forEach(inspectionList::add);
-                 });
-             });
-             if(Func.isNotEmpty(inspectionList)){
-                 Map<String,List<ElementData>> overMap=new HashMap<>();
-                 inspectionList.forEach(f->{
-
-                 });
-             }
-         }catch (Exception e){
-             e.printStackTrace();
-         }
-
         /*检查超页情况*/
         this.formDataMap.values().stream().filter(e->e.getUpdate()==1&&e.getAddPages()>0).sorted(Comparator.comparing(FormData::getAddPages).reversed())
                         .collect(Collectors.groupingBy(FormData::getTableName,LinkedHashMap::new,Collectors.toList())).values()
@@ -647,7 +761,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
     }
 
     @Override
-    public List<KeyMapper> getKeyMapperList(List<Long> ids,String projectId) {
+    public List<KeyMapper> getKeyMapperList(List<Long> ids,String projectId,String nodeId) {
         /*表名,pkeyId,元素名,元素id 映射对象*/
         String pkIds=ids.stream().map(String::valueOf).collect(Collectors.joining(","));
         List<Map<String,Object>> listMap = this.jdbcTemplate.queryForList(" select a.init_table_name as tableName,a.p_key_id as pkId ,c.e_key as field,c.e_name as eName,c.id  as fieldId   " +
@@ -675,6 +789,40 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                     }
                 });
             }
+            /*节点参数公式*/
+            if(StringUtils.isNotEmpty(nodeId)){
+                /*存在工序节点id则检查节点参数*/
+                WbsTreeContract wtc = this.wbsTreeContractService.getOne(Wrappers.<WbsTreeContract>lambdaQuery().eq(WbsTreeContract::getPKeyId,nodeId));
+                if(wtc!=null){
+                    List<WbsParam> total = new ArrayList<>();
+                    WbsTreePrivate wtp = this.wbsTreePrivateService.getOne(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getProjectId,wtc.getProjectId()).eq(WbsTreePrivate::getWbsId,wtc.getWbsId()).and(e->e.eq(WbsTreePrivate::getId,wtc.getId()).or().eq(WbsTreePrivate::getId,wtc.getOldId())));
+                    if(wtp!=null){
+                        List<WbsParam> wpsPrivate = this.wpService.list(Wrappers.<WbsParam>lambdaQuery().eq(WbsParam::getNodeId,wtp.getPKeyId()));
+                        if(Func.isEmpty(wpsPrivate)){
+                            WbsTree wt = this.wbsTreeService.getOne(Wrappers.<WbsTree>lambdaQuery().and(e->e.eq(WbsTree::getId,wtc.getId()).or().eq(WbsTree::getId,wtc.getOldId())));
+                            if(wt!=null){
+                                List<WbsParam> wpsPublic = this.wpService.list(Wrappers.<WbsParam>lambdaQuery().eq(WbsParam::getNodeId,wt.getId()));
+                                if(Func.isNotEmpty(wpsPublic)){
+                                    total.addAll(wpsPublic);
+                                }
+                            }
+                        }else{
+                            total.addAll(wpsPrivate);
+                        }
+                    }
+                    if(Func.isNotEmpty(total)){
+                      List<ElementFormulaMapping> mappingList =  this.elementFormulaMappingService.list(Wrappers.<ElementFormulaMapping>lambdaQuery().in(ElementFormulaMapping::getParamId,total.stream().map(WbsParam::getId).collect(Collectors.toList())));
+                      if(Func.isNotEmpty(mappingList)){
+                          list.forEach(e->{
+                              mappingList.stream().filter(m->StringUtils.isEquals(m.getElementId(),e.getFieldId())).findAny().ifPresent(d->{
+                                  e.setFormulaId(d.getFormulaId());
+                              });
+                          });
+
+                      }
+                    }
+                }
+            }
             if(list.size()>0){
                 return list;
             }
@@ -814,7 +962,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                            }
                        }else if(flag.contains("E[")){
                            List<FormData> target = getFormDataByCode(flag);
-                           if(target.size()>1){
+                           if(target.size()>0){
                               flag= target.get(0).getValues().stream().map(ElementData::stringValue).filter(StringUtils::isNotEmpty).findFirst().orElse("0");
                            }
                        }
@@ -867,8 +1015,13 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                              FormData dataFd=this.formDataMap.get(codeList.get(0));
                              FormData designFd=this.formDataMap.get(codeList.get(1));
                              if(dataFd!=null&&designFd!=null){
-                                 List<Object>  result =  CustomFunction.b445check(dataFd.getValues().stream().map(ElementData::getValue).collect(Collectors.toList()),designFd.getValues().stream().map(ElementData::getValue).collect(Collectors.toList()),formula.getDev(),1 );
-                                 data=result.get(1);
+                                 if(dataFd.getValues().stream().map(ElementData::getValue).anyMatch(StringUtils::isNotEmpty)&&(designFd.getValues().size()>1||designFd.getValues().stream().map(ElementData::getValue).anyMatch(StringUtils::isEmpty))){
+                                     /*多少个设计值暂时默认全部合格,满足绝大部分结果*/
+                                     data=dataFd.getValues().stream().map(ElementData::getValue).filter(StringUtils::isNotEmpty).count();
+                                 }else{
+                                     List<Object>  result =  CustomFunction.b445check(dataFd.getValues().stream().map(ElementData::getValue).collect(Collectors.toList()),designFd.getValues().stream().map(ElementData::getValue).collect(Collectors.toList()),formula.getDev(),1 );
+                                     data=result.get(1);
+                                 }
                              }
                          }
 
@@ -997,7 +1150,222 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
         return new HashMap<>();
     }
 
+    public R getBussDataInfo(Long pkeyId,int type) {
 
+        Map<String, Object> reData = new HashMap<>();
+
+        WbsTreeContract wbsTreeContract = wbsTreeContractService.getBaseMapper().selectOne(Wrappers.<WbsTreeContract>query().lambda()
+                .eq(WbsTreeContract::getPKeyId, pkeyId));
+        if (wbsTreeContract == null) {
+            return R.data(reData);
+        }
+
+        if (wbsTreeContract.getHtmlUrl() == null) {
+            return R.data(reData);
+        }
+
+        //表单是否存储在
+        String tabName = wbsTreeContract.getInitTableName();
+        String isExitSql = " select * from information_schema.TABLES where TABLE_NAME='" + tabName + "'";
+        List<Map<String, Object>> tabList = jdbcTemplate.queryForList(isExitSql);
+        if (tabList == null || tabList.size() <= 0) {
+            return R.fail("无实体表对应");
+        }
+
+        String querySql = "select * from " + wbsTreeContract.getInitTableName() + " where p_key_id=" + pkeyId;
+        List<Map<String, Object>> dataIn = jdbcTemplate.queryForList(querySql);
+
+        // 匹配关联
+        try {
+            File file1 = ResourceUtil.getFile(wbsTreeContract.getHtmlUrl());
+            String htmlString = IoUtil.readToString(new FileInputStream(file1));
+            Document doc = Jsoup.parse(htmlString);
+
+            // 解析
+            // 模糊匹配
+            Elements dwtitle = doc.select("el-input[placeholder~=.*承包单位]");
+            Elements sgtitle = doc.select("el-input[placeholder~=^施工单位]");
+            Elements sgtitle1 = doc.select("el-input[placeholder=安装单位]");
+            sgtitle.addAll(sgtitle1);
+
+            Elements htdtitle = doc.select("el-input[placeholder~=.*合同段.*]");
+            Elements htdtitle1 = doc.select("el-input[placeholder~=合同名称.*]");
+            htdtitle.addAll(htdtitle1);
+
+            Elements jltitle = doc.select("el-input[placeholder~=监理单位.*]");
+
+            Elements bhtitle = doc.select("el-input[placeholder~=^编号]");
+            Elements bhtitle1 = doc.select("el-input[placeholder~=合同编号.*]");
+            bhtitle.addAll(bhtitle1);
+
+
+            Elements xmtitle = doc.select("el-input[placeholder~=^项目名称]");
+
+
+            // Elements title = doc.select("el-input[placeholder~=^编号]");
+
+            /**
+             * 承包单位 承包单位、施工单位:引用施工单位名称 ,
+             * 监理单位:引用监理单位名称
+             * 合同段、所属建设项目(合同段):引用合同段编号
+             *
+             * 施工单位:施工单位 和 安装单位
+             *
+             */
+            ContractInfo contractInfo = contractInfoService.getById(wbsTreeContract.getContractId());
+            // 施工单位名称
+            if (dwtitle.size() >= 1) {
+                int y = Integer.parseInt(dwtitle.attr("trindex"));
+                if (y <= 10) {
+                    reData.put(dwtitle.attr("keyName"), contractInfo.getConstructionUnitName());
+                }
+
+            }
+            if (sgtitle.size() >= 1) {
+                int y = Integer.parseInt(sgtitle.attr("trindex"));
+                if (y <= 10) {
+                    reData.put(sgtitle.attr("keyName"), contractInfo.getConstructionUnitName());
+                }
+            }
+
+            // 合同段名称
+            if (htdtitle.size() >= 1) {
+                for (Element element : htdtitle) {
+                    int trindex = Integer.parseInt(element.attr("trindex"));
+                    if (trindex <= 8) {
+                        reData.put(element.attr("keyName"), contractInfo.getContractNumber());
+                    }
+                }
+            }
+            // 监理单位名称
+            if (jltitle.size() >= 1) {
+
+                for (Element element : jltitle) {
+                    int trindex = Integer.parseInt(element.attr("trindex"));
+                    if (trindex <= 10) {
+                        reData.put(element.attr("keyName"), contractInfo.getSupervisionUnitName());
+                    }
+                }
+            }
+            //获取父节点划分编号
+            WbsTreeContract node = wbsTreeContractService.getBaseMapper().selectOne(Wrappers.<WbsTreeContract>query().lambda()
+                    .eq(WbsTreeContract::getId, wbsTreeContract.getParentId())
+                    .eq(WbsTreeContract::getContractId, wbsTreeContract.getContractId()));
+            // 编号
+            if (bhtitle.size() >= 1 && contractInfo.getIsReferenceNumber() == 1) {
+                for (Element element : bhtitle) {
+                    int trindex = Integer.parseInt(element.attr("trindex"));
+                    if (trindex <= 10) {
+                        reData.put(element.attr("keyName"), node.getPartitionCode() == null ? "" : node.getPartitionCode());
+                    }
+                }
+            }
+
+            // 项目名称
+            if (xmtitle.size() >= 1) {
+                for (Element element : xmtitle) {
+                    int trindex = Integer.parseInt(element.attr("trindex"));
+                    if (trindex <= 6) {
+                        ProjectInfo projectInfo = projectInfoService.getById(wbsTreeContract.getProjectId());
+                        reData.put(element.attr("keyName"), projectInfo.getProjectName());
+                    }
+                }
+            }
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        }
+
+        if (dataIn != null && dataIn.size() >= 1) {
+            Map<String, Object> mysqlData = dataIn.get(0);
+            for (String key : mysqlData.keySet()) {
+                String tabVal = mysqlData.get(key) + "";
+                // 时间段处理
+                if (org.apache.commons.lang.StringUtils.isNotEmpty(tabVal) && tabVal.indexOf("null") < 0) {
+                    if (tabVal.indexOf("T") >= 0 && tabVal.indexOf(".000Z]") >= 0) {
+                        String[] tabData = tabVal.split("_\\^_");
+
+                        if (reData.containsKey("pickerKey")) {
+                            String pickerKey = reData.get("pickerKey") + "," + key + "__" + tabData[1];
+                            reData.put("pickerKey", pickerKey);
+                        } else {
+                            reData.put("pickerKey", key + "__" + tabData[1]);
+                        }
+
+                        String sql = tabData[0];
+                        sql = sql.replaceAll("\\[", "['");
+                        sql = sql.replaceAll("]", "']");
+                        sql = sql.replaceAll("000Z,", "000Z',");
+                        sql = sql.replaceAll(", 20", ", '20");
+                        //   sql = sql.replaceAll("'", "");
+                        if (org.apache.commons.lang.StringUtils.isNotEmpty(tabData[0])) {
+                            reData.put(key + "__" + tabData[1], sql);
+                        }
+                    } else if (tabVal.indexOf("T") >= 0 && tabVal.indexOf(".000Z") >= 0) { //时间
+                        // 时间和字符串合作
+                        if (tabVal.indexOf("☆") >= 0) {
+                            String[] mysql = tabVal.split("☆");
+                            for (String data : mysql) {
+                                String[] tabData = data.split("_\\^_");
+                                if (org.apache.commons.lang.StringUtils.isNotEmpty(tabData[0])) {
+                                    reData.put(key + "__" + tabData[1], tabData[0]);
+                                }
+                            }
+                        } else {
+                            String[] tabData = tabVal.split("_\\^_");
+                            if (org.apache.commons.lang.StringUtils.isNotEmpty(tabData[0])) {
+                                reData.put(key + "__" + tabData[1], tabData[0]);
+                            }
+                        }
+                    } else if (tabVal.indexOf("☆") >= 0) {
+                        String[] mysql = tabVal.split("☆");
+                        for (String data : mysql) {
+                            String[] tabData = data.split("_\\^_");
+                            if (org.apache.commons.lang.StringUtils.isNotEmpty(tabData[0])) {
+                                reData.put(key + "__" + tabData[1], tabData[0]);
+                            }
+                        }
+                    } else if (tabVal.indexOf("_^_") >= 0) {
+                        String[] tabData = tabVal.split("_\\^_");
+                        if (org.apache.commons.lang.StringUtils.isNotEmpty(tabData[0])) {
+                            reData.put(key + "__" + tabData[1], tabData[0]);
+                        }
+                    } else {
+                        reData.put(key, tabVal);
+                    }
+                }
+            }
+        }
+
+        // 获取默认值
+        QueryWrapper<TextdictInfo> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("type", 4);
+        queryWrapper.eq("tab_id", wbsTreeContract.getIsTypePrivatePid());
+        final List<TextdictInfo> textdictInfos = textdictInfoService.getBaseMapper().selectList(queryWrapper);
+        if (!textdictInfos.isEmpty()) {
+            for (TextdictInfo textdictInfo : textdictInfos) {
+                if (reData.containsKey(textdictInfo.getColKey())) {
+                    String keyVal = reData.get(textdictInfo.getColKey()) + "";
+                } else {
+                    reData.put(textdictInfo.getColKey() + "", textdictInfo.getSigRoleName());
+                }
+            }
+        }
+
+        // 移除Id 和 p_key_id
+        if(type==0){
+            reData.remove("id");
+            reData.remove("p_key_id");
+            reData.remove("classify");
+            reData.remove("contractId");
+            reData.remove("pkeyId");
+            reData.remove("projectId");
+        }
+        if(type==1){
+            reData.put("pkeyId",reData.get("p_key_id"));
+        }
+        reData.put("tabGroupId", wbsTreeContract.getTabGroupId());
+        return R.data(reData);
+    }
 
 }
 

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

@@ -4,9 +4,12 @@ import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.AllArgsConstructor;
 import org.apache.commons.lang.StringUtils;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
 import org.springblade.business.entity.ConstructionLedger;
 import org.springblade.business.feign.ConstructionLedgerFeignClient;
 import org.springblade.common.utils.FileUtils;
@@ -15,9 +18,8 @@ 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.node.ForestNodeMerger;
-import org.springblade.core.tool.utils.BeanUtil;
-import org.springblade.core.tool.utils.Func;
-import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.core.tool.utils.*;
+import org.springblade.manager.dto.RangeInfo;
 import org.springblade.manager.dto.WbsTreeContractDTO;
 import org.springblade.manager.dto.WbsTreeContractDTO2;
 import org.springblade.manager.entity.*;
@@ -34,6 +36,8 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.*;
 import java.util.stream.Collectors;
@@ -352,6 +356,62 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
         return ForestNodeMerger.merge(baseMapper.appSearchConcealedNodes(primaryKeyId, contractId));
     }
 
+    // 频率添加表单
+    @Override
+    public boolean addTabInfoByRan(RangeInfo info,List<Object> moreData,Integer excLenght) throws FileNotFoundException {
+        WbsTreeContract wbsInfo = this.baseMapper.selectOne(Wrappers.<WbsTreeContract>query().lambda()
+                .eq(WbsTreeContract::getPKeyId, info.getPkId()));
+
+        //查询复制表有多少张
+        List<WbsTreeContract> wbsTreeContractList = this.baseMapper.selectList(Wrappers.<WbsTreeContract>query().lambda()
+                .eq(WbsTreeContract::getId, wbsInfo.getId())
+                .eq(WbsTreeContract::getContractId, wbsInfo.getContractId())
+                .eq(WbsTreeContract::getParentId, wbsInfo.getParentId()));
+        List<WbsTreeContract> wbsTreeContractList2 = wbsTreeContractList.stream().filter(wbsTreeContract -> wbsTreeContract.getIsCopeTab() ==null || wbsTreeContract.getIsCopeTab()!=2).sorted(Comparator.comparing(WbsTreeContract::getCreateTime).reversed()).collect(Collectors.toList());
+        // 判读需要添加几张表
+        long tabGroupId = SnowFlakeUtil.getId();
+
+        List<WbsTreeContract> addList = new ArrayList<>();
+
+        double tabCount = moreData.size() / excLenght - wbsTreeContractList2.size()+1;
+        double tabsCount  = Math.ceil(tabCount);
+        if(tabsCount>=1){
+            for(int i =0 ;i<tabsCount;i++){
+                long newPkId = SnowFlakeUtil.getId();
+                WbsTreeContract wbsTreeContract = new WbsTreeContract();
+                BeanUtil.copy(wbsInfo,wbsTreeContract);
+                wbsTreeContract.setPKeyId(newPkId);
+                wbsTreeContract.setCreateTime(new Date());
+                wbsTreeContract.setTabGroupId(tabGroupId);
+                String nodeName = wbsTreeContractList2.get(0).getNodeName();
+
+                if (nodeName.indexOf("_PL_") >= 0) {
+                    String[] oldName = nodeName.split("_PL_");
+                    nodeName = oldName[0] + "_PL_" + (Integer.parseInt(oldName[1]) + 1);
+                } else {
+                    nodeName = nodeName + "_PL_" + 1;
+                }
+                wbsTreeContract.setNodeName(nodeName);
+                wbsTreeContract.setIsCopeTab(1);
+                wbsTreeContract.setIsTabPdf(1); // pdf 不能预览
+                wbsTreeContract.setIsBussShow(1); // 是否隐藏表
+                wbsTreeContract.setTabFileType(1);//没有上传附件
+                wbsTreeContract.setPdfUrl("");
+                addList.add(wbsTreeContract);
+            }
+            // 插入数据
+            this.baseMapper.insertBatchSomeColumn(addList);
+        }
+        for(WbsTreeContract wbsTreeCont:wbsTreeContractList2){
+            UpdateWrapper<WbsTreeContract> updateWrapper = new UpdateWrapper<>();
+            updateWrapper.in("p_key_id", wbsTreeCont.getPKeyId() + "");
+            updateWrapper.set("tab_group_id", tabGroupId);
+            wbsTreeCont.setTabGroupId(tabGroupId);
+            this.getBaseMapper().update(wbsTreeCont,updateWrapper);
+        }
+        return false;
+    }
+
     @Override
     public List<WbsTreeContract> updateAllNodeTabById(WbsTreePrivate aPrivate) {
         return baseMapper.updateAllNodeTabById(aPrivate);

+ 60 - 3
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreePrivateServiceImpl.java

@@ -15,6 +15,7 @@ import org.jsoup.nodes.Document;
 import org.jsoup.nodes.Element;
 import org.jsoup.select.Elements;
 import org.springblade.common.constant.CommonConstant;
+import org.springblade.common.utils.CommonUtil;
 import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.mp.base.BaseServiceImpl;
@@ -1332,7 +1333,7 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
 
                 //获取当前项目节点树
                 Map<Long, WbsTreePrivate> nowNodeTreeAll = wbsTreePrivatesNodeAndTabNow.stream().filter(f -> f.getType().equals(1)).collect(Collectors.toList()).stream()
-                        .collect(Collectors.toMap(WbsTreePrivate::getId, Function.identity()));
+                        .collect(Collectors.toMap(WbsTreePrivate::getId, WbsTreePrivate -> WbsTreePrivate, (obj1, obj2) -> obj1));
 
                 //获取当前引用的节点树下所有节点、表、独立表
                 String sqlNodeTreeAllOld = "SELECT p_key_id,id,type,parent_id FROM m_wbs_tree_private WHERE project_id = " + oneRecordRoot.getProjectId() + " AND STATUS = 1 AND is_deleted = 0 AND (((type = 1 OR type = 2) AND wbs_id = " + oneRecordRoot.getWbsId() + ") OR ((type= 10 OR parent_id = -10 ) AND wbs_id IS NULL))";
@@ -1478,13 +1479,69 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
                 File file_in = ResourceUtil.getFile(tree.getHtmlUrl());
                 String fileCode = SnowFlakeUtil.getId() + "";
                 String htmlUrl = file_path + "/privateUrlCopy/" + fileCode + ".html";
-//                String htmlUrl = "C:\\Users\\泓创研发01\\Desktop\\privateUrlCopy\\" + fileCode + ".html";
                 File file_out = ResourceUtil.getFile(htmlUrl);
                 FileUtil.copy(file_in, file_out);
                 tree.setHtmlUrl(htmlUrl);
             }
             //批量修改
-            baseMapper.updateBatchByPKeyId(wbsTreePrivateList);
+            if (wbsTreePrivateList.size() > 1000) {
+                List<List<WbsTreePrivate>> splitList = CommonUtil.splitList(wbsTreePrivateList, 1000);
+                for (List<WbsTreePrivate> list : splitList) {
+                    baseMapper.updateBatchByPKeyId(list);
+                }
+            } else {
+                baseMapper.updateBatchByPKeyId(wbsTreePrivateList);
+            }
+        }
+    }
+
+    @Override
+    public List<WbsTreePrivateVO> getMixRatioTestTree(String pKeyId) {
+        WbsTreePrivate wbsTreePrivate = baseMapper.selectOne(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getPKeyId, pKeyId));
+        if (wbsTreePrivate != null && StringUtils.isNotEmpty(wbsTreePrivate.getMixRatioTestIds())) {
+            String ids = wbsTreePrivate.getMixRatioTestIds();
+            List<WbsTreePrivate> wbsTreePrivates = baseMapper.selectList(Wrappers.<WbsTreePrivate>lambdaQuery()
+                    .in(WbsTreePrivate::getId, Func.toLongList(ids))
+                    .eq(WbsTreePrivate::getProjectId, wbsTreePrivate.getProjectId())
+                    .eq(WbsTreePrivate::getWbsId, wbsTreePrivate.getWbsId())
+                    .eq(WbsTreePrivate::getWbsType, wbsTreePrivate.getWbsType())
+                    .eq(WbsTreePrivate::getStatus, 1));
+
+            WbsTreePrivate root = wbsTreePrivates.stream().filter(f -> f.getParentId() == 0L).findAny().orElse(null);
+            if (root == null) {
+                WbsTreePrivate rootNode = baseMapper.selectOne(Wrappers.<WbsTreePrivate>lambdaQuery()
+                        .eq(WbsTreePrivate::getParentId, 0L)
+                        .eq(WbsTreePrivate::getProjectId, wbsTreePrivate.getProjectId())
+                        .eq(WbsTreePrivate::getWbsId, wbsTreePrivate.getWbsId())
+                        .eq(WbsTreePrivate::getWbsType, wbsTreePrivate.getWbsType())
+                        .eq(WbsTreePrivate::getStatus, 1));
+                if (rootNode != null) {
+                    wbsTreePrivates.add(rootNode);
+                }
+            }
+
+            List<WbsTreePrivateVO> wbsTreePrivateVOS = BeanUtil.copyProperties(wbsTreePrivates, WbsTreePrivateVO.class);
+            return this.buildWbsTreeByStream(wbsTreePrivateVOS);
+        } else {
+            throw new ServiceException("当前节点下未配置勾选相关联试验的配合比节点");
+        }
+    }
+
+    private List<WbsTreePrivateVO> buildWbsTreeByStream(List<WbsTreePrivateVO> wbsTreePrivateVOS) {
+        List<WbsTreePrivateVO> list = wbsTreePrivateVOS.stream().filter(f -> f.getParentId() == 0L).collect(Collectors.toList());
+        Map<Long, List<WbsTreePrivateVO>> map = wbsTreePrivateVOS.stream().collect(Collectors.groupingBy(WbsTreePrivateVO::getParentId));
+        this.recursionFnTree(list, map);
+        return list;
+    }
+
+    private void recursionFnTree(List<WbsTreePrivateVO> list, Map<Long, List<WbsTreePrivateVO>> map) {
+        for (WbsTreePrivateVO wbsTreePrivateVO : list) {
+            List<WbsTreePrivateVO> childrenList = map.get(wbsTreePrivateVO.getId());
+            wbsTreePrivateVO.setChildren(childrenList);
+            if (childrenList != null && childrenList.size() > 0) {
+                wbsTreePrivateVO.setHasChildren(true);
+                recursionFnTree(childrenList, map);
+            }
         }
     }
 

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

@@ -9,6 +9,7 @@ import com.spire.xls.*;
 import com.sun.image.codec.jpeg.JPEGCodec;
 import com.sun.image.codec.jpeg.JPEGImageEncoder;
 import org.apache.commons.lang.StringUtils;
+import org.apache.poi.hssf.usermodel.HSSFPrintSetup;
 import org.apache.poi.hssf.usermodel.HSSFSheet;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.ss.usermodel.*;
@@ -16,12 +17,16 @@ import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Units;
+import org.apache.poi.xssf.usermodel.XSSFPrintSetup;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.jsoup.Jsoup;
 import org.jsoup.nodes.Element;
 import org.jsoup.select.Elements;
 import org.springblade.common.utils.CommonUtil;
 import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.common.vo.DataVO;
+import org.springblade.core.tool.api.ResultCode;
 import org.springblade.core.tool.utils.FileUtil;
 import org.springblade.core.tool.utils.IoUtil;
 import org.springblade.core.tool.utils.ResourceUtil;
@@ -231,6 +236,7 @@ public class FileUtils {
                 sheet.setPrintGridlines(false);
                 //设置 整个工作表为一页
                 sheet.setFitToPage(true);
+
             }
             outReport = new ByteArrayOutputStream();
             ss.write(outReport);
@@ -302,6 +308,71 @@ public class FileUtils {
 
 
 
+    /**
+     * excel设置 打印缩放比例
+     *
+     * @param inputPath
+     * @param outPath
+     */
+    public static void setExcelScaleToPdf(String inputPath, String outPath) {
+        //读取excel文件
+        XSSFWorkbook workbook = null;
+        ByteArrayOutputStream outReport = null, bos = null;
+        ByteArrayInputStream byteArrayInputStream = null;
+        try {
+            workbook = new XSSFWorkbook(new FileInputStream(inputPath));
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        OutputStream fos = null;
+        try {
+            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {//获取每个Sheet表
+                XSSFSheet sheet = workbook.getSheetAt(i);
+                //打印设置
+                XSSFPrintSetup print = sheet.getPrintSetup();
+               // print.setLandscape(true); // 打印方向,true:横向,false:纵向(默认)
+             //   print.setFitHeight((short)0);//设置高度为自动分页
+                print.setFitWidth((short)1);//设置宽度为一页
+                print.setPaperSize(HSSFPrintSetup.A4_PAPERSIZE); //纸张类型
+//                print.setScale((short)55);//自定义缩放①,此处100为无缩放
+                //启用“适合页面”打印选项的标志
+                sheet.setFitToPage(true);
+            }
+            // Excel文件生成后存储的位置。
+            outReport = new ByteArrayOutputStream();
+            workbook.write(outReport);
+            byteArrayInputStream = new ByteArrayInputStream(outReport.toByteArray());
+            com.aspose.cells.Workbook wb = new com.aspose.cells.Workbook(byteArrayInputStream);
+            File pdfFile = new File(outPath);
+            if(!pdfFile.exists()){
+                pdfFile.mkdir();
+            }
+            wb.save(outPath, SaveFormat.PDF);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (fos != null) {
+                try {
+                    fos.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (workbook != null) {
+                try {
+                    workbook.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+
+
+
 
     public static void main123(String[] args) throws Exception {
 
@@ -337,8 +408,9 @@ public class FileUtils {
     }
 
 
-    public static void main23(String[] args) throws FileNotFoundException {
-        File file1 = ResourceUtil.getFile("/Users/hongchuangyanfa/fsdownload/1633774811681390592.html");
+    public static void main11(String[] args) throws FileNotFoundException {
+
+        /*File file1 = ResourceUtil.getFile("/Users/hongchuangyanfa/fsdownload/1633774811681390592.html");
         FileInputStream fileInputStream = new FileInputStream(file1);
         String htmlString = IoUtil.readToString(fileInputStream);
         // 解析 style
@@ -370,7 +442,7 @@ public class FileUtils {
         String[][] res = new String[redata.size()][]; // 存放转换结果的 二维数组
         for(int i=0; i<res.length; i++){ // 转换方法
             res[i] = redata.get(i).toArray(new String[redata.get(i).size()]);
-        }
+        }*/
 
     }
 }