Просмотр исходного кода

Merge remote-tracking branch 'origin/master'

chenr 2 месяцев назад
Родитель
Сommit
16f5fd0e87
88 измененных файлов с 2362 добавлено и 437 удалено
  1. 27 0
      blade-common/src/main/java/org/springblade/common/constant/WebsocketMsgConstant.java
  2. 2 3
      blade-common/src/main/java/org/springblade/common/utils/AsyncConfigurer.java
  3. 5 10
      blade-common/src/main/java/org/springblade/common/utils/BaseUtils.java
  4. 6 5
      blade-common/src/main/java/org/springblade/common/utils/CommonUtil.java
  5. 1 0
      blade-ops/blade-develop/src/main/java/org/springblade/develop/mapper/CodeMapper.java
  6. 0 1
      blade-ops/blade-resource/src/main/java/org/springblade/resource/builder/oss/MinioOssBuilder.java
  7. 2 54
      blade-ops/blade-resource/src/main/java/org/springblade/resource/builder/oss/OssBuilder.java
  8. 501 31
      blade-ops/blade-resource/src/main/java/org/springblade/resource/builder/ossre/MinioTemplateRe.java
  9. 5 3
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/feign/BusinessWebSocketClient.java
  10. 4 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/TrialSampleDataInfoVO.java
  11. 6 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/TrialSelfInspectionRecordVO.java
  12. 5 0
      blade-service-api/blade-manager-api/pom.xml
  13. 17 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/ContractInfo.java
  14. 90 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/SystemMsg.java
  15. 3 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/TableFile.java
  16. 5 3
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/feign/ManagerWebSocketClient.java
  17. 31 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/ArchiveSyncWbsVO.java
  18. 3 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/BaseInfo.java
  19. 1 1
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/FB02.java
  20. 4 4
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/InventoryForm.java
  21. 3 3
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/Payment.java
  22. 2 2
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/SubInterimMeterPaySummary.java
  23. 39 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/SystemAwaitMsgVO.java
  24. 19 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/SystemMsgVO.java
  25. 3 0
      blade-service-api/blade-meter-api/src/main/java/org/springblade/meter/vo/TaskDetailVO.java
  26. 11 1
      blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/feign/WebSocketClient.java
  27. 5 1
      blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/vo/MsgVO.java
  28. 26 0
      blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/vo/SystMsgVO.java
  29. 3 0
      blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/vo/UserInfoVO.java
  30. 42 0
      blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/vo/UserSingleVO.java
  31. 0 4
      blade-service/blade-business/src/main/java/org/springblade/business/controller/EVisaTaskCheckController.java
  32. 7 8
      blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java
  33. 1 2
      blade-service/blade-business/src/main/java/org/springblade/business/controller/TrialMaterialController.java
  34. 7 8
      blade-service/blade-business/src/main/java/org/springblade/business/feignClient/BusinessWebSocketClientImpl.java
  35. 30 2
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/EntrustInfoMapper.xml
  36. 1 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/TrialSampleInfoMapper.xml
  37. 2 2
      blade-service/blade-business/src/main/java/org/springblade/business/service/ITrialMaterialMobilizationService.java
  38. 5 10
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/EntrustInfoServiceImpl.java
  39. 5 17
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TaskServiceImpl.java
  40. 30 6
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialMaterialMobilizationServiceImpl.java
  41. 86 8
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialSelfInspectionRecordServiceImpl.java
  42. 15 5
      blade-service/blade-business/src/main/java/org/springblade/business/utils/FileUtils.java
  43. 19 15
      blade-service/blade-e-visa/src/main/java/org/springblade/evisa/controller/EVisaController.java
  44. 12 16
      blade-service/blade-e-visa/src/main/java/org/springblade/evisa/service/impl/EVisaServiceImpl.java
  45. 4 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/bean/TableInfo.java
  46. 6 4
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/APIController.java
  47. 74 15
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java
  48. 185 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/SystemMsgController.java
  49. 31 29
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/TableFileController.java
  50. 25 24
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/TextdictInfoController.java
  51. 33 8
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreeContractController.java
  52. 1 7
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreePrivateController.java
  53. 25 2
      blade-service/blade-manager/src/main/java/org/springblade/manager/feign/ExcelTabClientImpl.java
  54. 10 6
      blade-service/blade-manager/src/main/java/org/springblade/manager/feign/ManagerWebSocketClientImpl.java
  55. 1 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/feign/WbsTreePrivateClientImpl.java
  56. 34 12
      blade-service/blade-manager/src/main/java/org/springblade/manager/formula/impl/ExecutorMeter.java
  57. 88 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/job/SystemMsgJob.java
  58. 25 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/SystemMsgMapper.java
  59. 40 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/SystemMsgMapper.xml
  60. 2 2
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/TableFileMapper.java
  61. 2 2
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/TableFileMapper.xml
  62. 1 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreeContractMapper.java
  63. 3 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreeContractMapper.xml
  64. 9 10
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IExcelTabService.java
  65. 27 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/ISystemMsgService.java
  66. 2 2
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/ITableFileService.java
  67. 4 2
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IWbsTreeContractService.java
  68. 125 31
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ExcelTabServiceImpl.java
  69. 4 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/FormulaDaoImpl.java
  70. 13 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/FormulaServiceImpl.java
  71. 151 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/SystemMsgServiceImpl.java
  72. 4 4
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/TableFileServiceImpl.java
  73. 11 5
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeContractServiceImpl.java
  74. 3 0
      blade-service/blade-meter/src/main/java/org/springblade/meter/controller/MeterTreeController.java
  75. 18 5
      blade-service/blade-meter/src/main/java/org/springblade/meter/controller/TaskController.java
  76. 2 0
      blade-service/blade-meter/src/main/java/org/springblade/meter/feign/MeterWebSocketClientImpl.java
  77. 2 0
      blade-service/blade-meter/src/main/java/org/springblade/meter/mapper/ContractInventoryFormMapper.java
  78. 20 0
      blade-service/blade-meter/src/main/java/org/springblade/meter/mapper/ContractInventoryFormMapper.xml
  79. 3 0
      blade-service/blade-meter/src/main/java/org/springblade/meter/mapper/ContractMeterPeriodMapper.java
  80. 7 0
      blade-service/blade-meter/src/main/java/org/springblade/meter/mapper/ContractMeterPeriodMapper.xml
  81. 7 0
      blade-service/blade-meter/src/main/java/org/springblade/meter/mapper/MeterPeriodMapper.xml
  82. 3 0
      blade-service/blade-meter/src/main/java/org/springblade/meter/service/IContractInventoryFormService.java
  83. 9 0
      blade-service/blade-meter/src/main/java/org/springblade/meter/service/impl/ContractInventoryFormServiceImpl.java
  84. 2 1
      blade-service/blade-meter/src/main/java/org/springblade/meter/service/impl/TaskRepealMessageServiceImpl.java
  85. 15 0
      blade-service/blade-websocket/pom.xml
  86. 42 0
      blade-service/blade-websocket/src/main/java/org/springblade/websocket/config/TaskPoolConfig.java
  87. 6 0
      blade-service/blade-websocket/src/main/java/org/springblade/websocket/feign/WebSocketClientImpl.java
  88. 192 38
      blade-service/blade-websocket/src/main/java/org/springblade/websocket/service/WebSocketService.java

+ 27 - 0
blade-common/src/main/java/org/springblade/common/constant/WebsocketMsgConstant.java

@@ -0,0 +1,27 @@
+package org.springblade.common.constant;
+
+/**
+ * @Param   推送系统消息时所使用的标识
+ * @Author wangwl
+ * @Date 2024/9/9 9:30
+ **/
+public interface WebsocketMsgConstant {
+
+    /**
+     * 平台统一标识
+     */
+    //维护发布公告
+    String MSG_UPDATE_MSG = "msgUpdateMsg";
+    //系统普通公告
+    String MSG_SYSTEM_MSG = "msgSystemMsg";
+    //维护倒计时
+    String MSG_COUNT_DOWN = "msgCountDown";
+    //客户端从服务器获取公告
+    String GET_MSG = "getMsg";
+
+    /**
+     * 单个系统标识
+     */
+    //计量-消息提醒
+    String MSG_REMIND = "msgRemind";
+}

+ 2 - 3
blade-common/src/main/java/org/springblade/common/utils/AsyncConfigurer.java

@@ -15,17 +15,16 @@ public class AsyncConfigurer {
     /**
      * cpu 核心数量
      */
-    public static final int cpuNum =10 ;//Runtime.getRuntime().availableProcessors();
+    public static final int cpuNum =6 ;//Runtime.getRuntime().availableProcessors();
 
     /**
      * 线程池配置
-     *
      * @return
      */
     @Bean("taskExecutor1")
     public ThreadPoolExecutor getAsyncExecutor() {
         return new ThreadPoolMonitor(cpuNum
-                , 12
+                , 10
                 , 30
                 , TimeUnit.SECONDS
                 , new LinkedBlockingQueue<>(2000)

+ 5 - 10
blade-common/src/main/java/org/springblade/common/utils/BaseUtils.java

@@ -103,7 +103,7 @@ public class BaseUtils {
         }
     }
 
-    /*最小分割片*/
+    /**最小分割片*/
     public static int sliceNumber(Integer len,Integer capacity){
         return (int)Math.ceil(len/(double)capacity);
     }
@@ -159,6 +159,10 @@ public class BaseUtils {
         }
     }
 
+    public static String bigDecimalScale(Object s,int scale){
+             return str2BigDecimal(s).setScale(scale,RoundingMode.HALF_UP).stripTrailingZeros().toPlainString();
+    }
+
     /*默认返回零*/
     public static Double obj2DoubleZero(Object obj) {
         if(obj instanceof  Double){
@@ -597,13 +601,4 @@ public static List<Object> obj2List(Object obj) {
                 .collect(Collectors.toList());
     }
 
-
-/*
-    public static void main(String[] args) {
-        getTickUnit(202401,202410).forEach(System.out::println);
-    }
-*/
-
-
-
 }

+ 6 - 5
blade-common/src/main/java/org/springblade/common/utils/CommonUtil.java

@@ -115,10 +115,8 @@ public class CommonUtil {
      * 根据OSS文件路径获取文件输入流
      */
     public static synchronized InputStream getOSSInputStream(String urlStr) throws Exception {
+        urlStr = replaceOssUrl(urlStr);
         //获取OSS文件流
-        if(urlStr!=null && urlStr.indexOf("183.247.216.148:9000")>=0){// nimio 甬台温 本地部署修改
-            urlStr = urlStr.replace("https://","http://").replace("183.247.216.148","152.168.2.15").replace(":9000//",":9000/");
-        }
         URL url =new URL(urlStr);
         final URLConnection conn = url.openConnection();
         conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
@@ -633,7 +631,6 @@ public class CommonUtil {
     }
 
     public static String replaceOssUrl(String url) {
-
         String osName = System.getProperty("os.name");
         if (osName != null && osName.toLowerCase().contains("Cloud Linux")) {
             // 如果当前操作系统是Linux系统
@@ -646,7 +643,11 @@ public class CommonUtil {
         //本地部署- 甬台温
         if (url.indexOf("183.247.216.148")>=0) {
             // 如果当前环境变量不包含linuxtesttest,则替换URL中的oss路径
-            url = url.replace("https://","http://").replace("183.247.216.148","152.168.2.15").replace(":9000//",":9000/");
+            if(SystemUtils.isMacOs() || SystemUtils.isWindows()){
+                url = url.replace("https://","http://").replace(":9000//",":9000/");
+            }else{
+                url = url.replace("https://","http://").replace("183.247.216.148","152.168.2.15").replace(":9000//",":9000/");
+            }
         }
         return url;
     }

+ 1 - 0
blade-ops/blade-develop/src/main/java/org/springblade/develop/mapper/CodeMapper.java

@@ -16,6 +16,7 @@
  */
 package org.springblade.develop.mapper;
 
+import cn.hutool.db.Db;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import org.springblade.develop.entity.Code;
 

+ 0 - 1
blade-ops/blade-resource/src/main/java/org/springblade/resource/builder/oss/MinioOssBuilder.java

@@ -41,7 +41,6 @@ public class MinioOssBuilder {
                 .build();
         OssProperties ossProperties = new OssProperties();
         ossProperties.setEndpoint(oss.getEndpoint());
-        ossProperties.setEndpoint("http://183.247.216.148:9000/");
         ossProperties.setAccessKey(oss.getAccessKey());
         ossProperties.setSecretKey(oss.getSecretKey());
         ossProperties.setBucketName(oss.getBucketName());

+ 2 - 54
blade-ops/blade-resource/src/main/java/org/springblade/resource/builder/oss/OssBuilder.java

@@ -59,65 +59,11 @@ public class OssBuilder {
         this.ossService = ossService;
     }
 
-
-
     /**
      * oss配置缓存池
      */
     private final Map<String, Oss> ossPool = new ConcurrentHashMap<>();
 
-/*
-    *//**
-     * 获取template
-     *
-     * @return OssTemplate
-     *//*
-    public OssTemplate template() {
-        return template(StringPool.EMPTY);
-    }
-     private final Map<String, OssTemplate> templatePool = new ConcurrentHashMap<>();
-    *//**
-     * 获取template
-     *
-     * @param code 资源编号--minio
-     * @return OssTemplate
-     *//*
-    public OssTemplate template(String code) {
-        String tenantId = AuthUtil.getTenantId();
-        Oss oss = getOss(tenantId, code);
-        Oss ossCached = ossPool.get(tenantId);
-        OssTemplate template = templatePool.get(tenantId);
-        // 若为空或者不一致,则重新加载
-        if (Func.hasEmpty(template, ossCached) || !oss.getEndpoint().equals(ossCached.getEndpoint()) || !oss.getAccessKey().equals(ossCached.getAccessKey())) {
-            synchronized (OssBuilder.class) {
-                template = templatePool.get(tenantId);
-                if (Func.hasEmpty(template, ossCached) || !oss.getEndpoint().equals(ossCached.getEndpoint()) || !oss.getAccessKey().equals(ossCached.getAccessKey())) {
-                    OssRule ossRule;
-                    // 若采用默认设置则开启多租户模式, 若是用户自定义oss则不开启
-                    if (oss.getEndpoint().equals(ossProperties.getEndpoint()) && oss.getAccessKey().equals(ossProperties.getAccessKey()) && ossProperties.getTenantMode()) {
-                        ossRule = new BladeOssRule(Boolean.TRUE);
-                    } else {
-                        ossRule = new BladeOssRule(Boolean.FALSE);
-                    }
-                    //获取对象
-                    if (oss.getCategory() == OssEnum.MINIO.getCategory()) {
-                        template = MinioOssBuilder.template(oss, ossRule);
-                    } else if (oss.getCategory() == OssEnum.QINIU.getCategory()) {
-                        template = QiniuOssBuilder.template(oss, ossRule);
-                    } else if (oss.getCategory() == OssEnum.ALI.getCategory()) {
-                        template = AliOssBuilder.template(oss, ossRule);
-                    } else if (oss.getCategory() == OssEnum.TENCENT.getCategory()) {
-                        template = TencentOssBuilder.template(oss, ossRule);
-                    }
-                    templatePool.put(tenantId, template);
-                    ossPool.put(tenantId, oss);
-                }
-            }
-        }
-        return template;
-    }*/
-
-
     /**
      * OssTemplate配置缓存池
      */
@@ -139,6 +85,7 @@ public class OssBuilder {
     public OssTemplateRe template(String code) {
         String tenantId = AuthUtil.getTenantId();
         Oss oss = getOss(tenantId, code);
+       // oss.setEndpoint("http://183.247.216.148:9000/");
         Oss ossCached = ossPool.get(tenantId);
         OssTemplateRe template = templatePool.get(tenantId);
         // 若为空或者不一致,则重新加载
@@ -153,6 +100,7 @@ public class OssBuilder {
                     } else {
                         ossRule = new BladeOssRule(Boolean.FALSE);
                     }
+
                     //获取对象
                    if (oss.getCategory() == OssEnum.MINIO.getCategory()) {
                         template = MinioOssBuilder.template(oss, ossRule);

+ 501 - 31
blade-ops/blade-resource/src/main/java/org/springblade/resource/builder/ossre/MinioTemplateRe.java

@@ -1,49 +1,519 @@
-//
-// Source code recreated from a .class file by IntelliJ IDEA
-// (powered by FernFlower decompiler)
-//
-
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ * <p>
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ * <p>
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ * <p>
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ * <p>
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software
+ * remains with BladeX.
+ * <p>
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ * <p>
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ * <p>
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
 package org.springblade.resource.builder.ossre;
 
+import com.aliyun.oss.OSSClient;
 import com.aliyun.oss.model.*;
-import io.minio.MinioClient;
-import org.springblade.core.oss.MinioTemplate;
+import io.minio.*;
+import io.minio.http.Method;
+import io.minio.messages.Bucket;
+import io.minio.messages.DeleteObject;
+import lombok.AllArgsConstructor;
+import lombok.SneakyThrows;
+import org.springblade.common.utils.CommonUtil;
+import org.springblade.core.oss.OssTemplate;
+import org.springblade.core.oss.enums.PolicyType;
 import org.springblade.core.oss.model.BladeFile;
+import org.springblade.core.oss.model.OssFile;
 import org.springblade.core.oss.props.OssProperties;
 import org.springblade.core.oss.rule.OssRule;
+import org.springblade.core.tool.utils.DateUtil;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.StringPool;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springframework.web.multipart.MultipartFile;
 
 import java.io.InputStream;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+/**
+ * MinIOTemplate
+ *
+ * @author Chill
+ */
+@AllArgsConstructor
+public class MinioTemplateRe implements OssTemplateRe {
+
+	/**
+	 * MinIO客户端
+	 */
+	private final MinioClient client;
+
+	/**
+	 * 存储桶命名规则
+	 */
+	private final OssRule ossRule;
+
+	/**
+	 * 配置类
+	 */
+	private final OssProperties ossProperties;
+
+
+	@Override
+	@SneakyThrows
+	public void makeBucket(String bucketName) {
+		if (
+			!client.bucketExists(
+				BucketExistsArgs.builder().bucket(getBucketName(bucketName)).build()
+			)
+		) {
+			client.makeBucket(
+				MakeBucketArgs.builder().bucket(getBucketName(bucketName)).build()
+			);
+			client.setBucketPolicy(
+				SetBucketPolicyArgs.builder().bucket(getBucketName(bucketName)).config(getPolicyType(getBucketName(bucketName), PolicyType.READ)).build()
+			);
+		}
+	}
+
+	@SneakyThrows
+	public Bucket getBucket() {
+		return getBucket(getBucketName());
+	}
+
+	@SneakyThrows
+	public Bucket getBucket(String bucketName) {
+		Optional<Bucket> bucketOptional = client.listBuckets().stream().filter(bucket -> bucket.name().equals(getBucketName(bucketName))).findFirst();
+		return bucketOptional.orElse(null);
+	}
+
+	@SneakyThrows
+	public List<Bucket> listBuckets() {
+		return client.listBuckets();
+	}
+
+	@Override
+	@SneakyThrows
+	public void removeBucket(String bucketName) {
+		client.removeBucket(
+			RemoveBucketArgs.builder().bucket(getBucketName(bucketName)).build()
+		);
+	}
+
+	@Override
+	@SneakyThrows
+	public boolean bucketExists(String bucketName) {
+		return client.bucketExists(
+			BucketExistsArgs.builder().bucket(getBucketName(bucketName)).build()
+		);
+	}
+
+	@Override
+	@SneakyThrows
+	public void copyFile(String bucketName, String fileName, String destBucketName) {
+		copyFile(bucketName, fileName, destBucketName, fileName);
+	}
+
+	@Override
+	@SneakyThrows
+	public void copyFile(String bucketName, String fileName, String destBucketName, String destFileName) {
+		client.copyObject(
+			CopyObjectArgs.builder()
+				.source(CopySource.builder().bucket(getBucketName(bucketName)).object(fileName).build())
+				.bucket(getBucketName(destBucketName))
+				.object(destFileName)
+				.build()
+		);
+	}
+
+	@Override
+	@SneakyThrows
+	public OssFile statFile(String fileName) {
+		return statFile(ossProperties.getBucketName(), fileName);
+	}
+
+	@Override
+	@SneakyThrows
+	public OssFile statFile(String bucketName, String fileName) {
+		StatObjectResponse stat = client.statObject(
+			StatObjectArgs.builder().bucket(getBucketName(bucketName)).object(fileName).build()
+		);
+		OssFile ossFile = new OssFile();
+		ossFile.setName(Func.isEmpty(stat.object()) ? fileName : stat.object());
+		ossFile.setLink(fileLink(ossFile.getName()));
+		ossFile.setHash(String.valueOf(stat.hashCode()));
+		ossFile.setLength(stat.size());
+		ossFile.setPutTime(DateUtil.toDate(stat.lastModified().toLocalDateTime()));
+		ossFile.setContentType(stat.contentType());
+		return ossFile;
+	}
+
+	@Override
+	public String filePath(String fileName) {
+		return getBucketName().concat(StringPool.SLASH).concat(fileName);
+	}
+
+	@Override
+	public String filePath(String bucketName, String fileName) {
+		return getBucketName(bucketName).concat(StringPool.SLASH).concat(fileName);
+	}
+
+	@Override
+	@SneakyThrows
+	public String fileLink(String fileName) {
+		return getEndpoint().concat(StringPool.SLASH).concat(getBucketName()).concat(StringPool.SLASH).concat(fileName);
+
+	}
+
+	@Override
+	@SneakyThrows
+	public String fileLink(String bucketName, String fileName) {
+		return getEndpoint().concat(StringPool.SLASH).concat(getBucketName(bucketName)).concat(StringPool.SLASH).concat(fileName);
+	}
+
+
+	@Override
+	@SneakyThrows
+	public BladeFile putFile(MultipartFile file) {
+		return putFile(ossProperties.getBucketName(), file.getOriginalFilename(), file);
+	}
+
+	@Override
+	@SneakyThrows
+	public BladeFile putFile(String fileName, MultipartFile file) {
+		return putFile(ossProperties.getBucketName(), fileName, file);
+	}
+
+	@Override
+	@SneakyThrows
+	public BladeFile putFile(String bucketName, String fileName, MultipartFile file) {
+		return putFile(bucketName, file.getOriginalFilename(), file.getInputStream());
+	}
+
+	@Override
+	@SneakyThrows
+	public BladeFile putFile(String fileName, InputStream stream) {
+		return putFile(ossProperties.getBucketName(), fileName, stream);
+	}
+
+	@Override
+	@SneakyThrows
+	public BladeFile putFile(String bucketName, String fileName, InputStream stream) {
+		return putFile(bucketName, fileName, stream, "application/octet-stream");
+	}
+
+	@SneakyThrows
+	public BladeFile putFile(String bucketName, String fileName, InputStream stream, String contentType) {
+		makeBucket(bucketName);
+		String originalName = fileName;
+		fileName = getFileName(fileName);
+		try {
+			client.putObject(
+				PutObjectArgs.builder()
+					.bucket(getBucketName(bucketName))
+					.object(fileName)
+					.stream(stream, stream.available(), -1)
+					.contentType(contentType)
+					.build()
+			);
+		} catch (Exception e) {
+			e.printStackTrace();
+		} finally {
+			try {
+				if (stream != null) {
+					stream.close();
+				}
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+		}
+		BladeFile file = new BladeFile();
+		file.setOriginalName(originalName);
+		file.setName(fileName);
+		file.setDomain(getOssHost(bucketName));
+		file.setLink(fileLink(bucketName, fileName));
+		return file;
+	}
+
+	@Override
+	@SneakyThrows
+	public void removeFile(String fileName) {
+		removeFile(ossProperties.getBucketName(), fileName);
+	}
+
+	@Override
+	@SneakyThrows
+	public void removeFile(String bucketName, String fileName) {
+		client.removeObject(
+			RemoveObjectArgs.builder().bucket(getBucketName(bucketName)).object(fileName).build()
+		);
+	}
+
+	@Override
+	@SneakyThrows
+	public void removeFiles(List<String> fileNames) {
+		removeFiles(ossProperties.getBucketName(), fileNames);
+	}
+
+	@Override
+	@SneakyThrows
+	public void removeFiles(String bucketName, List<String> fileNames) {
+		Stream<DeleteObject> stream = fileNames.stream().map(DeleteObject::new);
+		client.removeObjects(RemoveObjectsArgs.builder().bucket(getBucketName(bucketName)).objects(stream::iterator).build());
+	}
+
+	/**
+	 * 获取私有存储文件输入流
+	 *
+	 * @param fileName 存储桶文件名称
+	 * @return InputStream
+	 */
+
+	public InputStream statFileStream(String fileName) {
+		return statFileStream(ossProperties.getBucketName(), fileName);
+	}
+
+	/**
+	 * 获取私有存储文件输入流
+	 *
+	 * @param bucketName 存储桶名称
+	 * @param fileName   存储桶文件名称
+	 * @return InputStream
+	 */
+
+	@SneakyThrows
+	public InputStream statFileStream(String bucketName, String fileName) {
+		return client.getObject(
+			GetObjectArgs.builder().bucket(getBucketName(bucketName)).object(fileName).build()
+		);
+	}
+
+	/**
+	 * 根据规则生成存储桶名称规则
+	 *
+	 * @return String
+	 */
+	private String getBucketName() {
+		return getBucketName(ossProperties.getBucketName());
+	}
+
+	/**
+	 * 根据规则生成存储桶名称规则
+	 *
+	 * @param bucketName 存储桶名称
+	 * @return String
+	 */
+	private String getBucketName(String bucketName) {
+		return ossRule.bucketName(bucketName);
+	}
+
+	/**
+	 * 根据规则生成文件名称规则
+	 *
+	 * @param originalFilename 原始文件名
+	 * @return string
+	 */
+	private String getFileName(String originalFilename) {
+		return ossRule.fileName(originalFilename);
+	}
+
+	/**
+	 * 获取文件外链
+	 *
+	 * @param bucketName bucket名称
+	 * @param fileName   文件名称
+	 * @param expires    过期时间 <=7 秒级
+	 * @return url
+	 */
+	@SneakyThrows
+	public String getPresignedObjectUrl(String bucketName, String fileName, Integer expires) {
+		return client.getPresignedObjectUrl(
+			GetPresignedObjectUrlArgs.builder()
+				.method(Method.GET)
+				.bucket(getBucketName(bucketName))
+				.object(fileName)
+				.expiry(expires)
+				.build()
+		);
+	}
+
+	/**
+	 * 获取存储桶策略
+	 *
+	 * @param policyType 策略枚举
+	 * @return String
+	 */
+	public String getPolicyType(PolicyType policyType) {
+		return getPolicyType(getBucketName(), policyType);
+	}
+
+	/**
+	 * 获取存储桶策略
+	 *
+	 * @param bucketName 存储桶名称
+	 * @param policyType 策略枚举
+	 * @return String
+	 */
+	public static String getPolicyType(String bucketName, PolicyType policyType) {
+		StringBuilder builder = new StringBuilder();
+		builder.append("{\n");
+		builder.append("    \"Statement\": [\n");
+		builder.append("        {\n");
+		builder.append("            \"Action\": [\n");
+
+		switch (policyType) {
+			case WRITE:
+				builder.append("                \"s3:GetBucketLocation\",\n");
+				builder.append("                \"s3:ListBucketMultipartUploads\"\n");
+				break;
+			case READ_WRITE:
+				builder.append("                \"s3:GetBucketLocation\",\n");
+				builder.append("                \"s3:ListBucket\",\n");
+				builder.append("                \"s3:ListBucketMultipartUploads\"\n");
+				break;
+			default:
+				builder.append("                \"s3:GetBucketLocation\"\n");
+				break;
+		}
+
+		builder.append("            ],\n");
+		builder.append("            \"Effect\": \"Allow\",\n");
+		builder.append("            \"Principal\": \"*\",\n");
+		builder.append("            \"Resource\": \"arn:aws:s3:::");
+		builder.append(bucketName);
+		builder.append("\"\n");
+		builder.append("        },\n");
+		if (PolicyType.READ.equals(policyType)) {
+			builder.append("        {\n");
+			builder.append("            \"Action\": [\n");
+			builder.append("                \"s3:ListBucket\"\n");
+			builder.append("            ],\n");
+			builder.append("            \"Effect\": \"Deny\",\n");
+			builder.append("            \"Principal\": \"*\",\n");
+			builder.append("            \"Resource\": \"arn:aws:s3:::");
+			builder.append(bucketName);
+			builder.append("\"\n");
+			builder.append("        },\n");
+
+		}
+		builder.append("        {\n");
+		builder.append("            \"Action\": ");
+
+		switch (policyType) {
+			case WRITE:
+				builder.append("[\n");
+				builder.append("                \"s3:AbortMultipartUpload\",\n");
+				builder.append("                \"s3:DeleteObject\",\n");
+				builder.append("                \"s3:ListMultipartUploadParts\",\n");
+				builder.append("                \"s3:PutObject\"\n");
+				builder.append("            ],\n");
+				break;
+			case READ_WRITE:
+				builder.append("[\n");
+				builder.append("                \"s3:AbortMultipartUpload\",\n");
+				builder.append("                \"s3:DeleteObject\",\n");
+				builder.append("                \"s3:GetObject\",\n");
+				builder.append("                \"s3:ListMultipartUploadParts\",\n");
+				builder.append("                \"s3:PutObject\"\n");
+				builder.append("            ],\n");
+				break;
+			default:
+				builder.append("\"s3:GetObject\",\n");
+				break;
+		}
+
+		builder.append("            \"Effect\": \"Allow\",\n");
+		builder.append("            \"Principal\": \"*\",\n");
+		builder.append("            \"Resource\": \"arn:aws:s3:::");
+		builder.append(bucketName);
+		builder.append("/*\"\n");
+		builder.append("        }\n");
+		builder.append("    ],\n");
+		builder.append("    \"Version\": \"2012-10-17\"\n");
+		builder.append("}\n");
+		return builder.toString();
+	}
+
+	/**
+	 * 获取域名
+	 *
+	 * @param bucketName 存储桶名称
+	 * @return String
+	 */
+	public String getOssHost(String bucketName) {
+		return getEndpoint() + StringPool.SLASH + getBucketName(bucketName);
+	}
 
+	/**
+	 * 获取域名
+	 *
+	 * @return String
+	 */
+	public String getOssHost() {
+		return getOssHost(ossProperties.getBucketName());
+	}
 
-public class MinioTemplateRe extends MinioTemplate implements OssTemplateRe{
+	/**
+	 * 获取服务地址
+	 *
+	 * @return String
+	 */
+	public String getEndpoint() {
+	//	if (StringUtil.isBlank(ossProperties.getTransformEndpoint())) {
+			//return ossProperties.getEndpoint();
+	//	}
+	//	return ossProperties.getTransformEndpoint();
+		// 将内网转化外网使用
+	//	ossProperties.setEndpoint("http://183.247.216.148:9000");
+		//return ossProperties.getEndpoint();
+		return "http://183.247.216.148:9000";
+	}
 
-    public MinioTemplateRe(MinioClient client, OssRule ossRule, OssProperties ossProperties) {
-        super(client, ossRule, ossProperties);
-    }
 
+	@Override
+	public UploadPartResult uploadPart(UploadPartRequest request) {
+		return null;
+	}
 
-    @Override
-    public UploadPartResult uploadPart(UploadPartRequest request) {
-        return null;
-    }
+	@Override
+	public CompleteMultipartUploadResult completeMultipartUpload(CompleteMultipartUploadRequest request) {
+		return null;
+	}
 
-    @Override
-    public CompleteMultipartUploadResult completeMultipartUpload(CompleteMultipartUploadRequest request) {
-        return null;
-    }
+	@Override
+	public InitiateMultipartUploadResult initiateMultipartUpload(InitiateMultipartUploadRequest request) {
+		return null;
+	}
 
-    @Override
-    public InitiateMultipartUploadResult initiateMultipartUpload(InitiateMultipartUploadRequest request) {
-        return null;
-    }
+	@Override
+	public Long getAllFileSizeByFileUrl(String fileUrl) {
+		return 0L;
+	}
 
-    @Override
-    public Long getAllFileSizeByFileUrl(String fileUrl) {
-        return 0L;
-    }
+	@Override
+	public BladeFile putFileWithPath(String fileName, String filePath, Long projectId, InputStream stream) {
+		return null;
+	}
 
-    @Override
-    public BladeFile putFileWithPath(String fileName, String filePath, Long projectId, InputStream stream) {
-        return null;
-    }
+	public MinioTemplateRe(final MinioClient ossClient, final OssProperties ossProperties, final OssRule ossRule) {
+		this.client = ossClient;
+		this.ossProperties = ossProperties;
+		this.ossRule = ossRule;
+	}
 }

+ 5 - 3
blade-service-api/blade-business-api/src/main/java/org/springblade/business/feign/BusinessWebSocketClient.java

@@ -2,9 +2,12 @@ package org.springblade.business.feign;
 
 
 import org.springblade.common.constant.BusinessConstant;
+import org.springblade.websocket.vo.UserInfoVO;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.stereotype.Component;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestParam;
 
 import java.util.Map;
@@ -13,7 +16,6 @@ import java.util.Map;
 @Component
 public interface BusinessWebSocketClient {
 
-    @GetMapping(value = "/business/getWebsocketMsg")
-    Map<String, String> getWebsocketMsg(@RequestParam String projectId, @RequestParam String contractId, @RequestParam String userIdResult);
-
+    @PostMapping(value = "/meter/pushMsg")
+    void pushMsg(@RequestBody UserInfoVO vo);
 }

+ 4 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/TrialSampleDataInfoVO.java

@@ -104,5 +104,9 @@ public class TrialSampleDataInfoVO extends TrialSampleInfo {
      */
     @ApiModelProperty(value = "是否留样")
     private String isSample;
+    /**
+     * 入库时间
+     */
+    private String sampleTime;
 
 }

+ 6 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/TrialSelfInspectionRecordVO.java

@@ -29,4 +29,10 @@ public class TrialSelfInspectionRecordVO extends TrialSelfInspectionRecord {
     @ApiModelProperty("原材料检测报告ids(试验记录id)")
     private String rawMaterialIds;
 
+    @ApiModelProperty("委托单名称")
+    private String entrustName;
+
+    @ApiModelProperty("委托单编号")
+    private String entrustNo;
+
 }

+ 5 - 0
blade-service-api/blade-manager-api/pom.xml

@@ -13,6 +13,11 @@
     <name>${project.artifactId}</name>
     <version>${bladex.project.version}</version>
     <dependencies>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-websocket-api</artifactId>
+            <version>${bladex.project.version}</version>
+        </dependency>
         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>fastjson</artifactId>

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

@@ -172,6 +172,23 @@ public class ContractInfo extends BaseEntity {
     @ApiModelProperty(value = "计量是否允许超计 '0'否 '1'是")
     private Integer isOverMeter;
 
+    @ApiModelProperty(value = "项目里程")
+    private BigDecimal projectMileage;
+
+    public BigDecimal getProjectMileage() {
+        if (projectMileage == null){
+            return null;
+        }else {
+            return new BigDecimal(projectMileage.stripTrailingZeros().toPlainString());
+        }
+    }
+
+    public void setProjectMileage(BigDecimal projectMileage) {
+        if (projectMileage != null) {
+            this.projectMileage = new BigDecimal(projectMileage.stripTrailingZeros().toPlainString());
+        }
+    }
+
 
     public String archivesUnit() {
 

+ 90 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/SystemMsg.java

@@ -0,0 +1,90 @@
+package org.springblade.manager.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.core.mp.base.BaseEntity;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+
+
+/**
+ * @Param
+ * @Author wangwl
+ * @Date 2024/8/29 16:07
+ **/
+@Data
+@TableName("m_system_msg")
+@EqualsAndHashCode(callSuper = true)
+public class SystemMsg extends BaseEntity {
+
+    @ApiModelProperty(value = "公告类型:1维护公告2普通公告(会在推送倒计时时,临时借位为3)")
+    @NotNull(message = "请传入公告类型!")
+    private Integer msgType;
+
+    @DateTimeFormat(
+            pattern = "yyyy-MM-dd HH:mm:ss"
+    )
+    @JsonFormat(
+            pattern = "yyyy-MM-dd HH:mm:ss"
+    )
+    @ApiModelProperty(value = "发布时间")
+    @NotNull(message = "请传入发布时间!")
+    private LocalDateTime pushDateTime;
+
+    @ApiModelProperty(value = "更新服务类型字符串拼接:1前端2后端")
+    private String updateServerType;
+
+    @ApiModelProperty(value = "更新代码类型字符串拼接:1需求2BUG")
+    private String updateCodeType;
+
+    @ApiModelProperty(value = "推送系统:系统名称逗号拼接")
+    @NotNull(message = "请传入推送系统!")
+    private String pushSystem;
+
+    @ApiModelProperty(value = "发布内容")
+    private String msgContent;
+
+    @ApiModelProperty(value = "发布备注")
+    private String pushRemark;
+
+    @ApiModelProperty(value = "创建人名称")
+    private String creatUserName;
+
+    @ApiModelProperty(value = "公告显示时间分钟(用于普通公告)")
+    private Integer msgShowTime;
+
+    @ApiModelProperty(value = "公告结束显示时间(用于普通公告)")
+    private LocalDateTime pushEndDateTime;
+
+    @ApiModelProperty(value = "发布状态:1待发布,2已发布,3已取消")
+    private Integer pushStatus;
+
+    @DateTimeFormat(
+            pattern = "yyyy-MM-dd HH:mm:ss"
+    )
+    @JsonFormat(
+            pattern = "yyyy-MM-dd HH:mm:ss"
+    )
+    @ApiModelProperty(value = "取消时间")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime cancelDateTime;
+
+    @ApiModelProperty(value = "公告提醒分钟(用于维护公告)")
+    private Integer msgWarnTime;
+
+    @ApiModelProperty(value = "公告开始提醒时间(用于维护公告)")
+    private LocalDateTime pushWarnDateTime;
+
+    @ApiModelProperty(value = "公告倒计时分钟(用于维护公告)")
+    private Integer msgCountDownTime;
+
+    @ApiModelProperty(value = "公告开始倒计时时间(用于维护公告)")
+    private LocalDateTime pushCountDownDateTime;
+}

+ 3 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/TableFile.java

@@ -93,4 +93,7 @@ public class TableFile implements Serializable {
 
     private Long contractId;
 
+    @ApiModelProperty(value = "1施工2监理")
+    private Integer classify;
+
 }

+ 5 - 3
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/feign/ManagerWebSocketClient.java

@@ -1,9 +1,12 @@
 package org.springblade.manager.feign;
 
 import org.springblade.common.constant.LauncherConstant;
+import org.springblade.websocket.vo.UserInfoVO;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.stereotype.Component;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestParam;
 
 import java.util.Map;
@@ -12,7 +15,6 @@ import java.util.Map;
 @Component
 public interface ManagerWebSocketClient {
 
-    @GetMapping(value = "/manager/getWebsocketMsg")
-    Map<String, String> getWebsocketMsg(@RequestParam String projectId, @RequestParam String contractId, @RequestParam String userIdResult);
-
+    @PostMapping(value = "/meter/pushMsg")
+    void pushMsg(@RequestBody UserInfoVO vo);
 }

+ 31 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/ArchiveSyncWbsVO.java

@@ -0,0 +1,31 @@
+package org.springblade.manager.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @Param   档案同步质检影像资料VO
+ * @Author wangwl
+ * @Date 2024/9/12 16:02
+ **/
+@Data
+public class ArchiveSyncWbsVO {
+
+    @ApiModelProperty(value = "主键id")
+    private Long pKeyId;
+
+    @ApiModelProperty(value = "父主键id")
+    private Long parentId;
+
+    @ApiModelProperty(value = "节点名称")
+    private String nodeName;
+
+    @ApiModelProperty(value = "节点全称")
+    private String fullName;
+
+    @ApiModelProperty(value = "祖级id列表")
+    private String ancestors;
+
+    @ApiModelProperty(value = "排序")
+    private Integer sort;
+}

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

@@ -106,6 +106,9 @@ public class BaseInfo  implements  DataModel{
     /**结束桩号*/
     @JSONField(name = "key_26",label="结束桩号",ordinal = 13)
     private String endStation;
+    /**里程信息*/
+    @JSONField(name = "key_27",label="里程信息",ordinal = 13)
+    private String   projectMileage;
 
 /*    @JSONField(name = "key_27",label="动员预付款占合同比例",ordinal = 13)
     private String startRatio="10";

+ 1 - 1
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/FB02.java

@@ -56,7 +56,7 @@ public class FB02 extends EvaSummary<Item02>{
                   this.fm.put(fd.getCode(),(List<Item02> l,Integer pn)->l.stream().map(Item02::getSubItem).collect(Collectors.toList()));
               }else if(fd.getEName().contains("序号")){
                   this.sn=fd;
-                  this.fm.put(fd.getCode(),(List<Item02> l,Integer pn)->IntStream.range(0, l.size()).boxed().map(i->i+pn*l.size()).collect(Collectors.toList()));
+                  this.fm.put(fd.getCode(),(List<Item02> l,Integer pn)->IntStream.range(0, l.size()).boxed().map(i->i+pn*l.size()+1).collect(Collectors.toList()));
               }else if(fd.getEName().contains("实测项目")){
                   this.name=fd;
                   this.fm.put(fd.getCode(),(List<Item02> l,Integer pn)->l.stream().map(Item02::getName).collect(Collectors.toList()));

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

@@ -26,11 +26,11 @@ public class InventoryForm {
     private String currentPrice;
     /*中标价格*/
     private  String bidPrice;
-    /*合同数量*/
-    private Integer contractTotal;
-    /*合同金额*/
+    /**合同数量*/
+    private String contractTotal;
+    /**合同金额*/
     private String contractMoney;
-    /*变更后的金额*/
+    /**变更后的金额*/
     private String changeMoney;
 
 }

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

@@ -33,11 +33,11 @@ public class Payment {
     /**单位*/
     private String unit;
     /**合同数量*/
-    private Integer contractTotal;
+    private String contractTotal;
     /**变更数量*/
-    private Integer changeTotal;
+    private String changeTotal;
     /**完成数量*/
-    private Double completed;
+    private String completed;
     /**消费金额*/
     private String money;
     /**章节*/

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

@@ -84,11 +84,11 @@ public class SubInterimMeterPaySummary implements  DataModel{
         this.setCurrentPeriodPay(list.stream().filter(BaseUtils::isNumber).map(BigDecimal::new).reduce(BigDecimal.ZERO,BigDecimal::add).toString());
     }
 
-    public void completedAdd(Double n){
+    public void completedAdd(String n){
         List<Object> list = new ArrayList<>();
         list.add(this.getCompleted());
         list.add(n);
-        this.setCompleted(String.valueOf(list.stream().filter(BaseUtils::isNumber).map(Object::toString).mapToDouble(BaseUtils::obj2DoubleZero).sum()));
+        this.setCompleted(list.stream().map(BaseUtils::str2BigDecimal).reduce(BigDecimal.ZERO,BigDecimal::add).toPlainString());
     }
 
     /*获取分项工程元素码*/

+ 39 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/SystemAwaitMsgVO.java

@@ -0,0 +1,39 @@
+package org.springblade.manager.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.manager.entity.SystemMsg;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * @Param   系统待发布消息VO
+ * @Author wangwl
+ * @Date 2024/8/29 16:47
+ **/
+@Data
+public class SystemAwaitMsgVO {
+
+    @ApiModelProperty(value = "发布公告")
+    private List<MsgInfo> updateMsg;
+
+    @ApiModelProperty(value = "普通公告")
+    private List<MsgInfo> systemMsg;
+
+    @ApiModelProperty(value = "待发布数量")
+    private Integer msgTotal;
+
+    @Data
+    public static class MsgInfo{
+        @ApiModelProperty(value = "待发布数量")
+        private Integer AwaitMsgTotal;
+
+        @ApiModelProperty(value = "创建人名称")
+        private String creatUserName;
+
+        @ApiModelProperty(value = "发布时间")
+        private LocalDateTime pushDateTime;
+    }
+}

+ 19 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/SystemMsgVO.java

@@ -0,0 +1,19 @@
+package org.springblade.manager.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.manager.entity.SystemMsg;
+
+/**
+ * @Param
+ * @Author wangwl
+ * @Date 2024/8/29 16:47
+ **/
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class SystemMsgVO extends SystemMsg {
+
+    @ApiModelProperty(value = "公告类型名称")
+    private String msgTypeName;
+}

+ 3 - 0
blade-service-api/blade-meter-api/src/main/java/org/springblade/meter/vo/TaskDetailVO.java

@@ -49,4 +49,7 @@ public class TaskDetailVO implements Serializable {
 
     @ApiModelProperty(value = "意见信息")
     private MeterApproveOpinion meterApproveOpinion;
+
+    @ApiModelProperty(value = "需要计算的key")
+    private List<String> calculateKey;
 }

+ 11 - 1
blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/feign/WebSocketClient.java

@@ -1,9 +1,9 @@
 package org.springblade.websocket.feign;
 
 import org.springblade.common.constant.LauncherConstant;
+import org.springblade.websocket.vo.SystMsgVO;
 import org.springblade.websocket.vo.UserInfoVO;
 import org.springframework.cloud.openfeign.FeignClient;
-import org.springframework.stereotype.Component;
 import org.springframework.web.bind.annotation.*;
 
 /**
@@ -13,6 +13,16 @@ import org.springframework.web.bind.annotation.*;
  **/
 @FeignClient(value = LauncherConstant.APPLICATION_WEBSOCKET_NAME)
 public interface WebSocketClient {
+    /**
+     * 推送一个用户的消息
+     * @param vo
+     */
     @PostMapping(value = "/socket/sendMsg")
     void sendMsg(@RequestBody UserInfoVO vo);
+
+    /**
+     * 推送系统公告
+     */
+    @PostMapping(value = "/socket/sendSystemMsg")
+    void sendSystemMsg(@RequestBody SystMsgVO vo);
 }

+ 5 - 1
blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/vo/MsgVO.java

@@ -14,9 +14,13 @@ import java.io.Serializable;
 public class MsgVO<T> implements Serializable {
 
     /**
-     * 每个系统独立拥有消息类型
+     * 每个系统独立拥有客户端消息类型
+     *  全平台通用:msgUpdateMsg(维护发布公告),msgSystemMsg(系统普通公告),msgCountDown(维护倒计时)
      *  计量:msgRemind(消息提醒)
      *  档案:
+     *
+     * 服务器处理的消息类型
+     *  getMsg:代表客户端向服务器获取所有公告
      */
     @ApiModelProperty("消息类型")
     private String type;

+ 26 - 0
blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/vo/SystMsgVO.java

@@ -0,0 +1,26 @@
+package org.springblade.websocket.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @Param
+ * @Author wangwl
+ * @Date 2024/8/30 14:02
+ **/
+@Data
+public class SystMsgVO implements Serializable {
+
+    @ApiModelProperty(value = "公告类型:1维护公告2普通公告")
+    private Integer msgType;
+
+    @ApiModelProperty(value = "推送系统:系统名称逗号拼接")
+    private String pushSystem;
+
+    @ApiModelProperty(value = "发布内容")
+    private String msgContent;
+
+
+}

+ 3 - 0
blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/vo/UserInfoVO.java

@@ -29,6 +29,9 @@ public class UserInfoVO implements Serializable {
     @ApiModelProperty("msg")
     private String msg;
 
+    @ApiModelProperty("公告类型1维护2普通,拼接字符串")
+    private String msgType;
+
     public UserInfoVO() {
     }
 

+ 42 - 0
blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/vo/UserSingleVO.java

@@ -0,0 +1,42 @@
+package org.springblade.websocket.vo;
+
+import lombok.Data;
+
+import java.util.Objects;
+
+/**
+ * @Param   用于推送时只推送一次
+ * @Author wangwl
+ * @Date 2024/9/4 14:09
+ **/
+@Data
+public class UserSingleVO {
+
+    private Long userId;
+
+    private String userIp;
+
+    private String system;
+
+    public UserSingleVO() {
+    }
+
+    public UserSingleVO(Long userId, String userIp, String system) {
+        this.userId = userId;
+        this.userIp = userIp;
+        this.system = system;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        UserSingleVO singleVO = (UserSingleVO) o;
+        return Objects.equals(userId, singleVO.userId) && Objects.equals(userIp, singleVO.userIp) && Objects.equals(system, singleVO.system);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(userId, userIp, system);
+    }
+}

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

@@ -1,6 +1,5 @@
 package org.springblade.business.controller;
 
-import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -21,7 +20,6 @@ import org.springblade.business.service.IFixedFlowLinkService;
 import org.springblade.business.service.IFixedFlowService;
 import org.springblade.business.service.IInformationQueryService;
 import org.springblade.business.utils.PDFUtil;
-import org.springblade.business.vo.AddContractTreeNodeVO;
 import org.springblade.business.vo.FixedFlowVO;
 import org.springblade.core.secure.utils.AuthUtil;
 import org.springblade.core.tool.api.R;
@@ -33,10 +31,8 @@ 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.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 
-import javax.management.MalformedObjectNameException;
 import java.util.*;
 import java.util.stream.Collectors;
 

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

@@ -27,7 +27,6 @@ import org.springblade.business.mapper.InformationQueryMapper;
 import org.springblade.business.service.*;
 import org.springblade.business.utils.FileUtils;
 import org.springblade.business.vo.*;
-import org.springblade.common.constant.ClientIdConstant;
 import org.springblade.common.constant.CommonConstant;
 import org.springblade.common.utils.BaseUtils;
 import org.springblade.common.utils.CommonUtil;
@@ -51,7 +50,6 @@ import org.springblade.manager.feign.*;
 import org.springblade.manager.vo.WbsTreeContractTreeVOS;
 import org.springblade.manager.vo.WbsTreeContractVO8;
 import org.springblade.manager.vo.WbsTreePrivateAddVO;
-//import org.springblade.producer.bean.PushMessage;
 import org.springblade.resource.feign.NewIOSSClient;
 import org.springblade.system.cache.ParamCache;
 import org.springblade.system.entity.DictBiz;
@@ -63,16 +61,13 @@ import org.springframework.dao.EmptyResultDataAccessException;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.jdbc.core.RowMapper;
-import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
-import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
-import java.sql.SQLException;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -1367,7 +1362,11 @@ public class InformationWriteQueryController extends BladeController {
 
                             // 为多单上报 状态修改
                             if(appType!=null && appType == 2L){
-                                String sql = "update u_entrust_info set status = 2 ,sample_status=1 where id = " + startTaskVO.getIds();
+                                //获取当前时间
+                                LocalDateTime now = LocalDateTime.now();
+                                //格式化时间
+                                String nowFormat = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+                                String sql = "update u_entrust_info set status = 2 , entrust_time = '"+ nowFormat + "' ,sample_status=1 where id = " + startTaskVO.getIds();
                                 jdbcTemplate.execute(sql);
                             }
                             var = true;

+ 1 - 2
blade-service/blade-business/src/main/java/org/springblade/business/controller/TrialMaterialController.java

@@ -29,7 +29,6 @@ import org.springframework.web.multipart.MultipartFile;
 
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
-import java.text.ParseException;
 import java.util.List;
 
 @RestController
@@ -94,7 +93,7 @@ public class TrialMaterialController extends BladeController {
     @ApiOperationSupport(order = 6)
     @ApiOperation(value = "进场材料批量删除", notes = "传入ids")
     public R<Object> mobilizationRemove(@Valid @RequestParam String ids) {
-        return R.status(iTrialMaterialMobilizationService.deleteLogic(Func.toLongList(ids)));
+        return  iTrialMaterialMobilizationService.mobilizationRemove(ids);
     }
 
     @PostMapping("/mobilization/copy")

+ 7 - 8
blade-service/blade-business/src/main/java/org/springblade/business/feignClient/BusinessWebSocketClientImpl.java

@@ -1,25 +1,24 @@
 package org.springblade.business.feignClient;
 
 import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
 import org.springblade.business.feign.BusinessWebSocketClient;
 import org.springblade.business.service.ITaskService;
 import org.springblade.core.tenant.annotation.NonDS;
+import org.springblade.websocket.vo.UserInfoVO;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 import java.util.Map;
 
 @RestController
-@AllArgsConstructor
-@NonDS
+@RequiredArgsConstructor
 public class BusinessWebSocketClientImpl implements BusinessWebSocketClient {
 
-    private final ITaskService iTaskService;
-
     @Override
-    @GetMapping(value = "/business/getWebsocketMsg")
-    public Map<String, String> getWebsocketMsg(String projectId, String contractId, String userIdResult) {
-        return iTaskService.getTaskCount(projectId, contractId, userIdResult);
-    }
+    @Async
+    public void pushMsg(UserInfoVO vo) {
 
+    }
 }

+ 30 - 2
blade-service/blade-business/src/main/java/org/springblade/business/mapper/EntrustInfoMapper.xml

@@ -87,8 +87,19 @@
                CONCAT_WS('-', resam_start_time, resam_end_time) as resamTime,IF(resam_start_time is NULL,'否','是') as isSample,
                a.repeal_reason as repealReason,a.repeal_time as repealTime,
         (SELECT max(task_status) from u_trial_self_inspection_record c where c.entrust_id = a.id) as entrustStatusName,
-        (SELECT IF((max(task_status)) ='已审批',4,1) from u_trial_self_inspection_record c where c.entrust_id = a.id) as entrustStatus,
-        (SELECT max(c.id) from u_trial_self_inspection_record c where c.entrust_id = a.id) as testId
+        (
+        SELECT
+        CASE
+        WHEN max(c.task_status) = '未上报' THEN 1
+        WHEN max(c.task_status) = '待审批' THEN 3
+        WHEN max(c.task_status) = '已审批' THEN 4
+        ELSE 5
+        END
+        FROM u_trial_self_inspection_record c
+        WHERE c.entrust_id = a.id
+        ) as entrustStatus,
+        (SELECT max(c.id) from u_trial_self_inspection_record c where c.entrust_id = a.id) as testId ,a.entrust_time as entrustTime,
+        a.sample_time as sampleTime
         from u_entrust_info a , u_trial_sample_info b
         where  a.sample_id=b.id and a.is_deleted = 0 and b.is_deleted=0
           and a.sample_status=#{param2.status}
@@ -101,6 +112,23 @@
         <if test="param2.contractId != null and param2.contractId != ''">
             AND a.contract_id = #{param2.contractId}
         </if>
+        <if test="param2.startTime != null and param2.endTime != ''" >
+            <if test="param2.status == 1">
+                AND #{param2.startTime} <![CDATA[<]]> a.entrust_time And  a.entrust_time <![CDATA[<]]> #{param2.endTime}
+            </if>
+            <if test="param2.status == 2">
+                AND #{param2.startTime} <![CDATA[<]]> a.sample_time And  a.sample_time <![CDATA[<]]> #{param2.endTime}
+            </if>
+            <if test="param2.status == 4">
+                AND #{param2.startTime} <![CDATA[<]]> b.create_time And  b.create_time <![CDATA[<]]> #{param2.endTime}
+            </if>
+            <if test="param2.status == 5">
+                AND #{param2.startTime} <![CDATA[<]]> a.resam_start_time And  a.resam_start_time <![CDATA[<]]> #{param2.endTime}
+            </if>
+            <if test="param2.status == 6">
+                AND #{param2.startTime} <![CDATA[<]]> a.repeal_time And  a.repeal_time <![CDATA[<]]> #{param2.endTime}
+            </if>
+        </if>
 
     </select>
 

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

@@ -66,5 +66,6 @@
                     or a.specification_number like CONCAT(CONCAT('%', #{param2.queryValue}), '%')
             )
         </if>
+        order by a.sampling_date desc
     </select>
 </mapper>

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

@@ -7,10 +7,9 @@ import org.springblade.business.excel.TrialMaterialMobilizationExcel;
 import org.springblade.business.vo.TrialMaterialMobilizationVO;
 import org.springblade.business.vo.TrialSamplingRecordVO;
 import org.springblade.core.mp.base.BaseService;
-import org.springframework.web.bind.annotation.RequestParam;
+import org.springblade.core.tool.api.R;
 
 import javax.servlet.http.HttpServletResponse;
-import java.text.ParseException;
 import java.util.List;
 
 
@@ -36,4 +35,5 @@ public interface ITrialMaterialMobilizationService extends BaseService<TrialMate
 
     boolean uploadFile(String id, Integer type, String url);
 
+    R<Object> mobilizationRemove(String ids);
 }

+ 5 - 10
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/EntrustInfoServiceImpl.java

@@ -17,18 +17,14 @@
 package org.springblade.business.service.impl;
 
 import com.alibaba.fastjson.JSONObject;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.AllArgsConstructor;
-import org.jsoup.select.Elements;
-import org.springblade.business.dto.TrialSelfInspectionRecordDTO;
 import org.springblade.business.entity.EntrustInfo;
-import org.springblade.business.entity.TrialSampleInfo;
-import org.springblade.business.service.ITrialSampleInfoService;
-import org.springblade.business.vo.EntrustDataInfoVO;
-import org.springblade.business.vo.EntrustInfoVO;
 import org.springblade.business.mapper.EntrustInfoMapper;
 import org.springblade.business.service.IEntrustInfoService;
+import org.springblade.business.vo.EntrustDataInfoVO;
+import org.springblade.business.vo.EntrustInfoVO;
 import org.springblade.business.vo.LoadDataInfoVO;
 import org.springblade.business.vo.TrialSampleDataInfoVO;
 import org.springblade.core.mp.base.BaseServiceImpl;
@@ -39,8 +35,6 @@ import org.springblade.manager.feign.ExcelTabClient;
 import org.springblade.manager.feign.WbsTreePrivateClient;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.stereotype.Service;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
 import java.util.Map;
@@ -107,6 +101,8 @@ public class EntrustInfoServiceImpl extends BaseServiceImpl<EntrustInfoMapper, E
 		EntrustInfo entrustInfo = baseMapper.selectOne(Wrappers.<EntrustInfo>query().lambda().eq(EntrustInfo::getSampleId, sampleId).eq(EntrustInfo::getContractId,contractId));
 		if(entrustInfo==null && Func.isEmpty(entrustInfo)){
 			entrustInfo = new EntrustInfo();
+			//委托单未上报不进入样品流转 状态设置为0
+			entrustInfo.setSampleStatus("0");
 		}
 		WbsTreePrivate wbsTreePrivate = wbsTreePrivateClient.getNodeByPrimaryKeyId(nodeErTreeId);
 
@@ -139,7 +135,6 @@ public class EntrustInfoServiceImpl extends BaseServiceImpl<EntrustInfoMapper, E
 		dataInfo.put("groupId",entrustInfo.getId());
 		dataInfo.put("pkeyId", dataInfo.getString("nodeErTreeId"));
 		excelTabClient.saveEntrustTabData(dataInfo);
-
 		return R.success("操作成功");
 	}
 

+ 5 - 17
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TaskServiceImpl.java

@@ -1,6 +1,5 @@
 package org.springblade.business.service.impl;
 
-import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -19,9 +18,7 @@ import org.springblade.business.service.*;
 import org.springblade.business.vo.*;
 import org.springblade.common.constant.CommonConstant;
 import org.springblade.common.utils.CommonUtil;
-import org.springblade.common.utils.FileUtils;
 import org.springblade.common.utils.SnowFlakeUtil;
-import org.springblade.core.cloud.feign.EnableBladeFeign;
 import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.mp.base.BaseServiceImpl;
 import org.springblade.core.mp.support.Query;
@@ -35,7 +32,6 @@ import org.springblade.core.tool.utils.Func;
 import org.springblade.core.tool.utils.ObjectUtil;
 import org.springblade.core.tool.utils.ResourceUtil;
 import org.springblade.evisa.feign.EVisaClient;
-import org.springblade.evisa.redissionUtil.DistributedRedisLock;
 import org.springblade.evisa.vo.EVisaTaskApprovalVO;
 import org.springblade.flow.core.constant.ProcessConstant;
 import org.springblade.flow.core.entity.BladeFlow;
@@ -44,36 +40,27 @@ import org.springblade.flow.core.feign.NewFlowClient;
 import org.springblade.flow.core.utils.FlowUtil;
 import org.springblade.flow.core.utils.TaskUtil;
 import org.springblade.flow.core.vo.FlowProcessVO;
-import org.springblade.manager.entity.*;
+import org.springblade.manager.entity.ContractInfo;
+import org.springblade.manager.entity.ProjectInfo;
+import org.springblade.manager.entity.TabBusstimeInfo;
+import org.springblade.manager.entity.WbsTreeContract;
 import org.springblade.manager.feign.*;
 import org.springblade.manager.vo.AppWbsTreeContractVO;
-import org.springblade.manager.vo.TableFileVO;
 import org.springblade.resource.feign.CommonFileClient;
 import org.springblade.resource.feign.NewIOSSClient;
 import org.springblade.system.cache.ParamCache;
-import org.springblade.system.user.cache.UserCache;
-import org.springblade.system.user.entity.User;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cloud.openfeign.EnableFeignClients;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.scheduling.annotation.Async;
-import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.RequestHeader;
 
-import javax.annotation.Resource;
-import javax.servlet.http.HttpServletRequest;
 import java.io.File;
 import java.io.FileNotFoundException;
-import java.nio.file.Watchable;
 import java.util.*;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 /**
@@ -1223,6 +1210,7 @@ public class TaskServiceImpl extends BaseServiceImpl<TaskMapper, Task> implement
                 //修改试验业务状态(已审批的情况下修改)
                 if (new Integer(2).equals(queryinfo.getType()) && ObjectUtil.isNotEmpty(queryinfo.getWbsId()) && status != 3) {
                     jdbcTemplate.execute("update u_trial_self_inspection_record set task_status = '已审批' where id = " + queryinfo.getWbsId());
+                    jdbcTemplate.execute("update u_entrust_info set status = 4 where id = (select entrust_id from u_trial_self_inspection_record where id = '" + queryinfo.getWbsId()+ "')");
                 }
 
             }

+ 30 - 6
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialMaterialMobilizationServiceImpl.java

@@ -27,7 +27,6 @@ import org.springblade.business.vo.TrialMaterialMobilizationVO;
 import org.springblade.business.vo.TrialSamplingRecordVO;
 import org.springblade.business.wrapper.TrialMaterialMobilizationWarpper;
 import org.springblade.common.utils.CommonUtil;
-import org.springblade.common.utils.FileUtils;
 import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.common.utils.SystemUtils;
 import org.springblade.core.log.exception.ServiceException;
@@ -36,12 +35,14 @@ import org.springblade.core.mp.support.Condition;
 import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.secure.utils.SecureUtil;
 import org.springblade.core.tool.api.R;
-import org.springblade.core.tool.utils.*;
+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.resource.entity.Attach;
 import org.springblade.resource.feign.NewIOSSClient;
 import org.springblade.system.entity.Dict;
 import org.springblade.system.feign.IDictClient;
-import org.springblade.system.feign.ISysClient;
 import org.springblade.system.user.entity.User;
 import org.springblade.system.user.feign.IUserClient;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
@@ -49,9 +50,10 @@ import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.stereotype.Service;
 
 import javax.servlet.http.HttpServletResponse;
-import java.io.*;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.util.*;
-import java.util.function.Function;
 import java.util.stream.Collectors;
 
 @Service
@@ -429,5 +431,27 @@ public class TrialMaterialMobilizationServiceImpl extends BaseServiceImpl<TrialM
         return false;
     }
 
-
+    /**
+     * 进场材料批量删除
+     * @param ids
+     * @return
+     */
+    @Override
+    public R<Object> mobilizationRemove(String ids) {
+        //限制 有取样记录的不允许删除
+        List<Long> idList = Func.toLongList(ids);
+        ArrayList<Long> newIdList = new ArrayList<>(idList);
+        for (Long id : idList) {
+            List<TrialSamplingRecord> trialSelfInspectionRecords = trialSamplingRecordMapper.selectListByMobilizationId(id);
+            if(trialSelfInspectionRecords != null && trialSelfInspectionRecords.size() > 0){
+                //存在取样记录 不允许删除 从idList中移除
+                newIdList.remove(newIdList.indexOf(id));
+            }
+        }
+        if(newIdList == null || newIdList.size() == 0){
+            return R.fail("所选数据均存在取样记录,不允许删除");
+        }
+        boolean b = super.deleteLogic(newIdList);
+        return  b?R.success("删除成功"):R.fail("删除失败");
+    }
 }

+ 86 - 8
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialSelfInspectionRecordServiceImpl.java

@@ -2,19 +2,25 @@ package org.springblade.business.service.impl;
 
 import cn.hutool.core.date.LocalDateTimeUtil;
 import com.alibaba.fastjson.JSONArray;
-import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
-import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.spire.xls.*;
+import com.spire.xls.CellRange;
+import com.spire.xls.ExcelVersion;
+import com.spire.xls.Workbook;
+import com.spire.xls.Worksheet;
 import lombok.AllArgsConstructor;
 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.*;
 import org.springblade.business.entity.*;
+import org.springblade.business.mapper.EntrustInfoMapper;
 import org.springblade.business.mapper.TrialMaterialMobilizationMapper;
 import org.springblade.business.mapper.TrialSampleInfoMapper;
 import org.springblade.business.mapper.TrialSelfInspectionRecordMapper;
@@ -35,7 +41,10 @@ import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.utils.*;
 import org.springblade.manager.entity.*;
-import org.springblade.manager.feign.*;
+import org.springblade.manager.feign.ContractClient;
+import org.springblade.manager.feign.ExcelTabClient;
+import org.springblade.manager.feign.TableFileClient;
+import org.springblade.manager.feign.WbsTreePrivateClient;
 import org.springblade.resource.entity.Attach;
 import org.springblade.resource.feign.CommonFileClient;
 import org.springblade.resource.feign.IOSSClient;
@@ -55,8 +64,8 @@ import org.springframework.web.multipart.MultipartFile;
 
 import java.io.File;
 import java.io.FileNotFoundException;
+import java.io.InputStream;
 import java.util.*;
-import java.util.List;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -66,6 +75,7 @@ public class TrialSelfInspectionRecordServiceImpl extends BaseServiceImpl<TrialS
 
     private final TrialSampleInfoMapper trialSampleInfoMapper;
     private final TrialMaterialMobilizationMapper trialMaterialMobilizationMapper;
+    private final EntrustInfoMapper entrustInfoMapper;
     private final IUserClient iUserClient;
     private final ContractClient contractClient;
     private final WbsTreePrivateClient wbsTreePrivateClient;
@@ -159,7 +169,12 @@ public class TrialSelfInspectionRecordServiceImpl extends BaseServiceImpl<TrialS
                     List<Long> ids = query1.stream().map(TrialRawMaterialSelfRecord::getRawMaterialRecordId).collect(Collectors.toList());
                     record.setRawMaterialIds(org.apache.commons.lang.StringUtils.join(ids, ","));
                 }
-
+                //委托单名称 委托单编号
+                EntrustInfo entrustInfo = entrustInfoMapper.selectById(record.getEntrustId());
+                if (entrustInfo != null){
+                    record.setEntrustName(entrustInfo.getEntrustName());
+                    record.setEntrustNo(entrustInfo.getEntrustNo());
+                }
                 //合并的pdfUrl
                 String pdf = this.getMergePdfToTrial(record.getContractId(), record.getId());
                 record.setPdfUrl(pdf);
@@ -972,7 +987,8 @@ public class TrialSelfInspectionRecordServiceImpl extends BaseServiceImpl<TrialS
         if (ObjectUtil.isNotEmpty(dto.getId())) {
             //------获取最新试验记录------
             TrialSelfInspectionRecord obj = baseMapper.selectById(dto.getId());
-
+            //如果传递了就修改对应记录的值
+            this.updateRecordNoOrReportNo(obj, dto);
             //------编辑时记录表编号或报告单编号为Null的重新生成------
             this.reBuildNumber(obj, dto);
 
@@ -998,6 +1014,66 @@ public class TrialSelfInspectionRecordServiceImpl extends BaseServiceImpl<TrialS
         return dto.getId().toString();
     }
 
+    /**
+     * 取到传入的表单中的报告编号或者记录编号 修改记录表中相应字段的值
+     * @param obj
+     * @param dto
+     */
+    private void updateRecordNoOrReportNo(TrialSelfInspectionRecord obj, TrialSelfInspectionRecordDTO dto) {
+        JSONArray dataArray = dto.getDataInfo().getJSONArray("orderList");
+        for (int i = 0; i < dataArray.size(); i++) {
+            JSONObject jsonObject = dataArray.getJSONObject(i);
+            String pkeyId = jsonObject.getString("pkeyId");
+            String sql = "select * from m_wbs_tree_private where p_key_id =" + pkeyId;
+            WbsTreePrivate table = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(WbsTreePrivate.class));
+            String fileUrl = table.getHtmlUrl();
+            try {
+                InputStream fileInputStream = FileUtils.getInputStreamByUrl(fileUrl);
+                String htmlString = IoUtil.readToString(fileInputStream);
+                htmlString = htmlString.replaceAll("placeholder", "placeholderxx");
+                Document doc = Jsoup.parse(htmlString);
+                // 查找所有具有 placeholderxx 属性的元素
+                //表类型 1=记录表 2=报告单 ,字符串拼接
+                String tableType = dto.getTableType();
+                String[] singleTableType = tableType.split(",");
+                if("1".equals(singleTableType[i])){
+                    //记录表
+                    this.updateRecordNoOrReportNo(dto,jsonObject,doc,"记录编 号:","record_no");
+                }else if("2".equals(singleTableType[i])){
+                    //报告单
+                    this.updateRecordNoOrReportNo(dto,jsonObject,doc,"报告编号:","report_no");
+                }
+            } catch (Exception e) {
+
+            }
+
+        }
+    }
+
+    /**
+     * 修改记录编号或者报告编号的值
+     * @param dto
+     * @param jsonObject
+     * @param doc
+     * @param value
+     * @param fileVlue
+     */
+    private void updateRecordNoOrReportNo(TrialSelfInspectionRecord dto,JSONObject jsonObject,Document doc,String  value, String fileVlue) {
+        Elements elementsWithPlaceholderxx = doc.select("[placeholderxx="+value+"]");
+        if((elementsWithPlaceholderxx.size() == 0 ||elementsWithPlaceholderxx == null) && value.equals("报告编号:")){
+            value = "编号:";
+            elementsWithPlaceholderxx = doc.select("[placeholderxx="+value+"]");
+        }
+        Element first = elementsWithPlaceholderxx.first();
+        String key = first.attr("id");
+        //记录编号或者报告编号的值
+        String recordOrReportNo = jsonObject.getString(key);
+        if(!"".equals(recordOrReportNo) && !(recordOrReportNo == null)){
+            String updateSql = "update u_trial_self_inspection_record set " + fileVlue +"='" + recordOrReportNo + "' where id='" + dto.getId()+"'";
+            jdbcTemplate.execute(updateSql);
+        }
+    }
+
     public void initBuildNumber(TrialSelfInspectionRecordDTO dto) {
         if (ObjectUtil.isEmpty(dto.getId()) && StringUtils.isNotEmpty(dto.getTableType())) {
             //构建记录表编号、报告单编号
@@ -1008,11 +1084,13 @@ public class TrialSelfInspectionRecordServiceImpl extends BaseServiceImpl<TrialS
 
     public void initTrialTabIds(TrialSelfInspectionRecordDTO dto) {
         JSONArray dataArray = dto.getDataInfo().getJSONArray("orderList");
+
         List<String> tableIds = new ArrayList<>();
         for (int i = 0; i < dataArray.size(); i++) {
             String pkeyId = dataArray.getJSONObject(i).getString("pkeyId");
             tableIds.add(pkeyId);
         }
+        // 获取
         List<String> ids = tableIds.stream().distinct().collect(Collectors.toList());
         String join = org.apache.commons.lang.StringUtils.join(ids, ",");
         dto.setTableIds(join);

+ 15 - 5
blade-service/blade-business/src/main/java/org/springblade/business/utils/FileUtils.java

@@ -2,16 +2,15 @@ package org.springblade.business.utils;
 
 import com.drew.imaging.ImageMetadataReader;
 import com.drew.imaging.ImageProcessingException;
-import com.drew.metadata.Directory;
 import com.drew.metadata.Metadata;
 import com.drew.metadata.MetadataException;
 import com.drew.metadata.exif.ExifIFD0Directory;
-import com.drew.metadata.exif.ExifSubIFDDirectory;
 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.*;
+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.constant.CommonConstant;
@@ -25,10 +24,8 @@ import javax.imageio.IIOImage;
 import javax.imageio.ImageIO;
 import javax.imageio.ImageWriteParam;
 import javax.imageio.ImageWriter;
-import javax.imageio.stream.ImageOutputStream;
 import javax.servlet.http.HttpServletResponse;
 import java.awt.*;
-import java.awt.Color;
 import java.awt.geom.AffineTransform;
 import java.awt.image.AffineTransformOp;
 import java.awt.image.BufferedImage;
@@ -346,6 +343,19 @@ public class FileUtils {
         }
         return file_path;
     }
+    // 获取本地 或 远程工作流ParamCache
+    public static InputStream getInputStreamByUrl(String fileUrl) throws Exception {
+
+        File file1 = new File(fileUrl);
+        InputStream fileInputStream = null;
+        if (file1.exists()) {
+            fileInputStream = new FileInputStream(file1);
+        } else {
+            String path = getNetUrl(fileUrl);
+            fileInputStream = CommonUtil.getOSSInputStream(path);
+        }
+        return fileInputStream;
+    }
 
     public static String getNetUrl(String fileUrl){
         String file_path = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);

+ 19 - 15
blade-service/blade-e-visa/src/main/java/org/springblade/evisa/controller/EVisaController.java

@@ -2,29 +2,29 @@ package org.springblade.evisa.controller;
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
-import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import io.swagger.annotations.*;
+import io.swagger.annotations.Api;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang.StringUtils;
 import org.springblade.business.entity.Task;
-import org.springblade.business.entity.TaskBatch;
-import org.springblade.business.entity.TaskParallel;
 import org.springblade.business.feign.TaskClient;
 import org.springblade.business.vo.TaskApprovalVO;
 import org.springblade.evisa.service.EVisaService;
 import org.springblade.evisa.vo.EVisaTaskApprovalVO;
-import org.springblade.resource.feign.NewIOSSClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 import java.io.FileNotFoundException;
-import java.util.*;
-import java.util.concurrent.*;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
 
 
 /**
@@ -122,13 +122,16 @@ public class EVisaController {
                 //获取状态为1(待审批)的分支流程
                 List<Task> tasks = taskClient.queryTaskListByFormDataId(taskApprovalVO.getFormDataId());
                 Task masterTask = tasks.get(0);
-                if(masterTask !=null && (masterTask.getApprovalType()==5 || masterTask.getApprovalType()==6 || masterTask.getApprovalType()==7 ) && masterTask.getFixedFlowId()!=null && masterTask.getFixedFlowId()!=0L ){
-                   String upsql = "update u_task_parallel set status=2 ,e_visa_status=1,e_visa_content='电签成功' ,update_time=SYSDATE()  where sort in(SELECT fixed_flow_branch_sort from u_fixed_flow_link where fixed_flow_id ="+masterTask.getFixedFlowId()+" and  fixed_flow_link like'%审计%') and process_instance_id="+masterTask.getProcessInstanceId()+"";
-                    jdbcTemplate.execute(upsql);
-                 }
-                String  sql = "SELECT a.* from u_task_parallel a where a.process_instance_id=(SELECT process_instance_id from u_task_parallel b where  b.parallel_process_instance_id='"+taskApprovalVO.getParallelProcessInstanceId()+"') and is_deleted=0 and `status`=1 ";
+
+                String  sql = "SELECT a.* from u_task_parallel a where a.process_instance_id=(SELECT process_instance_id from u_task_parallel b where  b.parallel_process_instance_id='"+taskApprovalVO.getParallelProcessInstanceId()+"') and is_deleted=0 and `status`=1 and sort not in(SELECT fixed_flow_branch_sort from u_fixed_flow_link where fixed_flow_id ="+masterTask.getFixedFlowId()+" and  flow_task_type=2 ) ";
                 List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
                 if (maps == null || maps.size() == 0) {
+                    // 最后修改计量数据
+                    /*if(masterTask !=null && (masterTask.getApprovalType()==5 || masterTask.getApprovalType()==6 || masterTask.getApprovalType()==7 ) && masterTask.getFixedFlowId()!=null && masterTask.getFixedFlowId()!=0L ){
+                        String upsql = "update u_task_parallel set status=2 ,e_visa_status=1,e_visa_content='电签成功' ,update_time=SYSDATE()  where sort in(SELECT fixed_flow_branch_sort from u_fixed_flow_link where fixed_flow_id ="+masterTask.getFixedFlowId()+" and  flow_task_type=2 ) and process_instance_id="+masterTask.getProcessInstanceId()+"";
+                        jdbcTemplate.execute(upsql);
+                    }*/
+
                     //说明都审批完成,将主表状态更改为已完成
                     String finalPdfUrl = null;
                     if (eVisaStatus.contains("@@@@")) {
@@ -214,8 +217,9 @@ public class EVisaController {
             this.jdbcTemplate.execute("delete from u_task_batch where id="+taskApprovalVO.getId());
             RedisTemplate.delete("sign-" + taskApprovalVO.getFormDataId());
         } else if (taskApprovalVO.getApprovalType()==8) { // 委托单
-
-            this.jdbcTemplate.execute("update u_entrust_info set sample_status=2,status="+(type+1)+",entrust_e_pdf='"+finalPdfUrl+"' where id=(SELECT wbs_id from u_information_query where id='"+taskApprovalVO.getFormDataId()+"')");
+           if(type == 2){
+               this.jdbcTemplate.execute("update u_entrust_info set sample_status=2,status="+(type+1)+",entrust_e_pdf='"+finalPdfUrl+"' where id=(SELECT wbs_id from u_information_query where id='"+taskApprovalVO.getFormDataId()+"')");
+           }
             jdbcTemplate.execute("update u_information_query set e_visa_pdf_url='"+finalPdfUrl+"',status="+type+" where id='"+taskApprovalVO.getFormDataId()+"'");
 
             this.jdbcTemplate.execute("delete from u_task_batch where id="+taskApprovalVO.getId());

+ 12 - 16
blade-service/blade-e-visa/src/main/java/org/springblade/evisa/service/impl/EVisaServiceImpl.java

@@ -1,15 +1,11 @@
 package org.springblade.evisa.service.impl;
 
-import cfca.com.itextpdf.text.Image;
 import cfca.com.itextpdf.text.Rectangle;
 import cfca.com.itextpdf.text.pdf.PdfReader;
 import cfca.paperless.ClientConstants;
 import cfca.paperless.base.BaseConstants;
 import cfca.paperless.base.util.Base64;
-import cfca.paperless.base.util.GUIDUtil;
-import cfca.paperless.base.util.ImageUtil;
-import cfca.paperless.base.util.IoUtil;
-import cfca.paperless.base.util.PwdEncryptUtil;
+import cfca.paperless.base.util.*;
 import cfca.paperless.client.PaperlessClient;
 import cfca.paperless.dto.RequestHead;
 import cfca.paperless.dto.ResponseDto;
@@ -33,14 +29,10 @@ import cfca.paperless.dto.response.tx40.SealPdfResponse;
 import cfca.paperless.dto.response.tx40.VerifyPdfSealResponse;
 import cn.hutool.core.io.file.FileReader;
 import com.alibaba.fastjson.JSONObject;
-import com.spire.xls.Workbook;
 import lombok.AllArgsConstructor;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.pdfbox.pdmodel.PDDocument;
-import org.apache.pdfbox.pdmodel.PDPage;
-import org.apache.pdfbox.pdmodel.PDPageContentStream;
-import org.apache.pdfbox.pdmodel.font.PDType1Font;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springblade.business.entity.ArchiveFile;
@@ -56,14 +48,15 @@ import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.secure.utils.AuthUtil;
 import org.springblade.core.secure.utils.SecureUtil;
 import org.springblade.core.tool.api.R;
-import org.springblade.core.tool.utils.*;
+import org.springblade.core.tool.utils.DateUtil;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.ObjectUtil;
 import org.springblade.evisa.redissionUtil.DistributedRedisLock;
 import org.springblade.evisa.service.EVisaService;
 import org.springblade.evisa.utils.FileUtils;
 import org.springblade.evisa.utils.PDFUtils;
 import org.springblade.evisa.vo.*;
 import org.springblade.manager.entity.ContractInfo;
-import org.springblade.manager.entity.ProjectInfo;
 import org.springblade.manager.entity.SignPfxFile;
 import org.springblade.manager.feign.ContractClient;
 import org.springblade.manager.feign.SignPfxClient;
@@ -90,9 +83,6 @@ import java.awt.image.BufferedImage;
 import java.io.*;
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -100,8 +90,8 @@ import java.util.stream.Collectors;
 @AllArgsConstructor
 public class EVisaServiceImpl implements EVisaService {
 
-    private static final String SIGN_HOST = "172.30.224.79";
-   // private static final String SIGN_HOST = "47.115.117.246";
+    //private static final String SIGN_HOST = "172.30.224.79";
+    private static final String SIGN_HOST = "47.115.117.246";
 
     private static final String SIGN_PORT = "8183";
 
@@ -550,16 +540,22 @@ public class EVisaServiceImpl implements EVisaService {
                             .collect(Collectors.groupingBy( hada ->(Func.toStr(hada.get("id")))));
 
                     for(String keyId :peopleByAge.keySet()){
+                        int exId = 0 ;
                         List<Map<String, Object>> keyList = peopleByAge.get(keyId);
                         if(keyList!=null && keyList.size()==1){
                             maps.addAll(keyList);
+                            exId =1;
                         }else if(keyList!=null && keyList.size()>=2){
                             for(Map<String, Object> datax : keyList){
                                 if((datax.get("project_id")+"").equals(projectId)){
                                     maps.add(datax);
+                                    exId =1;
                                 }
                             }
                         }
+                        if(exId == 0){
+                            maps.add(keyList.get(0));
+                        }
                     }
 
                     System.out.println("安心签-个人-user-id" + task.getUserId() + "--SQL=" + sqlinfo);

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

@@ -24,6 +24,10 @@ public class TableInfo {
     private String classify;
     private String projectId;
     private String groupId = "0";
+    // 用于实验
+    private String testGroupId = "0";
+
+
     /**
      * 待更新状态
      */

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

@@ -9,6 +9,7 @@ import lombok.AllArgsConstructor;
 import org.springblade.core.boot.ctrl.BladeController;
 import org.springblade.core.secure.BladeUser;
 import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.Func;
 import org.springblade.manager.service.IWbsTreeContractService;
 import org.springblade.manager.vo.APIWbsContractNodeHzrcVo;
 import org.springblade.manager.vo.APIWbsContractNodeVo;
@@ -54,18 +55,19 @@ public class APIController extends BladeController {
     @ApiImplicitParams(value = {
             @ApiImplicitParam(name = "contractId", value = "合同段Id", required = true)
     })
-    public R<List<APIWbsContractNodeVo>> tree(String contractId) {
-        List<APIWbsContractNodeVo> tree = iWbsTreeContractService.apiTreeNode(contractId);
+    public R<List<APIWbsContractNodeVo>> tree(String contractId,String nodeName) {
+        List<APIWbsContractNodeVo> tree = iWbsTreeContractService.apiTreeNode(contractId,nodeName);
         List<APIWbsContractNodeVo> retu = new ArrayList<>();
-        if (tree != null && tree.size() > 0) {
+        if (tree != null && tree.size() > 0 && Func.isEmpty(nodeName)) {
             for(APIWbsContractNodeVo va:tree){
                 if(va.getChildren().size()>=0 && va.getParentId()==0L){
                     retu.add(va);
                 }
             }
             return R.data(retu);
+        }else{
+            return R.data(tree);
         }
-        return R.fail(200, "未查询到信息");
     }
 
     /**

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

@@ -22,6 +22,7 @@ import org.apache.commons.codec.Charsets;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.jetbrains.annotations.TestOnly;
 import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
 import org.jsoup.nodes.Element;
@@ -72,7 +73,6 @@ import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
@@ -167,8 +167,8 @@ public class ExcelTabController extends BladeController {
 
 
     // 线程池
- //   @Resource(name = "taskExecutor1")
-   // private ThreadPoolExecutor executor;
+    @Resource(name = "taskExecutor1")
+    private ThreadPoolExecutor executor;
 
 
     @Autowired
@@ -1611,6 +1611,7 @@ public class ExcelTabController extends BladeController {
     @GetMapping("/cope-buss-tab")
     @ApiOperationSupport(order = 19)
     @ApiOperation(value = "表单复制", notes = "表单复制")
+    @Transactional
     @ApiImplicitParams(value = {
             @ApiImplicitParam(name = "pkeyId", value = "pkeyId", required = true)
     })
@@ -1658,7 +1659,6 @@ public class ExcelTabController extends BladeController {
         jdbcTemplate.execute(querySql);
         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);
@@ -1815,7 +1815,7 @@ public class ExcelTabController extends BladeController {
                 return R.fail("暂无PDF数据");
             } else {
                 // 由于独立附件 需要追加最后
-                List<TableFileVO> data = tableFileService.selectTableFileListByTen(Long.valueOf(nodeId + ""));
+                List<TableFileVO> data = tableFileService.selectTableFileListByTen(Long.valueOf(nodeId + ""), Integer.valueOf(classify));
                 List<String> datainfo = new ArrayList<>();
 
                 datainfo.add(pdfUrl);
@@ -3618,8 +3618,8 @@ public class ExcelTabController extends BladeController {
             @ApiImplicitParam(name = "id", value = "记录id-当做groupId", required = true),
             @ApiImplicitParam(name = "contractId", value = "合同段id", required = true)
     })
-    public R<List<Map<String, Object>>> getBussDataInfoTrial(Long id, Long pkeyId, Long contractId) {
-        List<Map<String, Object>> bussDataInfoTrial = excelTabService.getBussDataInfoTrial(id, pkeyId, contractId);
+    public R<List<Map<String, Object>>> getBussDataInfoTrial(Long id, Long pkeyId, Long contractId, Long entrustId) {
+        List<Map<String, Object>> bussDataInfoTrial = excelTabService.getBussDataInfoTrial(id, pkeyId, contractId, entrustId);
         return R.data(bussDataInfoTrial);
     }
 
@@ -3940,7 +3940,7 @@ public class ExcelTabController extends BladeController {
             @ApiImplicitParam(name = "nodeId", value = "nodeId", required = true),
 
     })
-    public R addBussFile(@RequestParam("file") MultipartFile[] file, String nodeId,Integer type,Long contractId) {
+    public R addBussFile(@RequestParam("file") MultipartFile[] file, String nodeId,Integer type,Long contractId,Integer classify) {
         List<TableFile> fileList = new ArrayList<>();
         if (file != null && file.length >= 1) {
             for (MultipartFile multipartFile : file) {
@@ -3960,6 +3960,7 @@ public class ExcelTabController extends BladeController {
                 tableFile.setDomainUrl(bladeFile1.getLink());
                 tableFile.setIsDeleted(0);
                 tableFile.setExtension(fileExtension);
+                tableFile.setClassify(classify);
                 fileList.add(tableFile);
             }
             tableFileService.saveOrUpdateBatch(fileList);
@@ -4091,15 +4092,70 @@ public class ExcelTabController extends BladeController {
             @ApiImplicitParam(name = "id", value = "记录id-当做groupId", required = true),
             @ApiImplicitParam(name = "contractId", value = "合同段id", required = true)
     })
-    public R<List<Map<String, Object>>> getBussDataInfoTrialentrust(Long id, Long pkeyId, Long contractId) {
+    public R<List<Map<String, Object>>> getBussDataInfoTrialentrust(Long id, Long pkeyId, Long contractId, Long sampleId) {
 
-        List<Map<String, Object>> bussDataInfoTrial = excelTabService.getBussDataInfoTrialentrust(id, pkeyId, contractId);
+        List<Map<String, Object>> bussDataInfoTrial = excelTabService.getBussDataInfoTrialentrust(id, pkeyId, contractId,sampleId);
         return R.data(bussDataInfoTrial);
     }
 
 
   //  @Scheduled(cron = "0/20 * * * * ?")
- /*   public void SignInfo() {
+    public void SignInfo() {
+        //执行代码
+        String sql = "SELECT * from m_wbs_tree_contract where id in(SELECT parent_id from m_wbs_tree_contract where contract_id=1750757576810766337 and is_cope_tab=2  ) and type =1 and contract_id=1750757576810766337 and is_deleted<>4 " ;
+        List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
+        if (maps != null && maps.size() >= 1) {
+            for (Map<String, Object> dataInfo : maps) {
+                if (executor.getQueue().size() <= 40) {
+                    String idkey = dataInfo.get("p_key_id") + "";
+                    Boolean aBoolean = RedisTemplate.hasKey("sign-" + idkey);
+                    if (!aBoolean) {
+                        RedisTemplate.opsForValue().set("sign-" + idkey, "1", 30, TimeUnit.SECONDS);
+                        CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> {
+                            try {
+                                this.checkIsExsitTaskBatch(dataInfo);
+                            } catch (Exception e) {
+                                e.printStackTrace();
+                            }
+                        }, executor);
+                    }
+
+                }
+            }
+        }
+        System.out.println("队列数量" + executor.getQueue().size());
+        System.out.println("活跃数量" + executor.getActiveCount());
+        System.out.println("总共数量" + executor.getTaskCount());
+        System.out.println("完成数量" + executor.getCompletedTaskCount());
+    }
+        public void checkIsExsitTaskBatch (Map < String, Object > dataInfo){
+            String sql = "SELECT * from m_wbs_tree_contract where parent_id =(select id from m_wbs_tree_contract where p_key_id='"+dataInfo.get("p_key_id")+"' and is_deleted=0 ) and type =2  and is_cope_tab=2 and contract_id=1750757576810766337 ORDER BY sort,create_time,node_name ASC" ;
+            List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
+            String node_name = "";
+            System.out.println(sql);
+            int index = 0;
+            if(maps!=null && maps.size()>=1){
+                for(int i =0;i<maps.size();i++){
+                    Map<String, Object> dataIn = maps.get(i);
+                    String nodeName =dataIn.get("node_name")+"";
+                    if(node_name.equals(nodeName)){
+                        index = index+1;
+                    }else{
+                        index =1;
+                    }
+                    node_name = nodeName;
+                    if(nodeName.indexOf("__")>=0){
+                        nodeName = nodeName.split("__")[0];
+                    }
+                  String  newNmae = nodeName+"__"+index;
+                    System.out.println(newNmae);
+                   // jdbcTemplate.update("update m_wbs_tree_contract set node_name='"+node_name+"' set is_deleted=4 where p_key_id='"+dataIn.get("p_key_id")+"' ");
+
+                 }
+            }
+        }
+   /* @Scheduled(cron = "0/20 * * * * ?")
+    public void SignInfo() {
         //执行代码
         String sql = "SELECT a.* from u_information_query a,m_wbs_tree_contract b  where a.wbs_id=b.p_key_id and  a.project_id='1681859557657550850' and  a.create_dept=100 LIMIT 5";
         List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
@@ -4127,9 +4183,12 @@ public class ExcelTabController extends BladeController {
         System.out.println("活跃数量" + executor.getActiveCount());
         System.out.println("总共数量" + executor.getTaskCount());
         System.out.println("完成数量" + executor.getCompletedTaskCount());
-    }
+    }*/
 
-    public void checkIsExsitTaskBatch(Map<String, Object> dataInfo) {
+
+
+
+ /*   public void checkIsExsitTaskBatch(Map<String, Object> dataInfo) {
         // 数据
         String file_path = "/Users/hongchuangyanfa/Desktop/";
         String nodeId = dataInfo.get("wbs_id")+"";
@@ -4182,11 +4241,11 @@ public class ExcelTabController extends BladeController {
             String dateInfo = "";
             for (String iId : list) {
                 //获取
-               *//* if(StringUtils.isNotBlank(dataInfo.get("file_user_id_and_name")+"")){
+                if(StringUtils.isNotBlank(dataInfo.get("file_user_id_and_name")+"")){
                     String userIdAndName = dataInfo.get("file_user_id_and_name")+"";
                     String[] split = userIdAndName.split("-");
                     userId = Long.parseLong(split[0]);
-                }*//*
+                }
 
                 List<AppWbsTreeContractVO> WbsTreeContract = wbsTreeContractService.searchNodeAllTable(nodeId+":"+userId, classify, contractId, projectId ,null);
 

+ 185 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/SystemMsgController.java

@@ -0,0 +1,185 @@
+package org.springblade.manager.controller;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.*;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.log.exception.ServiceException;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.secure.utils.AuthUtil;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.manager.entity.AppVersion;
+import org.springblade.manager.entity.SystemMsg;
+import org.springblade.manager.service.IAppVersionService;
+import org.springblade.manager.service.ISystemMsgService;
+import org.springblade.manager.vo.SystemAwaitMsgVO;
+import org.springblade.manager.vo.SystemMsgVO;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.time.LocalDateTime;
+import java.time.temporal.ChronoField;
+import java.util.List;
+import java.util.stream.Collectors;
+
+
+@RestController
+@AllArgsConstructor
+@RequestMapping("/systemMsg")
+@Api(value = "后管系统公告", tags = "后管系统公告")
+public class SystemMsgController extends BladeController {
+
+    private final ISystemMsgService systemMsgService;
+
+    /**
+     * 新增
+     */
+    @PostMapping("/add")
+    @ApiOperationSupport(order = 1)
+    @ApiOperation(value = "新增", notes = "传入版本信息")
+    public R add(@Valid @RequestBody SystemMsg systemMsg){
+        systemMsg.setPushDateTime(systemMsg.getPushDateTime().with(ChronoField.SECOND_OF_MINUTE, 0));
+        //如果新增的是更新公告,则校验是否已经存在更新公告
+        if (systemMsg.getMsgType() == 1) {
+            List<SystemMsg> list = systemMsgService.list(new LambdaQueryWrapper<SystemMsg>()
+                    .eq(SystemMsg::getMsgType, 1)
+                    .eq(SystemMsg::getPushStatus,1)
+                    .gt(SystemMsg::getPushDateTime, LocalDateTime.now()));
+            if (list.size() > 0){
+                throw new ServiceException("当前已存在待发布的更新公告,请检查后再重新发布");
+            }
+            if (systemMsg.getMsgWarnTime() == null){
+                throw new ServiceException("请填写提醒时间");
+            }
+            if (systemMsg.getMsgCountDownTime() == null){
+                throw new ServiceException("请填写倒计时时间");
+            }
+            //更新公告,计算提醒开始时间,倒计时开始时间
+            systemMsg.setPushWarnDateTime(systemMsg.getPushDateTime().minusMinutes(systemMsg.getMsgWarnTime()));
+            systemMsg.setPushCountDownDateTime(systemMsg.getPushDateTime().minusMinutes(systemMsg.getMsgCountDownTime()));
+        }else {
+            //普通公告,则计算推送结束时间
+            if (systemMsg.getMsgShowTime() == null){
+                throw new ServiceException("请填写停留时间");
+            }
+            systemMsg.setPushEndDateTime(systemMsg.getPushDateTime().plusMinutes(systemMsg.getMsgShowTime()));
+        }
+        //校验公告时间不能小于当前
+        if (systemMsg.getPushDateTime().isBefore(LocalDateTime.now())){
+            throw new ServiceException("发布时间不能小于当前,请检查后再重新发布");
+        }
+        systemMsg.setCreatUserName(AuthUtil.getUserName());
+        systemMsgService.save(systemMsg);
+        return R.data("新增成功");
+    }
+
+    /**
+     * 分页
+     */
+    @GetMapping("/page")
+    @ApiOperationSupport(order = 2)
+    @ApiOperation(value = "分页", notes = "传入分页信息")
+    @ApiImplicitParams(value = {
+            @ApiImplicitParam(name = "current", value = "当前页", required = true),
+            @ApiImplicitParam(name = "size", value = "每页的数量", required = true),
+            @ApiImplicitParam(name = "msgType", value = "公告类型:1维护公告2普通公告", required = false),
+            @ApiImplicitParam(name = "pushStatus", value = "发布状态:1待发布,2已发布,3已取消", required = false)
+    })
+    public R<IPage<SystemMsgVO>> page(Query query, Integer msgType, Integer pushStatus){
+        IPage<SystemMsgVO> page = systemMsgService.page2(query,msgType,pushStatus);
+        return R.data(page);
+    }
+
+    /**
+     * 修改
+     */
+    @PostMapping("/update")
+    @ApiOperationSupport(order = 3)
+    @ApiOperation(value = "修改", notes = "传入版本信息")
+    public R update(@Valid @RequestBody SystemMsg systemMsg){
+        systemMsg.setPushDateTime(systemMsg.getPushDateTime().with(ChronoField.SECOND_OF_MINUTE, 0));
+        if (systemMsg.getMsgType() == 1) {
+            //如果修改的是更新公告,则校验是否已经存在更新公告
+            List<SystemMsg> list = systemMsgService.list(new LambdaQueryWrapper<SystemMsg>()
+                    .eq(SystemMsg::getMsgType, 1)
+                    .ne(SystemMsg::getId, systemMsg.getId())
+                    .gt(SystemMsg::getPushDateTime, LocalDateTime.now()));
+            if (list.size() > 0){
+                throw new ServiceException("当前已存在待发布的更新公告,请检查后再重新编辑发布");
+            }
+            if (systemMsg.getMsgWarnTime() == null){
+                throw new ServiceException("请填写提醒时间");
+            }
+            if (systemMsg.getMsgCountDownTime() == null){
+                throw new ServiceException("请填写倒计时时间");
+            }
+            //更新公告,计算提醒开始时间,倒计时开始时间
+            systemMsg.setPushWarnDateTime(systemMsg.getPushDateTime().minusMinutes(systemMsg.getMsgWarnTime()));
+            systemMsg.setPushCountDownDateTime(systemMsg.getPushDateTime().minusMinutes(systemMsg.getMsgCountDownTime()));
+        }else {
+            //普通公告,计算推送结束时间
+            if (systemMsg.getMsgShowTime() == null){
+                throw new ServiceException("请填写停留时间");
+            }
+            systemMsg.setPushEndDateTime(systemMsg.getPushDateTime().plusMinutes(systemMsg.getMsgShowTime()));
+        }
+        //校验公告时间不能小于当前
+        if (systemMsg.getPushDateTime().isBefore(LocalDateTime.now())){
+            throw new ServiceException("发布时间不能小于当前,请检查后再重新发布");
+        }
+        systemMsg.setCreatUserName(AuthUtil.getUserName());
+        systemMsg.setPushStatus(1);
+        systemMsg.setCancelDateTime(null);
+        systemMsgService.updateById(systemMsg);
+        return R.data("修改成功");
+    }
+
+    /**
+     * 取消发布
+     */
+    @GetMapping("/cancelPush")
+    @ApiOperationSupport(order = 4)
+    @ApiOperation(value = "取消发布", notes = "传入id")
+    public R cancelPush(@RequestParam Long id){
+        SystemMsg msg = systemMsgService.getById(id);
+        msg.setMsgContent(null);
+        systemMsgService.update(new LambdaUpdateWrapper<SystemMsg>()
+                .eq(SystemMsg::getId,id)
+                .set(SystemMsg::getPushStatus,3)
+                .set(SystemMsg::getCancelDateTime,LocalDateTime.now()));
+        systemMsgService.pushSystemMsgToAllUser(msg);
+        return R.data("修改成功");
+    }
+
+    /**
+     * 获取待发布公告
+     */
+    @GetMapping("/getAwaitMsg")
+    @ApiOperationSupport(order = 5)
+    @ApiOperation(value = "获取待发布公告", notes = "没有参数,返回两个数组:发布公告和系统公告")
+    public R<SystemAwaitMsgVO> getAwaitMsg(){
+        SystemAwaitMsgVO vo = systemMsgService.getAwaitMsg();
+        return R.data(vo);
+    }
+
+    /**
+     * 批量删除
+     */
+    @GetMapping("/remove")
+    @ApiOperationSupport(order = 7)
+    @ApiOperation(value = "批量删除", notes = "传入id逗号拼接")
+    public R remove(@RequestParam String ids) {
+        return R.status(systemMsgService.deleteLogic(Func.toLongList(ids)));
+    }
+
+
+}

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

@@ -86,34 +86,36 @@ public class TableFileController extends BladeController {
 
         // 删除数据
         tableFileService.delDataById(ids, null);
-
-        List<TableFileVO> fileVOList = tableFileService.selectTableFileList(Long.parseLong(tableFile.getTabId()));
-        // 该文本无附件
-        if (fileVOList == null || fileVOList.size() <= 0) {
-            UpdateWrapper<WbsTreeContract> updateWrapper = new UpdateWrapper<>();
-            updateWrapper.in("p_key_id", tableFile.getTabId());
-            updateWrapper.set("tab_file_type", 1);
-            wbsTreeContractService.update(updateWrapper);
-        }
-        Long pkeyId = Long.parseLong(tableFile.getTabId() + "");
-        excelTabService.getBussPdfInfo(pkeyId);
-
-        WbsTreeContract wbsTreeContract = wbsTreeContractService.getBaseMapper().selectOne(Wrappers.<WbsTreeContract>query().lambda()
-                .eq(WbsTreeContract::getPKeyId, pkeyId));
-
-        WbsTreeContract wbsTreeContractP = wbsTreeContractService.getBaseMapper().selectOne(Wrappers.<WbsTreeContract>query().lambda()
-                .eq(WbsTreeContract::getContractId, wbsTreeContract.getContractId())
-                .eq(WbsTreeContract::getProjectId, wbsTreeContract.getProjectId())
-                .eq(WbsTreeContract::getId, wbsTreeContract.getParentId())
-        );
-        String classfy = "1";
-        String dataInfo = wbsTreeContract.getTableOwner();
-        if (dataInfo.equals("1") || dataInfo.equals("2") || dataInfo.equals("3")) {
-            classfy = "1";
-        } else if (dataInfo.equals("4") || dataInfo.equals("5") || dataInfo.equals("6")) {
-            classfy = "2";
+        //如果为节点附件,则不去做其他处理,只删除
+        if (tableFile.getType() == 1 || tableFile.getType() == 2) {
+            List<TableFileVO> fileVOList = tableFileService.selectTableFileList(Long.parseLong(tableFile.getTabId()));
+            // 该文本无附件
+            if (fileVOList == null || fileVOList.size() <= 0) {
+                UpdateWrapper<WbsTreeContract> updateWrapper = new UpdateWrapper<>();
+                updateWrapper.in("p_key_id", tableFile.getTabId());
+                updateWrapper.set("tab_file_type", 1);
+                wbsTreeContractService.update(updateWrapper);
+            }
+            Long pkeyId = Long.parseLong(tableFile.getTabId() + "");
+            excelTabService.getBussPdfInfo(pkeyId);
+
+            WbsTreeContract wbsTreeContract = wbsTreeContractService.getBaseMapper().selectOne(Wrappers.<WbsTreeContract>query().lambda()
+                    .eq(WbsTreeContract::getPKeyId, pkeyId));
+
+            WbsTreeContract wbsTreeContractP = wbsTreeContractService.getBaseMapper().selectOne(Wrappers.<WbsTreeContract>query().lambda()
+                    .eq(WbsTreeContract::getContractId, wbsTreeContract.getContractId())
+                    .eq(WbsTreeContract::getProjectId, wbsTreeContract.getProjectId())
+                    .eq(WbsTreeContract::getId, wbsTreeContract.getParentId())
+            );
+            String classfy = "1";
+            String dataInfo = wbsTreeContract.getTableOwner();
+            if (dataInfo.equals("1") || dataInfo.equals("2") || dataInfo.equals("3")) {
+                classfy = "1";
+            } else if (dataInfo.equals("4") || dataInfo.equals("5") || dataInfo.equals("6")) {
+                classfy = "2";
+            }
+            excelTabService.getBussPdfs(wbsTreeContractP.getPKeyId() + "", classfy, wbsTreeContract.getContractId(), wbsTreeContract.getProjectId());
         }
-        excelTabService.getBussPdfs(wbsTreeContractP.getPKeyId() + "", classfy, wbsTreeContract.getContractId(), wbsTreeContract.getProjectId());
         return R.status(true);
     }
 
@@ -222,8 +224,8 @@ public class TableFileController extends BladeController {
     @ApiImplicitParams(value = {
             @ApiImplicitParam(name = "pkeyid", value = "表单pkeyid", required = true),
     })
-    public R selectTableFileListByTen(Long pkeyid) {
-        List<TableFileVO> dataList= tableFileService.selectTableFileListByTen(pkeyid);
+    public R selectTableFileListByTen(Long pkeyid,Integer classify) {
+        List<TableFileVO> dataList= tableFileService.selectTableFileListByTen(pkeyid,classify);
         return R.data(dataList);
     }
 

+ 25 - 24
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/TextdictInfoController.java

@@ -19,23 +19,18 @@ package org.springblade.manager.controller;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import io.swagger.annotations.*;
 import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.*;
 import lombok.AllArgsConstructor;
-
-import javax.validation.Valid;
-
 import org.apache.commons.lang.StringUtils;
-import org.apache.commons.net.ftp.FTPClient;
 import org.jsoup.Jsoup;
 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.common.utils.SystemUtils;
+import org.springblade.core.boot.ctrl.BladeController;
 import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.mp.support.Condition;
 import org.springblade.core.mp.support.Query;
@@ -43,28 +38,30 @@ import org.springblade.core.redis.cache.BladeRedis;
 import org.springblade.core.secure.utils.SecureUtil;
 import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.utils.*;
-import org.springblade.manager.entity.*;
+import org.springblade.manager.entity.TextdictInfo;
+import org.springblade.manager.entity.WbsTreeContract;
+import org.springblade.manager.entity.WbsTreePrivate;
 import org.springblade.manager.mapper.WbsTreePrivateMapper;
+import org.springblade.manager.service.ITextdictInfoService;
 import org.springblade.manager.service.impl.WbsTreeContractServiceImpl;
-import org.springblade.manager.service.impl.WbsTreePrivateServiceImpl;
 import org.springblade.manager.utils.ExcelInfoUtils;
 import org.springblade.manager.utils.FileUtils;
 import org.springblade.manager.vo.*;
-import org.springblade.manager.wrapper.ExcelTabWrapper;
-import org.springblade.manager.wrapper.TextdictWrapper;
-import org.springblade.system.cache.ParamCache;
+import org.springframework.dao.DataAccessException;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
-import org.springframework.web.bind.annotation.RequestParam;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import org.springblade.manager.service.ITextdictInfoService;
-import org.springblade.core.boot.ctrl.BladeController;
 
-import java.io.*;
-import java.util.*;
+import javax.validation.Valid;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 /**
@@ -374,10 +371,15 @@ public class TextdictInfoController extends BladeController {
                 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 && wbsTreePrivate.getType() != 10) {
-                    String clarSql = "update  " + tabName + " set " + keyname.split("__")[0] + "=null where p_key_id in(SELECT p_key_id FROM m_wbs_tree_contract WHERE id ='" + wbsTreePrivate.getId() + "' and project_id='" + wbsTreePrivate.getProjectId() + "' )";
-                    jdbcTemplate.execute(clarSql);
+                    String clarSql = "update  " + tabName + " set " + keyname.split("__")[0] + "=null where p_key_id in(SELECT p_key_id FROM m_wbs_tree_contract WHERE is_type_private_pid ='" + wbsTreePrivate.getPKeyId() + "' and project_id='" + wbsTreePrivate.getProjectId() + "'UNION ALL SELECT 1 )";
+                    try {
+                        jdbcTemplate.execute(clarSql);
+                    } catch (DataAccessException e) {
+                        throw new RuntimeException("该实体信息无对应字段");
+                    }
                 }
             }
+
             File writeFile = ResourceUtil.getFile(wbsTreePrivate.getHtmlUrl());
             if (!writeFile.exists()) {
                 if (StringUtils.isNotEmpty(fileUrl)) {
@@ -516,8 +518,8 @@ public class TextdictInfoController extends BladeController {
                 }
             }
         }
-
         File writeFile = new File(wbsTreePrivate.getHtmlUrl());
+//        File writeFile = new File("D:\\file\\downfile\\1792757075013533696.html");
         FileUtil.writeToFile(writeFile, doc.html(), Boolean.parseBoolean("UTF-8"));
 
         String str1 = wbsTreePrivate.getHtmlUrl().replace("Desktop//privateUrl", "Desktop/privateUrl");
@@ -815,5 +817,4 @@ public class TextdictInfoController extends BladeController {
         TextdictInfoVO detail = textdictInfoService.selectTextdictInfoById(textdictInfo);
         return R.data(detail);
     }
-
 }

+ 33 - 8
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreeContractController.java

@@ -9,14 +9,15 @@ import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
 import com.google.common.collect.Lists;
 import com.spire.xls.FileFormat;
 import com.spire.xls.Worksheet;
-import io.swagger.annotations.*;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
 import lombok.SneakyThrows;
 import org.apache.commons.lang.StringUtils;
 import org.apache.poi.ss.usermodel.*;
-import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.ss.util.RegionUtil;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
@@ -47,21 +48,20 @@ import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
 
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.*;
+import java.net.URL;
 import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.*;
-import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
@@ -246,8 +246,8 @@ public class WbsTreeContractController extends BladeController {
     @GetMapping("/search-node-tablesAndFile")
     @ApiOperationSupport(order = 12)
     @ApiOperation(value = "查询当前节点下所有表的附件信息", notes = "传入节点primaryKeyId、type、合同段id、项目id")
-    public R<List<AppWbsTreeContractVO>> searchNodeAllTableAndFile(String primaryKeyId, String type, String contractId, String projectId) {
-        List<AppWbsTreeContractVO> list = iWbsTreeContractService.searchNodeAllTableAndFile(primaryKeyId, type, contractId, projectId);
+    public R<List<AppWbsTreeContractVO>> searchNodeAllTableAndFile(String primaryKeyId, String type, String contractId, String projectId,Integer classify) {
+        List<AppWbsTreeContractVO> list = iWbsTreeContractService.searchNodeAllTableAndFile(primaryKeyId, type, contractId, projectId,classify);
         return R.data(list);
     }
 
@@ -272,6 +272,12 @@ public class WbsTreeContractController extends BladeController {
                 WbsTreePrivate treePrivateTab = jdbcTemplate.query("select * from m_wbs_tree_private where p_key_id = " + pKeyId, new BeanPropertyRowMapper<>(WbsTreePrivate.class)).stream().findAny().orElse(null);
                 if (treePrivateTab != null && treePrivateTab.getHtmlUrl() != null) {
                     htmlUrl = treePrivateTab.getHtmlUrl();
+                    //<开始>-----------本地测试  下载html到本地
+//                    htmlUrl = FileUtils.getNetUrl(htmlUrl);
+//                    String localFilePath = "D:\\file\\downfile\\1792757075013533696.html";
+//                    downloadHtmlAndSave(htmlUrl, localFilePath);
+//                    htmlUrl =localFilePath;
+                    //本地测试  下载html到本地-----------<结束>
                     fileName = ObjectUtil.isNotEmpty(treePrivateTab.getFullName()) ? treePrivateTab.getFullName() : treePrivateTab.getNodeName();
                 }
             } else {
@@ -757,4 +763,23 @@ public class WbsTreeContractController extends BladeController {
         return R.success("成功");
     }
 
+    /**
+     * 文件存储到指定路径方法
+     * @param htmlUrl
+     * @param localFilePath
+     */
+    public static void downloadHtmlAndSave(String htmlUrl, String localFilePath) {
+        try (BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(htmlUrl).openStream(), StandardCharsets.UTF_8));
+             BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(localFilePath), StandardCharsets.UTF_8))) {
+
+            String line;
+            while ((line = reader.readLine()) != null) {
+                writer.write(line);
+                writer.newLine();
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
 }

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

@@ -1,14 +1,11 @@
 package org.springblade.manager.controller;
 
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
 import com.mixsmart.utils.StringUtils;
 import io.swagger.annotations.*;
 import lombok.AllArgsConstructor;
-import oracle.jdbc.proxy.annotation.Post;
-import org.springblade.business.entity.TrialSelfInspectionRecord;
 import org.springblade.business.vo.SaveLogContractVO;
 import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.core.boot.ctrl.BladeController;
@@ -36,7 +33,6 @@ import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.web.bind.annotation.*;
 
 import javax.validation.Valid;
-
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.*;
@@ -423,7 +419,6 @@ public class WbsTreePrivateController extends BladeController {
         return R.fail(200, "未查询到信息");
     }
 
-
     @PostMapping("/self/trial/getMixRatioTestTree")
     @ApiOperationSupport(order = 5)
     @ApiOperation(value = "获取当前节点的试验配合比树", notes = "传入当前节点的pKeyId")
@@ -435,7 +430,6 @@ public class WbsTreePrivateController extends BladeController {
         return R.fail(200, "未查询到信息");
     }
 
-
     /**
      * 获取当前节点详情
      */
@@ -703,7 +697,7 @@ public class WbsTreePrivateController extends BladeController {
                 }
 
                 //表单数据
-                List<Map<String, Object>> bussDataInfoTrial = iExcelTabService.getBussDataInfoTrial(id, treePrivate.getPKeyId(), Long.parseLong(contractId));
+                List<Map<String, Object>> bussDataInfoTrial = iExcelTabService.getBussDataInfoTrial(id, treePrivate.getPKeyId(), Long.parseLong(contractId),null);
                 if (bussDataInfoTrial != null && bussDataInfoTrial.size() > 0) {
                     bussDataInfoTrial.get(0).remove("group_id");
                     treePrivate.setBussDataInfoTrial(bussDataInfoTrial.get(0));

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

@@ -1,5 +1,6 @@
 package org.springblade.manager.feign;
 
+import com.alibaba.druid.util.DaemonThreadFactory;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@@ -29,6 +30,7 @@ import org.springblade.manager.enums.ExecuteType;
 import org.springblade.manager.service.IExcelTabService;
 import org.springblade.manager.service.IWbsTreePrivateService;
 import org.springblade.manager.utils.FileUtils;
+import org.springblade.manager.vo.WbsTreePrivateVO4;
 import org.springblade.resource.feign.NewIOSSClient;
 import org.springblade.system.cache.ParamCache;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
@@ -42,6 +44,7 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.InputStream;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 @RestController
@@ -53,6 +56,7 @@ public class ExcelTabClientImpl implements ExcelTabClient {
     private final NewIOSSClient newIOSSClient;
     private final InformationQueryClient informationQueryClient;
     private final ExcelTabController excelTabController;
+    private final IWbsTreePrivateService wbsTreePrivateService;
     private static final Logger logger = LoggerFactory.getLogger(ExcelTabClientImpl.class);
 
     @Override
@@ -69,6 +73,23 @@ public class ExcelTabClientImpl implements ExcelTabClient {
         String projectId = table.getString("projectId");
         String contractId = table.getString("contractId");
 
+    //    List<WbsTreePrivateVO4> wbsTreePrivateVO4s = wbsTreePrivateService.searchNodeAllTable(nodeId, type + "", "1", contractId, projectId, 0, id);
+/*        for (WbsTreePrivateVO4 treePrivate : wbsTreePrivateVO4s) {
+            if (tabIds.indexOf(treePrivate.getPKeyId() + "") < 0) {
+                List<Map<String, Object>> bussDataInfoTrial = excelTabService.getBussDataInfoTrial(id, treePrivate.getPKeyId(), Long.parseLong(contractId));
+                Map<String, Object> dataInfo = bussDataInfoTrial.get(0);
+                dataInfo.put("pkeyId", treePrivate.getPKeyId());
+                dataInfo.put("projectId", treePrivate.getProjectId());
+                dataInfo.put("type", 1);
+                dataInfo.put("isBussShow", 1);
+                dataInfo.put("nodeId", nodeId);
+                dataInfo.put("contractId", contractId);
+                dataInfo.put("oper", true);
+                dataInfo.put("isCollapseLoad", true);
+                dataArray.add(dataInfo);
+            }
+        }*/
+
         //应用抽取的数据
         dataArray = excelTabService.addLoadDataInfo(dataArray);
 
@@ -76,6 +97,7 @@ public class ExcelTabClientImpl implements ExcelTabClient {
         try {
             //------公式填充------
             this.excelTabService.formulaFillData(tableInfoList, Long.parseLong(nodeId), ExecuteType.TESTING);
+
         } catch (Exception e) {
             e.printStackTrace();
             throw new RuntimeException("试验公式执行异常,操作失败");
@@ -144,8 +166,9 @@ public class ExcelTabClientImpl implements ExcelTabClient {
     public R synPDFInfo(String contractId, String nodeIds, String classify, String projectId, String authorization) throws Exception {
         return excelTabController.synPDFInfo(contractId, nodeIds, classify, projectId);
     }
+
     @Override
-    public List<ExcelTab> getArchiveTabList(){
+    public List<ExcelTab> getArchiveTabList() {
         return excelTabService.getListByParentName("档案");
     }
 
@@ -172,7 +195,7 @@ public class ExcelTabClientImpl implements ExcelTabClient {
             //------试验填报数据保存,当前记录id作为groupId------
             this.excelTabService.saveOrUpdateInfoTrial(tableInfoList, Func.toLong(groupId));
 
-            pdfUrl = this.excelTabService.getEntrustPDFTrial(Func.toLong(pkeyId),contractId,Func.toLong(groupId));
+            pdfUrl = this.excelTabService.getEntrustPDFTrial(Func.toLong(pkeyId), contractId, Func.toLong(groupId));
 
         } catch (Exception e) {
             e.printStackTrace();

+ 10 - 6
blade-service/blade-manager/src/main/java/org/springblade/manager/feign/ManagerWebSocketClientImpl.java

@@ -1,24 +1,28 @@
 package org.springblade.manager.feign;
 
 import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
 import org.springblade.business.feign.OpinionUserClient;
 import org.springblade.core.tenant.annotation.NonDS;
+import org.springblade.manager.service.ISystemMsgService;
+import org.springblade.websocket.vo.UserInfoVO;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 import java.util.Map;
 
 @RestController
-@AllArgsConstructor
-@NonDS
+@RequiredArgsConstructor
 public class ManagerWebSocketClientImpl implements ManagerWebSocketClient {
 
-    private final OpinionUserClient opinionUserClient;
+    private final ISystemMsgService systemMsgService;
 
     @Override
-    @GetMapping(value = "/manager/getWebsocketMsg")
-    public Map<String, String> getWebsocketMsg(String projectId, String contractId, String userIdResult) {
-        return opinionUserClient.getWebsocketMsg(projectId, contractId, userIdResult);
+    @Async
+    public void pushMsg(UserInfoVO vo) {
+        //推送系统公告
+        systemMsgService.pushSystemMsg(vo);
     }
 
 }

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

@@ -213,7 +213,7 @@ public class WbsTreePrivateClientImpl implements WbsTreePrivateClient {
 
     @Override
     public List<Map<String, Object>> getTrialDataInfo(String pKeyId, Long id) {
-        return excelTabServiceImpl.getBussDataInfoTrial(id, Long.parseLong(pKeyId), null);
+        return excelTabServiceImpl.getBussDataInfoTrial(id, Long.parseLong(pKeyId), null,null);
     }
 
     @Override

+ 34 - 12
blade-service/blade-manager/src/main/java/org/springblade/manager/formula/impl/ExecutorMeter.java

@@ -1141,7 +1141,7 @@ public class ExecutorMeter extends FormulaExecutor {
                     /* fieldSetImmediately(hj,InterimPaymentCertificate::getCurrentPeriodEndPay,hj::setCurrentPeriodEndPay,x->!x.getIsSummary(),InterimPaymentCertificate::getInvertState);
                      fieldSetImmediately(hj,InterimPaymentCertificate::getPreviousPeriodEndPay,hj::setPreviousPeriodEndPay,x->!x.getIsSummary(),InterimPaymentCertificate::getInvertState);
                      fieldSetImmediately(hj,InterimPaymentCertificate::getCurrentPeriodPay,hj::setCurrentPeriodPay,x->!x.getIsSummary(),InterimPaymentCertificate::getInvertState);*/
-                     addGetSetConfig(hj,InterimPaymentCertificate::getContractAmount,hj::setContractAmount);
+                     /*addGetSetConfig(hj,InterimPaymentCertificate::getContractAmount,hj::setContractAmount);*/
                      addGetSetConfig(hj,InterimPaymentCertificate::getCurrentPeriodEndPay,hj::setCurrentPeriodEndPay);
                      addGetSetConfig(hj,InterimPaymentCertificate::getPreviousPeriodEndPay,hj::setPreviousPeriodEndPay);
                      addGetSetConfig(hj,InterimPaymentCertificate::getCurrentPeriodPay,hj::setCurrentPeriodPay);
@@ -1150,7 +1150,7 @@ public class ExecutorMeter extends FormulaExecutor {
                      payItemZj.add(new InterimPaymentCertificate("违约罚金",MINUS_ONE));
                      payItemZj.add(new InterimPaymentCertificate("迟付款利息"));
                      InterimPaymentCertificate startPay =new InterimPaymentCertificate("动员预付款");
-                     startPay.setContractAmount(StringUtils.handleNull(tec.meterInfo.getBaseInfo().getDyTotalAmount()));
+                     /*startPay.setContractAmount(StringUtils.handleNull(tec.meterInfo.getBaseInfo().getDyTotalAmount()));*/
                      if(tec.meterInfo.getStartPayFormAll()!=null){
                          /*中期计量第一期之前的*/
                         List<StartPayForm> startPayForm = tec.getMeterInfo().getStartPayFormAll();
@@ -1535,9 +1535,9 @@ public class ExecutorMeter extends FormulaExecutor {
             /**计量单位*/
             private String unit;
             /**合同数量*/
-            private Integer contractTotal=0;
+            private BigDecimal contractTotal=BigDecimal.ZERO;
             /**变更数量*/
-            private Integer changeTotal =0;
+            private BigDecimal changeTotal =BigDecimal.ZERO;
             /**完成数量*/
             private BigDecimal completed=BigDecimal.ZERO;
             /**单价*/
@@ -1562,8 +1562,8 @@ public class ExecutorMeter extends FormulaExecutor {
                     this.formNumber=p.getNumber();
                     this.itemName=p.getName();
                     this.unit = p.getUnit();
-                    this.contractTotal=p.getContractTotal();
-                    this.changeTotal = p.getChangeTotal();
+                    this.contractTotal=BaseUtils.str2BigDecimal(p.getContractTotal());
+                    this.changeTotal = BaseUtils.str2BigDecimal(p.getChangeTotal());
                     this.completed =BaseUtils.str2BigDecimal(p.getCompleted());
                     this.contractMoney =new BigDecimal(p.getContractMoney());
                     this.changeMoney =new BigDecimal(p.getChangeMoney());
@@ -1626,7 +1626,7 @@ public class ExecutorMeter extends FormulaExecutor {
                 sis.setFormNumber(itf.getFormNumber());
                 sis.setItemName(itf.getFormName());
                 sis.setUnit(itf.getUnit());
-                sis.setContractTotal(StringUtils.handleNull(itf.getContractTotal()));
+                sis.setContractTotal(BaseUtils.str2BigDecimal(itf.getContractTotal()).stripTrailingZeros().toPlainString());
                 sis.setContractMoney(itf.getContractMoney());
                 sis.setChangeMoney(itf.getChangeMoney());
                 sis.setPrice(itf.getBidPrice());
@@ -1652,7 +1652,11 @@ public class ExecutorMeter extends FormulaExecutor {
                     }
                     sis.setCompleted(end.getCompleted().toPlainString());
                     sis.setCurrentPeriodEndPay(end.getMoney().toPlainString());
-                    sis.setPayRatio(ratioFc.apply(sis.getCurrentPeriodEndPay(), sis.getChangeMoney()));
+                    BigDecimal percent= BaseUtils.str2BigDecimal(ratioFc.apply(sis.getCurrentPeriodEndPay(), sis.getChangeMoney()));
+                    if(BigDecimal.ZERO.compareTo(percent)<0) {
+                        /*百分比大于零才显示*/
+                        sis.setPayRatio(percent.setScale(2,RoundingMode.HALF_UP).stripTrailingZeros().toPlainString()+"%");
+                    }
                 }
                 totalList.add(sis);
             });
@@ -2280,6 +2284,9 @@ public class ExecutorMeter extends FormulaExecutor {
        private Function<Payment,String> chapterPreFixFc=payment -> {
             String pnb=  payment.getNumber().split("-")[0];
             if(BaseUtils.isNumber(pnb)){
+                if(payment.getNumber().contains(BTDL)){
+                   return  100 * (Integer.parseInt(pnb) / 100)+BTDL;
+                }
                 return 100 * (Integer.parseInt(pnb) / 100)+"";
             }
             return pnb;
@@ -2300,6 +2307,7 @@ public class ExecutorMeter extends FormulaExecutor {
             List<MeterApply> meterApplyList=tec.meterInfo.getMeterApplyList();
             Map<Long,MeterApply> meterApplyGroup = meterApplyList.stream().collect(Collectors.toMap(MeterApply::getId,m->m,(v1,v2)->v1));
            LinkedHashMap<String,List<Payment>>  group= current.stream().collect(Collectors.groupingBy(chapterPreFixFc,LinkedHashMap::new,Collectors.toList()));
+           String last= new LinkedList<>(group.keySet()).getLast();
            group.forEach((k,v)->{
                List<InterimMeterPaySummary> addList= new ArrayList<>();
                /*先按编号分组,再归集*/
@@ -2327,7 +2335,7 @@ public class ExecutorMeter extends FormulaExecutor {
                            InterimMeterPaySummary part = new InterimMeterPaySummary();
                            part.setItemName(meterApply.getEngineerDivide());
                            part.setMeterNumber(meterApply.getMeterNumber());
-                           part.setCompleted(pay.getCompleted().toString());
+                           part.setCompleted(pay.getCompleted());
                            partList.add(part);
                        }
                        partList.removeIf(e->BaseUtils.obj2DoubleZero(e.getCompleted())<=0);
@@ -2339,6 +2347,8 @@ public class ExecutorMeter extends FormulaExecutor {
                });
                dataList.addAll(addList);
                int add= capacity-addList.size()%capacity-1;
+               boolean isLast= last.equals(k);
+               if(isLast) add--;
                if(add>0){
                    dataList.addAll(Collections.nCopies(add,new InterimMeterPaySummary()));
                }
@@ -2346,6 +2356,12 @@ public class ExecutorMeter extends FormulaExecutor {
                String sum=addList.stream().map(InterimMeterPaySummary::getMoney).map(p->BaseUtils.str2BigDecimal(p).setScale(0,RoundingMode.HALF_UP)).reduce(BigDecimal.ZERO,BigDecimal::add).toPlainString();
                chapter.setMoney(sum);
                dataList.add(chapter);
+               if(isLast){
+                   InterimMeterPaySummary total = new InterimMeterPaySummary("合计");
+                   String st=dataList.stream().filter(s->"章小计".equals(s.getItemName())).map(InterimMeterPaySummary::getMoney).map(BaseUtils::str2BigDecimal).reduce(BigDecimal.ZERO,BigDecimal::add).toPlainString();
+                   total.setMoney(st);
+                   dataList.add(total);
+               }
            });
             tec.periodInfo.setSummaryNumber(String.valueOf(BaseUtils.sliceNumber(dataList.size(),capacity)));
             putOut(InterimMeterPaySummary.class);
@@ -2367,13 +2383,17 @@ public class ExecutorMeter extends FormulaExecutor {
                 Payment pm =paymentList.get(0);
                 String pnb=  pm.getNumber().split("-")[0];
                 if(BaseUtils.isNumber(pnb)){
-                    return 100 * (Integer.parseInt(pnb) / 100) +"章";
+                    String c=100 * (Integer.parseInt(pnb) / 100) +"章";
+                    if(pm.getNumber().contains(BTDL)){
+                        return c+BTDL;
+                    }
+                    return c;
                 }
             }
           String[]  arr= meterApply.getMeterNumber().split("-");
           return BaseUtils.handleObj2Integer(arr[arr.length-1])*100+"章";
         };
-        private Function<NodeTable,String> chapterNumberTableFc= nodeTable -> RegexUtil.findResult("\\d+章",nodeTable.getNodeName());
+        private Function<NodeTable,String> chapterNumberTableFc= nodeTable -> RegexUtil.findResult("\\d+章(保通道路)?",nodeTable.getNodeName());
         private  Map<Long,List<Payment>> paymentGroup=new HashMap<>();
         @Override
         public void parse() {
@@ -2578,6 +2598,7 @@ public class ExecutorMeter extends FormulaExecutor {
             FormData pageIndex = fdm.get(FormulaUtils.getPageIndex(clazz));
             if(pageFd!=null) {
                 int total = totalPage();
+                total=Math.max(1,total);
                 JSONField jf =FormulaUtils.getPageFormat(clazz);
                 String pageTmp;
                 if(jf != null&&jf.format().length()>0){
@@ -2586,7 +2607,8 @@ public class ExecutorMeter extends FormulaExecutor {
                     pageTmp = "第$1页 共" + total + "页";
                 }
                 if(pageTotal!=null){
-                    pageTotal.setValues(IntStream.rangeClosed(1, total).boxed().map(i -> new ElementData(total)).collect(Collectors.toList()));
+                    int finalTotal = total;
+                    pageTotal.setValues(IntStream.rangeClosed(1, total).boxed().map(i -> new ElementData(finalTotal)).collect(Collectors.toList()));
                 }
                 if(pageIndex!=null){
                     pageIndex.setValues(IntStream.rangeClosed(1, total).boxed().map(ElementData::new).collect(Collectors.toList()));

+ 88 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/job/SystemMsgJob.java

@@ -0,0 +1,88 @@
+package org.springblade.manager.job;
+
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.jackson.JsonUtil;
+import org.springblade.manager.entity.SystemMsg;
+import org.springblade.manager.service.ISystemMsgService;
+import org.springblade.websocket.vo.MsgVO;
+import org.springblade.websocket.vo.SystMsgVO;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @Param   系统消息定时器管理类
+ * @Author wangwl
+ * @Date 2024/9/5 10:18
+ **/
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class SystemMsgJob {
+
+    private final ISystemMsgService systemMsgService;
+
+    private final JdbcTemplate jdbcTemplate;
+
+    /**
+     *  定时推送公告-取消公告-修改公告状态,不想污染日志,使用jdbc
+     */
+    @Scheduled(cron = "0 */1 * * * ?")
+    public void autoUpdateMsgStatus(){
+        /** 普通公告推送*/
+        String sql1 = "select * from m_system_msg where is_deleted = 0 and msg_type = 2 and push_status = 1 and push_date_time <= TIMESTAMPADD(SECOND, 1, NOW()) and push_end_date_time >= now()";
+        List<SystemMsg> list1 = jdbcTemplate.query(sql1,new BeanPropertyRowMapper<>(SystemMsg.class));
+        if (list1.size() > 0){
+            for (SystemMsg msg : list1) {
+                systemMsgService.pushSystemMsgToAllUser(msg);
+            }
+            systemMsgService.update(new LambdaUpdateWrapper<SystemMsg>()
+                    .set(SystemMsg::getPushStatus,2)
+                    .in(SystemMsg::getId,list1.stream().map(SystemMsg::getId).collect(Collectors.toList())));
+        }
+        /** 维护公告推送*/
+        String sql2 = "select * from m_system_msg where is_deleted = 0 and msg_type = 1 and status = 1 and push_status = 1 and push_date_time >= now() and push_warn_date_time <= TIMESTAMPADD(SECOND, 1, NOW())";
+        List<SystemMsg> list2 = jdbcTemplate.query(sql2,new BeanPropertyRowMapper<>(SystemMsg.class));
+        if (list2.size() > 0){
+            for (SystemMsg msg : list2) {
+                systemMsgService.pushSystemMsgToAllUser(msg);
+            }
+            systemMsgService.update(new LambdaUpdateWrapper<SystemMsg>()
+                    .set(SystemMsg::getStatus,2)
+                    .in(SystemMsg::getId,list2.stream().map(SystemMsg::getId).collect(Collectors.toList())));
+        }
+        /** 维护倒计时*/
+        String sql3 = "select * from m_system_msg where is_deleted = 0 and msg_type = 1 and status != 3 and TIMESTAMPADD(SECOND, 1, NOW()) >= push_count_down_date_time and now() < push_date_time ";
+        List<SystemMsg> list3 = jdbcTemplate.query(sql3,new BeanPropertyRowMapper<>(SystemMsg.class));
+        if (list3.size() > 0){
+            SystemMsg msg = list3.get(0);
+            msg.setMsgType(3);
+            msg.setMsgContent(Duration.between(LocalDateTime.now(), msg.getPushDateTime()).getSeconds()+"");
+            systemMsgService.pushSystemMsgToAllUser(msg);
+            systemMsgService.update(new LambdaUpdateWrapper<SystemMsg>()
+                    .set(SystemMsg::getStatus,3)
+                    .eq(SystemMsg::getId,msg.getId()));
+        }
+
+        /** 维护公告修改状态*/
+        //搜索出发布时间超过当前时间的待发布公告
+        String sql4 = "select * from m_system_msg where is_deleted = 0 and msg_type = 1 and push_status = 1 and push_date_time < now()";
+        List<SystemMsg> list4 = jdbcTemplate.query(sql4,new BeanPropertyRowMapper<>(SystemMsg.class));
+        //如果有数据,则修改为已发布
+        if (list4.size() > 0){
+            systemMsgService.update(new LambdaUpdateWrapper<SystemMsg>()
+                    .set(SystemMsg::getPushStatus,2)
+                    .in(SystemMsg::getId,list4.stream().map(SystemMsg::getId).collect(Collectors.toList())));
+        }
+    }
+}

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

@@ -0,0 +1,25 @@
+package org.springblade.manager.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.apache.ibatis.annotations.Param;
+import org.springblade.manager.entity.SystemMsg;
+import org.springblade.manager.vo.SystemMsgVO;
+
+import java.util.List;
+
+/**
+ * @Param
+ * @Author wangwl
+ * @Date 2024/8/29 16:20
+ **/
+public interface SystemMsgMapper extends BaseMapper<SystemMsg> {
+    IPage<SystemMsgVO> page(IPage<SystemMsgVO> iPage, @Param("msgType") Integer msgType, @Param("pushStatus") Integer pushStatus);
+
+    List<SystemMsg> getAwaitMsg();
+
+
+    List<SystemMsg> getAwaitSystemMsg(@Param("system") String system);
+
+    SystemMsg getAwaitUpdateMsg(@Param("system") String system);
+}

+ 40 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/SystemMsgMapper.xml

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.manager.mapper.SystemMsgMapper">
+
+
+    <select id="page" resultType="org.springblade.manager.vo.SystemMsgVO">
+        select *,
+               if(msg_type = 1,"系统发布公告","系统普通公告") as msgTypeName
+        from m_system_msg
+        where is_deleted = 0
+        <if test="msgType != null">
+            and msg_type = #{msgType}
+        </if>
+        <if test="pushStatus != null">
+            and push_status = #{pushStatus}
+        </if>
+        order by push_date_time desc
+    </select>
+    <select id="getAwaitMsg" resultType="org.springblade.manager.entity.SystemMsg">
+        select *
+        from m_system_msg
+        where is_deleted = 0 and push_status = 1
+        order by push_date_time desc
+    </select>
+    <select id="getAwaitSystemMsg" resultType="org.springblade.manager.entity.SystemMsg">
+        select *
+        from m_system_msg
+        where is_deleted = 0 and push_system like concat('%',#{system},'%')
+          and msg_type = 2 and push_date_time &lt;= now() and push_end_date_time &gt;= now()
+        order by push_date_time desc
+    </select>
+    <select id="getAwaitUpdateMsg" resultType="org.springblade.manager.entity.SystemMsg">
+        select *
+        from m_system_msg
+        where is_deleted = 0 and push_status = 1 and push_system like concat('%',#{system},'%')
+          and msg_type = 1 and push_date_time &gt;= now() and push_warn_date_time &lt;= now()
+        order by push_date_time desc
+            limit 1
+    </select>
+</mapper>

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

@@ -44,9 +44,9 @@ public interface TableFileMapper extends BaseMapper<TableFile> {
     List<TableFileVO> selectTableFileList(String pKid);
 
 
-    List<TableFileVO> selectTableFileListByTen(String pKid);
+    List<TableFileVO> selectTableFileListByTen(String pKid,@Param("classify") Integer classify);
 
     void delDataById(String id, Long recordId);
 
-    List<TableFile> getAllFileByIds(@Param("ids") List<Long> ids);
+    List<TableFile> getAllFileByIds(@Param("ids") List<Long> ids,@Param("classify") Integer classify);
 }

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

@@ -37,7 +37,7 @@
         select *,domain_url as url from m_table_file where is_deleted = 0 and type=2 and tab_id = #{pKid}
     </select>
     <select id="getAllFileByIds" resultType="org.springblade.manager.entity.TableFile">
-        SELECT mtf.* from m_table_file mtf WHERE  type = 2 and tab_id in
+        SELECT mtf.* from m_table_file mtf WHERE is_deleted = 0 and classify = #{classify} and type = 2 and tab_id in
         <foreach collection="ids" item="id" open="(" close=")" separator=",">
             #{id}
         </foreach>
@@ -51,6 +51,6 @@
     </delete>
 
     <select id="selectTableFileListByTen" resultMap="TableFileVO">
-        select *,domain_url as url from m_table_file where is_deleted = 0 and type in (10,11,12) and tab_id = #{pKid}
+        select *,domain_url as url from m_table_file where is_deleted = 0  and classify = #{classify} and type in (10,11,12) and tab_id = #{pKid}
     </select>
 </mapper>

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

@@ -109,7 +109,7 @@ public interface WbsTreeContractMapper extends EasyBaseMapper<WbsTreeContract> {
 
     void tableSort(@Param("map") Map<Long, Integer> map);
 
-    List<APIWbsContractNodeVo> apiTreeNode(@Param("contractId") String contractId);
+    List<APIWbsContractNodeVo> apiTreeNode(@Param("contractId") String contractId,@Param("nodeName") String nodeName);
 
     List<APIWbsContractNodeHzrcVo> apiTreeNodeHzrc(@Param("contractId") String contractId,@Param("classType") Integer classType);
 }

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

@@ -841,6 +841,9 @@
         and wbs_type = 1
         and type=1
         and contract_id = #{contractId}
+        <if test="nodeName != null and nodeName != ''">
+            AND node_name like CONCAT(CONCAT('%', #{nodeName}), '%')
+        </if>
         ORDER BY type,sort
     </select>
 

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

@@ -17,25 +17,23 @@
 package org.springblade.manager.service;
 
 import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import org.jsoup.nodes.Document;
 import org.springblade.business.dto.TrialSelfInspectionRecordDTO;
+import org.springblade.core.mp.base.BaseService;
 import org.springblade.core.tool.api.R;
 import org.springblade.manager.bean.TableInfo;
-import org.springblade.manager.entity.*;
+import org.springblade.manager.entity.ExcelEditCallback;
+import org.springblade.manager.entity.ExcelTab;
+import org.springblade.manager.entity.WbsFormElement;
+import org.springblade.manager.entity.WbsTreeContract;
 import org.springblade.manager.enums.ExecuteType;
 import org.springblade.manager.vo.ExceTabTreVO;
 import org.springblade.manager.vo.ExcelTabVO;
-import org.springblade.core.mp.base.BaseService;
-import com.baomidou.mybatisplus.core.metadata.IPage;
 import org.springblade.manager.vo.ExcelTabWbsTypeVO;
 import org.springblade.manager.vo.WbsTreeVO;
-import org.springframework.web.bind.annotation.RequestParam;
 
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import java.io.FileNotFoundException;
-import java.io.IOException;
 import java.sql.SQLException;
 import java.util.List;
 import java.util.Map;
@@ -100,6 +98,7 @@ public interface IExcelTabService extends BaseService<ExcelTab> {
      * 公式填充
      */
     void formulaFillData(List<TableInfo> tableInfoList, Long nodeId, ExecuteType type);
+
     void formulaFillData2(JSONArray dataArray, ExecuteType type);
 
 
@@ -137,7 +136,7 @@ public interface IExcelTabService extends BaseService<ExcelTab> {
     /**
      * 获取试验用户端 单个表单接口数据
      */
-    List<Map<String, Object>> getBussDataInfoTrial(Long id, Long pkeyId, Long contractId);
+    List<Map<String, Object>> getBussDataInfoTrial(Long id, Long pkeyId, Long contractId, Long entrustId);
 
     /**
      * 获取试验用户端 单个表单接口数据 - 关联施工
@@ -210,5 +209,5 @@ public interface IExcelTabService extends BaseService<ExcelTab> {
      * @param contractId
      * @return
      */
-    List<Map<String, Object>> getBussDataInfoTrialentrust(Long id, Long pkeyId, Long contractId);
+    List<Map<String, Object>> getBussDataInfoTrialentrust(Long id, Long pkeyId, Long contractId, Long sampleId);
 }

+ 27 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/ISystemMsgService.java

@@ -0,0 +1,27 @@
+package org.springblade.manager.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springblade.core.mp.base.BaseService;
+import org.springblade.core.mp.support.Query;
+import org.springblade.manager.entity.SystemMsg;
+import org.springblade.manager.vo.SystemAwaitMsgVO;
+import org.springblade.manager.vo.SystemMsgVO;
+import org.springblade.websocket.vo.UserInfoVO;
+
+/**
+ * @Param
+ * @Author wangwl
+ * @Date 2024/8/29 16:23
+ **/
+public interface ISystemMsgService extends BaseService<SystemMsg> {
+    IPage<SystemMsgVO> page2(Query query, Integer msgType, Integer pushStatus);
+
+    SystemAwaitMsgVO getAwaitMsg();
+
+    //用户登录推送系统消息
+    void pushSystemMsg(UserInfoVO vo);
+
+    //后管发布时推送给选择系统的所有用户
+    void pushSystemMsgToAllUser(SystemMsg SystemMsg);
+
+}

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

@@ -32,7 +32,7 @@ import java.util.List;
  */
 public interface ITableFileService extends IService<TableFile> {
 
-    List<TableFile> getAllFileByIds(List<Long> list);
+    List<TableFile> getAllFileByIds(List<Long> list,Integer classify);
 
     /**
      * 自定义分页
@@ -47,6 +47,6 @@ public interface ITableFileService extends IService<TableFile> {
 
     void delDataById(String pkid, Long id);
 
-    List<TableFileVO> selectTableFileListByTen(Long pKid);
+    List<TableFileVO> selectTableFileListByTen(Long pKid,Integer classify);
 
 }

+ 4 - 2
blade-service/blade-manager/src/main/java/org/springblade/manager/service/IWbsTreeContractService.java

@@ -65,13 +65,15 @@ public interface IWbsTreeContractService extends BaseService<WbsTreeContract> {
 
     boolean syncContractTabSort(String projectId);
 
-    List<AppWbsTreeContractVO> searchNodeAllTableAndFile(String primaryKeyId, String type, String contractId, String projectId);
+    List<AppWbsTreeContractVO> searchNodeAllTableAndFile(String primaryKeyId, String type, String contractId, String projectId,Integer classify);
 
     List<WbsTreeContractLazyVO> getConcealedWorksNodeTree(String contractId, String parentId);
 
     //获取质检 wbs -甬台温
-    List<APIWbsContractNodeVo> apiTreeNode(String contractId);
+    List<APIWbsContractNodeVo> apiTreeNode(String contractId,String nodeName);
 
     //获取质检 wbs -湖州绕城
     List<APIWbsContractNodeHzrcVo> apiTreeNodeHzrc(String contractId,Integer classType);
+
+    List<ArchiveSyncWbsVO> getContractAllNode(Long contractId);
 }

+ 125 - 31
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ExcelTabServiceImpl.java

@@ -2,7 +2,6 @@ package org.springblade.manager.service.impl;
 
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.StopWatch;
-import org.springblade.core.mp.support.Query;
 import cn.hutool.log.StaticLog;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
@@ -15,33 +14,26 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.mixsmart.utils.FormulaUtils;
 import com.mixsmart.utils.ListUtils;
 import com.mixsmart.utils.RegexUtils;
-import com.spire.pdf.PdfDocument;
 import com.spire.xls.FileFormat;
-import com.spire.xls.Worksheet;
 import lombok.AllArgsConstructor;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-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.usermodel.Workbook;
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
 import org.jsoup.nodes.Element;
+import org.jsoup.nodes.Node;
 import org.jsoup.select.Elements;
 import org.springblade.business.dto.TrialSelfInspectionRecordDTO;
-import org.springblade.business.entity.ContractLog;
-import org.springblade.business.entity.InformationQuery;
-import org.springblade.business.entity.TrialSelfInspectionRecord;
+import org.springblade.business.entity.*;
 import org.springblade.business.feign.ContractLogClient;
 import org.springblade.business.feign.InformationQueryClient;
 import org.springblade.business.feign.OperationLogClient;
-import org.springblade.business.feign.TrialSelfInspectionRecordClient;
 import org.springblade.business.vo.SaveContractLogVO;
 import org.springblade.common.constant.CommonConstant;
 import org.springblade.common.utils.CommonUtil;
@@ -50,6 +42,7 @@ import org.springblade.common.vo.DataVO;
 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.support.Query;
 import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.secure.utils.AuthUtil;
 import org.springblade.core.tool.api.R;
@@ -66,14 +59,13 @@ import org.springblade.manager.formula.NodeTable;
 import org.springblade.manager.formula.impl.TableElementConverter;
 import org.springblade.manager.mapper.ExcelTabMapper;
 import org.springblade.manager.service.*;
-import org.springblade.manager.utils.ExcelInfoUtils;
 import org.springblade.manager.utils.FileUtils;
 import org.springblade.manager.utils.PdfAddimgUtil;
 import org.springblade.manager.vo.*;
 import org.springblade.resource.feign.NewIOSSClient;
 import org.springblade.system.cache.ParamCache;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.dao.DataAccessException;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
@@ -81,18 +73,13 @@ 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 java.awt.geom.Rectangle2D;
 import java.io.*;
-import java.net.URL;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
-import java.util.List;
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentSkipListMap;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
@@ -358,17 +345,27 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
                 List<NodeTable> tableAll = createNodeTables(nodeId, tableInfoList.get(0).getContractId(), tableInfoList.get(0).getProjectId(), type,tableInfoList.get(0).getClassify());
                 if (tableAll.size() > tableInfoList.size()) {
                     TableInfo example = tableInfoList.get(0);
+
                     /*补充缺失的数据*/
                     List<Long> cp = tableInfoList.stream().map(TableInfo::getPkeyId).map(Long::parseLong).collect(Collectors.toList());
                     List<Long> load = tableAll.stream().map(NodeTable::getPKeyId).filter(pk -> !cp.contains(pk)).collect(Collectors.toList());
+
                     Map<Long, String> keyMap = tableAll.stream().collect(toMap(NodeTable::getPKeyId, NodeTable::getInitTableName));
                     Map<String, List<Long>> loadMap = load.stream().collect(Collectors.groupingBy(keyMap::get, Collectors.toList()));
+
                     loadMap.entrySet().parallelStream().forEach(entry -> {
                         /*init_table_name*/
                         String k = entry.getKey();
                         /*pkeyId集合*/
                         List<Long> v = entry.getValue();
-                        List<Map<String, Object>> dataMap = this.jdbcTemplate.queryForList("select * from " + k + " where p_key_id in (" + v.stream().map(Objects::toString).collect(Collectors.joining(",")) + ")");
+                        String selSql = "";
+                        if(type.equals(ExecuteType.TESTING)) {
+                            selSql = "select * from " + k + " where p_key_id in (" + v.stream().map(Objects::toString).collect(Collectors.joining(",")) + ") and group_id="+example.getTestGroupId()+"";
+                        }else{
+                            selSql = "select * from " + k + " where p_key_id in (" + v.stream().map(Objects::toString).collect(Collectors.joining(",")) + ")";
+                        }
+
+                        List<Map<String, Object>> dataMap = this.jdbcTemplate.queryForList(selSql);
                         if (dataMap.size() > 0) {
                             dataMap.forEach(map -> {
                                 TableInfo e = new TableInfo();
@@ -2206,6 +2203,9 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
         FileUtils.excelToPdf(excelPath, pdfPath);
 
         BladeFile bladeFile = newIOSSClient.uploadFile(pkeyId + ".pdf", pdfPath);
+        if(pkeyId == 1806174262705258575L){
+            System.out.println();
+        }
 
         //附件
         TableFile tableFile1 = tableFileService.getBaseMapper().selectList(Wrappers.<TableFile>query().lambda().eq(TableFile::getTabId, pkeyId + "").eq(TableFile::getType, 1)).stream().findAny().orElse(null);
@@ -2323,6 +2323,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
                 TableInfo tableInfo = new TableInfo();
                 JSONObject dataInfo2 = dataArray.getJSONObject(m);
                 tableInfo.setPkeyId(dataInfo2.getString("pkeyId"));
+                tableInfo.setTestGroupId(dataInfo2.getString("group_id"));
                 tableInfo.setToBeUpdated(true);
 
                 // entrustInfo = 为 委托单信息
@@ -2410,7 +2411,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
      * 试验 获取填报信息
      */
     @Override
-    public List<Map<String, Object>> getBussDataInfoTrial(Long groupId, Long pkeyId, Long contractId) {
+    public List<Map<String, Object>> getBussDataInfoTrial(Long groupId, Long pkeyId, Long contractId, Long entrustId) {
         String file_path = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
         String sys_file_net_url = ParamCache.getValue(CommonConstant.SYS_FILE_NET_URL);
         List<Map<String, Object>> list = new ArrayList<>();
@@ -2468,6 +2469,26 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
             htmlString = htmlString.replaceAll("placeholder", "placeholderxx");
             htmlString = htmlString.replaceAll("title", "titlexx");
             Document doc = Jsoup.parse(htmlString);
+            if(entrustId != null){
+                //有委托单信息是从实验报告关联委托单进来的 通过委托单查询到具体的样品id
+                String sql = "select * from u_entrust_info where id ="+entrustId;
+                EntrustInfo entrustInfo = jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<>(EntrustInfo.class));
+                String  sampleId= entrustInfo.getSampleId().toString();
+                String querySql1 = "select * from u_trial_sample_info where id=" + sampleId ;
+                TrialSampleInfo sampleInfo = jdbcTemplate.queryForObject(querySql1, new BeanPropertyRowMapper<>(TrialSampleInfo.class));
+                //用sampleId查询出关联的材料对象
+                String querySql2 = "select * from u_trial_material_mobilization where id =(select mobilization_id from u_trial_sampling_record where sample_info_id = "+sampleId+") ";
+                TrialMaterialMobilization trialMaterialMobilization = null;
+                try {
+                    trialMaterialMobilization = jdbcTemplate.queryForObject(querySql2, new BeanPropertyRowMapper<>(TrialMaterialMobilization.class));
+                } catch (DataAccessException e) {
+                    trialMaterialMobilization = null;
+                }
+                //通过html获取页面上的key值 返回key值对应的数据
+                setBasicFormData(doc, reData, sampleInfo, trialMaterialMobilization,entrustInfo);
+            }
+
+
             //匹配
             Elements bgBH = doc.select("el-input[placeholderxx~=报告编号.*]");
             Elements cbdwBH = doc.select("el-input[placeholderxx~=承包单位.*]");
@@ -2871,7 +2892,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
         }
 
         //获取数据信息info
-        List<Map<String, Object>> bussDataInfoTrial = this.getBussDataInfoTrial(id, pkeyId, Long.parseLong(contractId));
+        List<Map<String, Object>> bussDataInfoTrial = this.getBussDataInfoTrial(id, pkeyId, Long.parseLong(contractId),null);
         Map<String, Object> DataInfo = new HashMap<>();
         if (bussDataInfoTrial.size() > 0) {
             DataInfo.putAll(bussDataInfoTrial.stream().findAny().orElse(null));
@@ -3948,7 +3969,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
         }
 
         //获取数据信息info
-        List<Map<String, Object>> bussDataInfoTrial = this.getBussDataInfoTrial(groupId, pkeyId, Long.parseLong(contractId));
+        List<Map<String, Object>> bussDataInfoTrial = this.getBussDataInfoTrial(groupId, pkeyId, Long.parseLong(contractId),null);
         Map<String, Object> DataInfo = new HashMap<>();
         if (bussDataInfoTrial.size() > 0) {
             DataInfo.putAll(bussDataInfoTrial.stream().findAny().orElse(null));
@@ -4326,10 +4347,10 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
 
 
     /**
-     * 试验 委托单获取填报信息
+     * 试验 委托单获取填报信息  groupId和sampleId1必须传其中一个
      */
     @Override
-    public List<Map<String, Object>> getBussDataInfoTrialentrust(Long groupId, Long pkeyId, Long contractId) {
+    public List<Map<String, Object>> getBussDataInfoTrialentrust(Long groupId, Long pkeyId, Long contractId,Long sampleId1) {
         String file_path = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
         String sys_file_net_url = ParamCache.getValue(CommonConstant.SYS_FILE_NET_URL);
         List<Map<String, Object>> list = new ArrayList<>();
@@ -4355,6 +4376,10 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
         //获取引用数据信息
         String loadDataId = "";
         String sampleId = "";
+        if(groupId == null){
+            sampleId = sampleId1.toString();
+        }
+
         try {
             String sqlQuery = "select * from u_trial_self_data_record where record_id = " + groupId + " and tab_id = " + pkeyId;
             List<Map<String, Object>> stringObjectMap = jdbcTemplate.queryForList(sqlQuery);
@@ -4362,10 +4387,12 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
                 loadDataId = stringObjectMap.get(0).get("load_data_id") + "";
             }
 
-            String samQuery = "SELECT * from u_entrust_info where id=" + groupId + " ";
-            List<Map<String, Object>> strbjectMap = jdbcTemplate.queryForList(samQuery);
-            if (strbjectMap != null && strbjectMap.size() >= 1) {
-                sampleId = strbjectMap.get(0).get("sample_id") + "";
+            if(groupId !=null){
+                String samQuery = "SELECT * from u_entrust_info where id=" + groupId + " ";
+                List<Map<String, Object>> strbjectMap = jdbcTemplate.queryForList(samQuery);
+                if (strbjectMap != null && strbjectMap.size() >= 1) {
+                    sampleId = strbjectMap.get(0).get("sample_id") + "";
+                }
             }
         } catch (Exception e) {
             e.printStackTrace();
@@ -4374,8 +4401,16 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
             reData.put("loadDataId", loadDataId);
             reData.put("sampleId", sampleId);
         }
-
-
+        String querySql1 = "select * from u_trial_sample_info where id=" + sampleId ;
+        TrialSampleInfo sampleInfo = jdbcTemplate.queryForObject(querySql1, new BeanPropertyRowMapper<>(TrialSampleInfo.class));
+        //用sampleId查询出关联的材料对象
+        String querySql2 = "select * from u_trial_material_mobilization where id =(select mobilization_id from u_trial_sampling_record where sample_info_id = "+sampleId+") ";
+        TrialMaterialMobilization trialMaterialMobilization = null;
+        try {
+            trialMaterialMobilization = jdbcTemplate.queryForObject(querySql2, new BeanPropertyRowMapper<>(TrialMaterialMobilization.class));
+        } catch (DataAccessException e) {
+            trialMaterialMobilization = null;
+        }
         //实体数据
         String querySql = "select * from " + wbsTreePrivate.getInitTableName() + " where p_key_id=" + pkeyId + " and group_id = " + groupId;
         List<Map<String, Object>> dataIn = jdbcTemplate.queryForList(querySql);
@@ -4395,8 +4430,8 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
             htmlString = htmlString.replaceAll("placeholder", "placeholderxx");
             htmlString = htmlString.replaceAll("title", "titlexx");
             Document doc = Jsoup.parse(htmlString);
-
-
+            //通过html获取页面上的key值 返回key值对应的数据
+            setBasicFormData(doc, reData, sampleInfo, trialMaterialMobilization,null);
             if (dataIn.size() >= 1) {
                 Map<String, Object> mysqlData = dataIn.get(0);
                 for (String key : mysqlData.keySet()) {
@@ -4494,4 +4529,63 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
         return list;
     }
 
+    private static void setBasicFormData(Document doc, Map<String, Object> reData, TrialSampleInfo sampleInfo ,TrialMaterialMobilization trialMaterialMobilization, EntrustInfo entrustInfo) {
+        setFirstData(doc,"委托编号",entrustInfo.getEntrustNo(),reData);
+        setFirstData(doc,"样品编号",sampleInfo.getSpecificationNumber(),reData);
+        setFirstData(doc,"取样地点",sampleInfo.getSamplingLocation(),reData);
+        setFirstData(doc,"样品描述",sampleInfo.getSampleDescription(),reData);
+        setFirstData(doc,"取样时间",sampleInfo.getSamplingDate(),reData);
+        setFirstData(doc,"取样日期",sampleInfo.getSamplingDate(),reData);
+        setFirstData(doc,"试样名称",sampleInfo.getMaterialName(),reData);
+        setFirstData(doc,"样品名称",sampleInfo.getMaterialName(),reData);
+        setFirstData(doc,"规格 型号",sampleInfo.getSpecificationModel(),reData);
+        setFirstData(doc,"规格型号",sampleInfo.getSpecificationModel(),reData);
+        setFirstData(doc,"试样 数量",sampleInfo.getMaterialCount(),reData);
+        if(trialMaterialMobilization != null){
+            setFirstData(doc,"生产厂家",trialMaterialMobilization.getPlaceOfProduction(),reData);
+        }
+        String representativeCount = sampleInfo.getRepresentativeCount();
+        Date mobilizationDate = sampleInfo.getMobilizationDate();
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:ss:mm");
+        String format = simpleDateFormat.format(mobilizationDate);
+        setFirstData(doc,"批号",sampleInfo.getBatchNumber(),reData);
+        setFirstData(doc,"拟用结构部 位",sampleInfo.getProposedPosition(),reData);
+        setFirstData(doc,"进场日期代表数量",format+representativeCount,reData);
+    }
+    private static void setFirstData(Document doc, String elementValue,Object value,Map<String, Object> reData) {
+
+        Elements select = doc.select("[placeholderxx=" + elementValue + "]");
+        if(select.isEmpty()){
+            elementValue = elementValue + ":";
+            select = doc.select("[placeholderxx=" + elementValue + "]");
+        }
+        if (!select.isEmpty()) {
+            Element textareaElement = select.stream().filter(element -> element.tagName().equals("el-input")).findFirst().orElse(null);
+            if( (elementValue.contains("时间") || elementValue.contains("日期")) && textareaElement == null){
+                textareaElement = select.first();
+                String keyName = textareaElement.attr("keyName");
+                reData.put(keyName, value);
+                return;
+            }
+            if(textareaElement != null){
+                String id = textareaElement.attr("id");
+                reData.put(id, value);
+            }
+        } else {
+            if(elementValue.equals("进场日期代表数量")){
+                Elements select1 = doc.select("[titlexx=\"进场日期/ 代表数量\"]");
+                Element textareaElement = select1.stream().filter(element -> element.tagName().equals("el-input")).findFirst().orElse(null);
+                if(textareaElement != null){
+                    List<Node> nodes = textareaElement.childNodes();
+                    Node node = nodes.get(1);
+                    String id = node.attributes().get("id");
+                    reData.put(id, value);
+                }
+//                Element textareaElement = select1.first();
+            }else {
+                System.out.println("没有找到[" + elementValue + "]的元素");
+            }
+        }
+    }
+
 }

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

@@ -1,5 +1,6 @@
 package org.springblade.manager.service.impl;
 
+import com.mixsmart.utils.CustomFunction;
 import com.mixsmart.utils.StringUtils;
 import lombok.RequiredArgsConstructor;
 import org.springblade.common.utils.BaseUtils;
@@ -42,6 +43,9 @@ public class FormulaDaoImpl implements IFormulaDao {
             ContractInfo info=  this.contractInfoService.getById(contractId);
             ProjectInfo projectInfo= projectInfoService.getById(info.getPId());
             BeanUtils.copyProperties(info,baseInfo);
+            if(info.getProjectMileage()!=null){
+                baseInfo.setProjectMileage(info.getProjectMileage().toPlainString());
+            }
             if(info.getPlanStartTime()!=null) {
                 baseInfo.setStartDatePlan(info.getPlanStartTime().format(chineseDateFm));
             }

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

@@ -178,9 +178,11 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
             tec.constantMap.put(CHAIN,nodes.stream().map(e->StringUtils.isNotEmpty(e.getFullName())?e.getFullName():e.getNodeName()).collect(Collectors.toList()));
             /*节点参数*/
             tec.constantMap.put(WP,getWpMap(one,tec));
+
             /*表格名称*/
             List<AppWbsTreeContractVO> tableList =wbsTreeContractService.searchNodeAllTable(one.getPkId().toString(), "1", tec.getContractId().toString(),tec.getProjectId().toString(),null);
             tec.constantMap.put(TABLE_LIST,tableList);
+
             /*监表质量附件,过滤掉隐藏表格*/
             tec.constantMap.put("tableNames",tableList.stream().filter(e->StringUtils.isEquals(e.getIsBussShow(),1)&&StringUtils.isNotEquals(e.getTableType(),4)).map(WbsTreeContract::getNodeName).collect(Collectors.toList()));
 
@@ -1118,6 +1120,9 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
         for(FormData fd:tec.formDataList){
             if(fd.verify()){
                 Formula formula =fd.getFormula();
+                if(formula.getId()==1575013024912113671l){
+                    System.out.println("");
+                }
                 String f=formula.getFormula();
                 if(Func.isNotBlank(f)){
                     try{
@@ -2808,7 +2813,9 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                             /*swId是分项评定的父节点Id*/
                             List<FormulaDataBlock> formulaDataBlocks = this.getSqlList("select a.id,a.type,a.sw_id swId,a.contract_id contractId,a.val from m_formula_data_block a join (select parent_id from m_wbs_tree_contract where tree_code like '" + treeCode.getLast() + "%' and contract_id =" + wtcEva.getContractId() + " and major_data_type=2 and is_deleted=0 ORDER BY tree_code)b on a.sw_id=b.parent_id ", FormulaDataBlock.class);
                             if (formulaDataBlocks != null && formulaDataBlocks.size() > 0) {
+
                                 /*就是分项工程节点的父节点名称*/
+
                                 String swIds = formulaDataBlocks.stream().map(FormulaDataBlock::getSwId).map(Objects::toString).collect(Collectors.joining(","));
                                 List<Map<String, Object>> listMaps = this.jdbcTemplate.queryForList("select id ,node_name nodeName,full_name fullName  from m_wbs_tree_contract where is_deleted =0 and contract_id=" + wtcEva.getContractId() + " and id in(" + swIds + ")");
                                 Map<String, String> swNameMap = new HashMap<>();
@@ -3004,7 +3011,8 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
         MeterType meterType = MeterType.getByIndex(type,contractInfo.getContractType());
         /*元素创建*/
         Map<String,String> parent=  getWtpParent(meterType.getName(),contractInfo.getPId());
-        List<NodeTable> tableList=getTableListMeter(parent);
+        List<NodeTable> tableList = getTableListMeter(parent);
+        // 表-html 间的关系
         Map<String,Document> documentMap=  tableList.parallelStream().collect(Collectors.toMap(NodeTable::getInitTableName,m->{
             String htmlUrl = m.getHtmlUrl();
             InputStream inputStreamByUrl = null;
@@ -3029,11 +3037,14 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
         executionTime.info("坐标信息获取");
         /*额外单元格坐标配置*/
         settingCoordsExtend(coordinateMap);
+        // 获取表对应的所有元素字段信息
         List<FormData> processFds = this.createFormDataByTableName(tableList.stream().map(NodeTable::getInitTableName).collect(Collectors.joining("','")));
         listForMeter(processFds,contractInfo.getPId(),parent.get("id"));
         executionTime.info("元素信息");
+
         /*转换器上下文声明*/
         TableElementConverter tec = new TableElementConverter(processFds,coordinateMap,tableList);
+
         tec.setNewIOSSClient(this.newIOSSClient);
         tec.setProjectId(Long.parseLong(contractInfo.getPId()));
         tec.setESignMaps(eSignMaps);
@@ -3047,6 +3058,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
         List<FormulaHandleChain> formulaHandleChains = new ArrayList<>();
         /*初始化*/
         ExecutorInit init= new ExecutorInit(tec);
+
         BeanUtils.copyProperties(this.formulaDao,init);
         formulaHandleChains.add(init);
         formulaHandleChains.add(new ExecutorSort(tec));

+ 151 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/SystemMsgServiceImpl.java

@@ -0,0 +1,151 @@
+package org.springblade.manager.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.AllArgsConstructor;
+import org.springblade.common.constant.WebsocketMsgConstant;
+import org.springblade.core.mp.base.BaseServiceImpl;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.jackson.JsonUtil;
+import org.springblade.manager.entity.SystemMsg;
+import org.springblade.manager.mapper.SystemMsgMapper;
+import org.springblade.manager.service.ISystemMsgService;
+import org.springblade.manager.vo.SystemAwaitMsgVO;
+import org.springblade.manager.vo.SystemMsgVO;
+import org.springblade.meter.entity.TaskRepealMessage;
+import org.springblade.websocket.feign.WebSocketClient;
+import org.springblade.websocket.vo.MsgVO;
+import org.springblade.websocket.vo.SystMsgVO;
+import org.springblade.websocket.vo.UserInfoVO;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @Param
+ * @Author wangwl
+ * @Date 2024/8/29 16:25
+ **/
+@Service
+@AllArgsConstructor
+public class SystemMsgServiceImpl extends BaseServiceImpl<SystemMsgMapper, SystemMsg> implements ISystemMsgService {
+
+    private final WebSocketClient webSocketClient;
+
+    private final JdbcTemplate jdbcTemplate;
+    @Override
+    public IPage<SystemMsgVO> page2(Query query, Integer msgType, Integer pushStatus) {
+        IPage<SystemMsgVO> iPage = new Page<>(query.getCurrent(), query.getSize());
+        iPage = baseMapper.page(iPage, msgType, pushStatus);
+        return iPage;
+    }
+
+    @Override
+    public SystemAwaitMsgVO getAwaitMsg() {
+        //获取出系统中所有待发布的公告
+        List<SystemMsg> list = baseMapper.getAwaitMsg();
+        SystemAwaitMsgVO vo = new SystemAwaitMsgVO();
+        List<SystemAwaitMsgVO.MsgInfo> updateMsg = new ArrayList<>();
+        List<SystemAwaitMsgVO.MsgInfo> systemMsg = new ArrayList<>();
+        updateMsg.add(setMsgInfo(list.stream().filter(l -> l.getMsgType() == 1 && l.getUpdateServerType().contains("1")).collect(Collectors.toList())));
+        updateMsg.add(setMsgInfo(list.stream().filter(l -> l.getMsgType() == 1 && l.getUpdateServerType().contains("2")).collect(Collectors.toList())));
+        systemMsg.add(setMsgInfo(list.stream().filter(l -> l.getMsgType() == 2).collect(Collectors.toList())));
+        vo.setUpdateMsg(updateMsg);
+        vo.setSystemMsg(systemMsg);
+        vo.setMsgTotal(list.size());
+        return vo;
+    }
+
+    /**
+     * 推送系统消息
+     * @param vo
+     */
+    @Override
+    @Async
+    public void pushSystemMsg(UserInfoVO vo) {
+        try {
+            Thread.sleep(10L);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+        String msgType = vo.getMsgType();
+        if (msgType.contains("2")) {
+            //获取当前系统普通公告
+            List<SystemMsg> systemMsgs = baseMapper.getAwaitSystemMsg(vo.getSystem());
+            if (systemMsgs.size() > 0) {
+                for (SystemMsg systemMsg : systemMsgs) {
+                    MsgVO<String> msgVO = new MsgVO<>();
+                    msgVO.setType(WebsocketMsgConstant.MSG_SYSTEM_MSG);
+                    msgVO.setData(systemMsg.getMsgContent());
+                    String msg = JsonUtil.toJson(R.data(msgVO));
+                    vo.setMsg(msg);
+                    webSocketClient.sendMsg(vo);
+                }
+            }
+        }
+        if (msgType.contains("1")) {
+            //获取当前系统维护公告
+            SystemMsg updateMsg = baseMapper.getAwaitUpdateMsg(vo.getSystem());
+            if (updateMsg != null) {
+                MsgVO<String> msgVO = new MsgVO<>();
+                msgVO.setType(WebsocketMsgConstant.MSG_UPDATE_MSG);
+                msgVO.setData(updateMsg.getMsgContent());
+                String msg = JsonUtil.toJson(R.data(msgVO));
+                vo.setMsg(msg);
+                webSocketClient.sendMsg(vo);
+            }
+        }
+        /** 查看是否正在倒计时*/
+        /** 维护倒计时*/
+        if (msgType.contains("3")) {
+            String sql3 = "select * from m_system_msg where is_deleted = 0 and msg_type = 1 and TIMESTAMPADD(SECOND, 1, NOW()) >= push_count_down_date_time and now() < push_date_time ";
+            List<SystemMsg> list3 = jdbcTemplate.query(sql3, new BeanPropertyRowMapper<>(SystemMsg.class));
+            if (list3.size() > 0) {
+                SystemMsg countDownMsg = list3.get(0);
+                MsgVO<String> msgVO = new MsgVO<>();
+                msgVO.setType(WebsocketMsgConstant.MSG_COUNT_DOWN);
+                msgVO.setData(Duration.between(LocalDateTime.now(), countDownMsg.getPushDateTime()).getSeconds() + "");
+                String msg = JsonUtil.toJson(R.data(msgVO));
+                vo.setMsg(msg);
+                webSocketClient.sendMsg(vo);
+            }
+        }
+
+    }
+
+    /**
+     * 后管发布时推送给选择系统的所有用户
+     * @param msg
+     */
+    @Override
+    @Async
+    public void pushSystemMsgToAllUser(SystemMsg msg) {
+        SystMsgVO systMsgVO = new SystMsgVO();
+        systMsgVO.setMsgType(msg.getMsgType());
+        systMsgVO.setPushSystem(msg.getPushSystem());
+        systMsgVO.setMsgContent(msg.getMsgContent());
+        webSocketClient.sendSystemMsg(systMsgVO);
+    }
+
+    private SystemAwaitMsgVO.MsgInfo setMsgInfo(List<SystemMsg> list) {
+        SystemAwaitMsgVO.MsgInfo msgInfo = new SystemAwaitMsgVO.MsgInfo();
+        if (list.size() > 0) {
+            msgInfo.setAwaitMsgTotal(1);
+            msgInfo.setCreatUserName(list.get(0).getCreatUserName());
+            msgInfo.setPushDateTime(list.get(0).getPushDateTime());
+        } else {
+            msgInfo.setAwaitMsgTotal(0);
+        }
+        return msgInfo;
+    }
+}

+ 4 - 4
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/TableFileServiceImpl.java

@@ -36,8 +36,8 @@ import java.util.List;
 public class TableFileServiceImpl extends ServiceImpl<TableFileMapper, TableFile> implements ITableFileService {
 
     @Override
-    public List<TableFile> getAllFileByIds(List<Long> ids) {
-        return baseMapper.getAllFileByIds(ids);
+    public List<TableFile> getAllFileByIds(List<Long> ids,Integer classify) {
+        return baseMapper.getAllFileByIds(ids,classify);
     }
 
     @Override
@@ -56,7 +56,7 @@ public class TableFileServiceImpl extends ServiceImpl<TableFileMapper, TableFile
     }
 
     @Override
-    public List<TableFileVO> selectTableFileListByTen(Long pKid) {
-        return baseMapper.selectTableFileListByTen(pKid + "");
+    public List<TableFileVO> selectTableFileListByTen(Long pKid,Integer classify) {
+        return baseMapper.selectTableFileListByTen(pKid + "",classify);
     }
 }

+ 11 - 5
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeContractServiceImpl.java

@@ -989,14 +989,15 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
 
     @Override
     public List<AppWbsTreeContractVO> searchNodeAllTableAndFile(String primaryKeyId, String type, String
-            contractId, String projectId) {
+            contractId, String projectId,Integer classify) {
         List<AppWbsTreeContractVO> vos = this.searchNodeAllTable(primaryKeyId, type, contractId, projectId, null);
         List<AppWbsTreeContractVO> voList = new ArrayList<>();
         List<TableFile> files2 = tableFileService.list(new LambdaQueryWrapper<TableFile>()
-                .eq(TableFile::getTabId,primaryKeyId));
+                .eq(TableFile::getTabId,primaryKeyId)
+                .eq(TableFile::getClassify,classify));
         if (vos != null && vos.size() > 0) {
             List<Long> list = vos.stream().map(AppWbsTreeContractVO::getPKeyId).collect(Collectors.toList());
-            List<TableFile> files = tableFileService.getAllFileByIds(list);
+            List<TableFile> files = tableFileService.getAllFileByIds(list,classify);
             if (files != null && files.size() > 0) {
                 Map<String, List<TableFile>> map = files.parallelStream()
                         .collect(Collectors.groupingBy(TableFile::getTabId));
@@ -1081,8 +1082,8 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
      * @return
      */
     @Override
-    public List<APIWbsContractNodeVo> apiTreeNode(String contractId) {
-        return ForestNodeMerger.merge(baseMapper.apiTreeNode(contractId));
+    public List<APIWbsContractNodeVo> apiTreeNode(String contractId,String nodeName) {
+        return ForestNodeMerger.merge(baseMapper.apiTreeNode(contractId,nodeName));
     }
 
     /**
@@ -1095,6 +1096,11 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
         return ForestNodeMerger.merge(baseMapper.apiTreeNodeHzrc(contractId,classType));
     }
 
+    @Override
+    public List<ArchiveSyncWbsVO> getContractAllNode(Long contractId) {
+        return baseMapper.getContractAllNode(contractId);
+    }
+
     /**
      * 递归获取隐蔽工程节点的所有父级节点
      *

+ 3 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/controller/MeterTreeController.java

@@ -727,6 +727,9 @@ public class MeterTreeController extends BladeController {
             vo.setLinkNodeList(wbsTreeVOS);
         } else {
             meterTreeContractService.getAllChildNodeMoney(vo);
+            //设置清单
+            List<ContractFromVO> contrFormAllByContrId = contractInventoryFormService.getChildNodeResolveForm(vo.getContractId(), vo.getId());
+            vo.setDecompositionList(contrFormAllByContrId);
         }
         return R.data(vo);
     }

+ 18 - 5
blade-service/blade-meter/src/main/java/org/springblade/meter/controller/TaskController.java

@@ -110,8 +110,7 @@ import java.util.function.Function;
 import java.util.regex.Matcher;
 import java.util.stream.Collectors;
 
-import static org.bouncycastle.asn1.x500.style.RFC4519Style.l;
-import static org.bouncycastle.asn1.x500.style.RFC4519Style.o;
+import static org.bouncycastle.asn1.x500.style.RFC4519Style.*;
 
 @RestController
 @AllArgsConstructor
@@ -1424,7 +1423,13 @@ public class TaskController extends BladeController {
                                     //获取本期之前所有计量期金额
                                     if (task.getMeterTaskType() == 1) {
                                         //中间计量
-                                        beforeMoney = contractMeterPeriodMapper.getBeforeMoney(periodVO);
+                                        //是第一期。则获取开工计量已审批的金额
+                                        if (periodVO.getId().equals(contractMeterPeriodMapper.getFirst(periodVO.getContractId()))){
+                                            periodVO.setType(3);
+                                            beforeMoney = meterPeriodMapper.getBeforeMoney(periodVO);
+                                        }else {
+                                            beforeMoney = contractMeterPeriodMapper.getBeforeMoney(periodVO);
+                                        }
                                     } else if (task.getMeterTaskType() == 2 || task.getMeterTaskType() == 3) {
                                         //材料计量,开工计量
                                         beforeMoney = meterPeriodMapper.getBeforeMoney(periodVO);
@@ -1439,6 +1444,13 @@ public class TaskController extends BladeController {
                                     tableData = dataInfo;
                                 }
                                 vo.setTableData(tableData);
+                                //设置需要计算的key,按照顺序,本期-截至上期-已累计
+                                List<String> str = new ArrayList<>();
+                                str.add(map.get("造价机构现场咨询意见_本期审核进度款(元)"));
+                                str.add(map.get("造价机构现场咨询意见_截止上期已累计审批进度款(元)"));
+                                str.add(map.get("造价机构现场咨询意见_截止上期已累计审批进度款(元)_截止本期已累计审核进度款(元)"));
+                                vo.setCalculateKey(str);
+
                             } else {
                                 if (StringUtils.isNotBlank(task.getAttachmentPdfUrl())) {
                                     vo.setOpinionType(2);
@@ -4034,16 +4046,17 @@ public class TaskController extends BladeController {
 
 
     // 添加电签任务列表
+    @Transactional
     public void addSignTaskBatch(Report report) {
         try {
             // 修改个人电签状态
             String UPSql = "update u_task_parallel a set a.e_visa_status=null,e_visa_content=null where a.process_instance_id = (select b.process_instance_id from u_task b where  b.`status` in(1,2) and b.form_data_id=" + report.getPeriodId() +  ") ";
             String DeSql = "delete from u_task_batch where task_parallel_id = (select b.process_instance_id from u_task b where b.`status` in(1,2) and b.form_data_id=" + report.getPeriodId()  + ")";
             //删除以前存在的电签
-            String sql = " insert INTO u_task_batch(id,task_parallel_id,json_data,create_user,create_dept,create_time,update_user,update_time,status,is_deleted,nick_name) " + " SELECT a.id,a.process_instance_id,json_object('approvalFileList',json_array(),'approvalType',b.meter_task_type,'comment','','flag','OK','formDataId',b.form_data_id,'parallelProcessInstanceId',a.parallel_process_instance_id,'pass',true,'taskId',b.id) as  json_data,a.task_user,a.create_dept,a.create_time,a.update_user,a.update_time,1 as status,0 as is_deleted,a.task_user_name as nick_name " + " from u_task_parallel a,u_task b where b.`status` in(1,2) and a.status=2 and  a.process_instance_id=b.process_instance_id and b.form_data_id= '" + report.getPeriodId()+"'";
-            jdbcTemplate.execute(sql);
+            String sql = " insert INTO u_task_batch(id,task_parallel_id,json_data,create_user,create_dept,create_time,update_user,update_time,status,is_deleted,nick_name) " + " SELECT a.id,a.process_instance_id,json_object('approvalFileList',json_array(),'approvalType',b.approval_type,'comment','','flag','OK','formDataId',b.form_data_id,'parallelProcessInstanceId',a.parallel_process_instance_id,'pass',true,'taskId',b.id) as  json_data,a.task_user,a.create_dept,a.create_time,a.update_user,a.update_time,1 as status,0 as is_deleted,a.task_user_name as nick_name " + " from u_task_parallel a,u_task b where b.`status` in(1,2) and  a.process_instance_id=b.process_instance_id and b.form_data_id= '" + report.getPeriodId()+"'";
             jdbcTemplate.execute(DeSql);
             jdbcTemplate.execute(UPSql);
+            jdbcTemplate.execute(sql);
         } catch (Exception e) {
             StaticLog.error(e.getMessage());
         }

+ 2 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/feign/MeterWebSocketClientImpl.java

@@ -3,6 +3,7 @@ package org.springblade.meter.feign;
 import lombok.AllArgsConstructor;
 import org.springblade.meter.service.ITaskRepealMessageService;
 import org.springblade.websocket.vo.UserInfoVO;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.web.bind.annotation.RestController;
 
 
@@ -12,6 +13,7 @@ public class MeterWebSocketClientImpl implements MeterWebSocketClient {
 
     private final ITaskRepealMessageService repealMessageService;
     @Override
+    @Async
     public void pushMsg(UserInfoVO vo) {
         //推送废除通知
         repealMessageService.pushUnreadMessage(vo);

+ 2 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/mapper/ContractInventoryFormMapper.java

@@ -71,4 +71,6 @@ public interface ContractInventoryFormMapper extends BaseMapper<ContractInventor
     List<FormNodeSortVO> getAllForm(@Param("contractId") Long contractId);
 
     List<FormTreeVO2> getAllForm2(@Param("contractId") Long contractId,@Param("materialId") Long materialId);
+
+    List<ContractFromVO> getChildNodeResolveForm(@Param("contractId") Long contractId,@Param("meterId") Long meterId);
 }

+ 20 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/mapper/ContractInventoryFormMapper.xml

@@ -180,5 +180,25 @@
         from s_contract_inventory_form scif where contract_id = #{contractId} and is_deleted = 0
         order by -sort desc,create_time
     </select>
+    <select id="getChildNodeResolveForm" resultType="org.springblade.meter.vo.ContractFromVO">
+        select ifm.id, ifm.contract_form_id ,cif.form_number,cif.form_name,cif.current_price,cif.contract_total,cif.change_total,cif.is_supplement,ifm.up_pay_ratio as upPayRatio,
+               ifm.build_picture_total,ifm.change_build_picture_total,ifm.build_picture_money,ifm.change_build_picture_money,
+
+               if(ifm.build_picture_total=ifm.change_build_picture_total,if((select count(1) from s_inventory_form_apply
+                                                                             where contract_id = #{contractId} and is_deleted = 0 and contract_form_id = ifm.contract_form_id and contract_meter_id = ifm.contract_meter_id)=0,
+                                                                            if((select count(1) from s_change_token_inventory
+                                                                                where contract_id = #{contractId} and is_deleted = 0 and contract_form_id = ifm.contract_form_id and contract_meter_id = ifm.contract_meter_id)=0,0,1)
+                   ,1),1) as citeStatus,
+
+               IFNULL((SELECT SUM(change_build_picture_total) from s_inventory_form_meter WHERE contract_id = #{contractId} and contract_form_id = cif.id
+                                                                                            and is_deleted = 0 and contract_meter_id and contract_meter_id != #{meterId}),0)  as otherPoseNum,
+               IFNULL((SELECT SUM(change_build_picture_total) from s_inventory_form_meter
+                       WHERE contract_id = #{contractId} and is_deleted = 0 and contract_form_id = cif.id),0)  as poseNum
+        from s_inventory_form_meter ifm left join s_contract_inventory_form cif on ifm.contract_form_id = cif.id
+        WHERE ifm.contract_id = #{contractId} and ifm.is_deleted = 0
+          and ifm.contract_meter_id in (
+              select id from s_meter_tree_contract where contract_id = #{contractId} and is_deleted = 0 and FIND_IN_SET(#{meterId},ancestor) > 0
+            )
+    </select>
 
 </mapper>

+ 3 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/mapper/ContractMeterPeriodMapper.java

@@ -48,4 +48,7 @@ public interface ContractMeterPeriodMapper extends BaseMapper<ContractMeterPerio
     String getContractNumber(@Param("contractId") Long contractId);
 
     PeriodVO getById(@Param("id") String formDataId);
+
+    //获取第一期合同计量期
+    Long getFirst(@Param("contractId") Long contractId);
 }

+ 7 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/mapper/ContractMeterPeriodMapper.xml

@@ -58,6 +58,13 @@
     <select id="getById" resultType="org.springblade.meter.vo.PeriodVO">
         select id ,project_id,contract_id,sort from s_contract_meter_period where id = #{id}
     </select>
+    <select id="getFirst" resultType="java.lang.Long">
+        select id
+        from s_contract_meter_period
+        WHERE contract_id = #{contractId} and is_deleted = 0
+        ORDER BY start_date
+        limit 1
+    </select>
 
 
 </mapper>

+ 7 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/mapper/MeterPeriodMapper.xml

@@ -103,6 +103,13 @@
             where  project_id = #{period.projectId} and contract_id = #{period.contractId}
             and type = #{period.type} and approve_status = 2 and sort &lt; #{period.sort})
         </if>
+        <if test="period.type == 3">
+            select sum(meter_money) from s_start_pay_meter_form
+            where is_deleted = 0  and meter_period_id in
+            (select id from s_meter_period
+            where  project_id = #{period.projectId} and contract_id = #{period.contractId}
+            and type = 2 and approve_status = 2)
+        </if>
     </select>
 
 

+ 3 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/service/IContractInventoryFormService.java

@@ -65,4 +65,7 @@ public interface IContractInventoryFormService extends BaseService<ContractInven
 
     //材料调差-获取允许调差清单树,并且回显已经选择的
     GetAdjustFormTreeVO getAdjustFormTree(Long contractId, Long materialId);
+
+    //获取节点下分解的清单
+    List<ContractFromVO> getChildNodeResolveForm(Long contractId, Long id);
 }

+ 9 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/service/impl/ContractInventoryFormServiceImpl.java

@@ -724,6 +724,15 @@ public class ContractInventoryFormServiceImpl extends BaseServiceImpl<ContractIn
         return vo;
     }
 
+    @Override
+    public List<ContractFromVO> getChildNodeResolveForm(Long contractId, Long id) {
+        List<ContractFromVO> vos = baseMapper.getChildNodeResolveForm(contractId, id);
+        for (ContractFromVO vo : vos) {
+            vo.setResidueNum(vo.getChangeTotal().subtract(vo.getPoseNum()));
+        }
+        return vos;
+    }
+
     /**
      * 判断当前清单是否已经分解或变更过,变更过返回true
      */

+ 2 - 1
blade-service/blade-meter/src/main/java/org/springblade/meter/service/impl/TaskRepealMessageServiceImpl.java

@@ -21,6 +21,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.AllArgsConstructor;
 import org.apache.commons.lang.StringUtils;
+import org.springblade.common.constant.WebsocketMsgConstant;
 import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.mp.base.BaseServiceImpl;
 import org.springblade.core.secure.utils.AuthUtil;
@@ -113,7 +114,7 @@ public class TaskRepealMessageServiceImpl extends BaseServiceImpl<TaskRepealMess
                 //1为未读,2为已读
                 .eq(TaskRepealMessage::getStatus, 1));
         MsgVO<Integer> msgVO = new MsgVO<>();
-        msgVO.setType("msgRemind");
+        msgVO.setType(WebsocketMsgConstant.MSG_REMIND);
         msgVO.setData(Math.toIntExact(count));
         String msg = JsonUtil.toJson(R.data(msgVO));
         vo.setMsg(msg);

+ 15 - 0
blade-service/blade-websocket/pom.xml

@@ -25,6 +25,21 @@
             <artifactId>blade-meter-api</artifactId>
             <version>${bladex.project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-archive-api</artifactId>
+            <version>${bladex.project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-manager-api</artifactId>
+            <version>${bladex.project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-business-api</artifactId>
+            <version>${bladex.project.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.springblade</groupId>
             <artifactId>blade-core-boot</artifactId>

+ 42 - 0
blade-service/blade-websocket/src/main/java/org/springblade/websocket/config/TaskPoolConfig.java

@@ -0,0 +1,42 @@
+package org.springblade.websocket.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.Executor;
+
+/**
+ * 线程池参数配置
+ **/
+@EnableAsync
+@Configuration
+public class TaskPoolConfig {
+
+    /**
+     * 自定义线程池
+     **/
+    @Bean("WebsocketExecutor")
+    public Executor taskExecutor() {
+        //返回可用处理器的Java虚拟机的数量 12
+        int i = Runtime.getRuntime().availableProcessors();
+        System.out.println("系统最大线程数  : " + i);
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        //核心线程池大小
+        executor.setCorePoolSize(5);
+        //最大线程数
+        executor.setMaxPoolSize(10);
+        //配置队列容量,默认值为Integer.MAX_VALUE
+        executor.setQueueCapacity(20);
+        // 设置线程活跃时间(当超过了核心线程出的核心线程的存活时间,并且没有任务)
+        executor.setKeepAliveSeconds(60);
+        //线程名字前缀
+        executor.setThreadNamePrefix("websocketExecutor -");
+        //设置此执行程序应该在关闭时阻止的最大秒数,以便在容器的其余部分继续关闭之前等待剩余的任务完成他们的执行
+//        executor.setAwaitTerminationSeconds(60);
+        //等待所有的任务结束后再关闭线程池
+//        executor.setWaitForTasksToCompleteOnShutdown(true);
+        return executor;
+    }
+}

+ 6 - 0
blade-service/blade-websocket/src/main/java/org/springblade/websocket/feign/WebSocketClientImpl.java

@@ -2,6 +2,7 @@ package org.springblade.websocket.feign;
 
 import lombok.AllArgsConstructor;
 import org.springblade.websocket.service.WebSocketService;
+import org.springblade.websocket.vo.SystMsgVO;
 import org.springblade.websocket.vo.UserInfoVO;
 import org.springframework.web.bind.annotation.RestController;
 
@@ -19,4 +20,9 @@ public class WebSocketClientImpl implements WebSocketClient{
     public void sendMsg(UserInfoVO vo) {
         socketService.sendMessage(vo);
     }
+
+    @Override
+    public void sendSystemMsg(SystMsgVO vo) {
+        socketService.sendSystemMsg(vo);
+    }
 }

+ 192 - 38
blade-service/blade-websocket/src/main/java/org/springblade/websocket/service/WebSocketService.java

@@ -1,72 +1,114 @@
 package org.springblade.websocket.service;
 
+import io.undertow.websockets.jsr.UndertowSession;
 import lombok.Data;
-import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springblade.business.feign.BusinessWebSocketClient;
 import org.springblade.common.constant.ClientIdConstant;
+import org.springblade.common.constant.WebsocketMsgConstant;
 import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.jackson.JsonUtil;
-import org.springblade.core.tool.utils.SpringUtil;
+import org.springblade.feign.ArchiveWebSocketClient;
+import org.springblade.manager.feign.ManagerWebSocketClient;
 import org.springblade.meter.feign.MeterWebSocketClient;
 import org.springblade.websocket.entity.WebSocketClientInfo;
 import org.springblade.websocket.vo.MsgVO;
+import org.springblade.websocket.vo.SystMsgVO;
 import org.springblade.websocket.vo.UserInfoVO;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
 import org.springframework.stereotype.Component;
-
 import javax.websocket.*;
 import javax.websocket.server.PathParam;
 import javax.websocket.server.ServerEndpoint;
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.*;
+import java.util.concurrent.*;
 import java.util.concurrent.locks.ReentrantLock;
 
 @ServerEndpoint(value = "/websocket/{system}/{projectId}/{contractId}/{userId}")
 @Component
 @Data
-public class WebSocketService {
+public class WebSocketService implements ApplicationContextAware {
+
+    @Autowired
+    @Qualifier("WebsocketExecutor")
+    private Executor WebsocketExecutor;
 
-    private static MeterWebSocketClient meterWebSocketClient = null;
+    /** 计量*/
+    private static MeterWebSocketClient meterWebSocketClient;
+    /** 质检*/
+    private static BusinessWebSocketClient businessWebSocketClient;
+    /** 档案*/
+    private static ArchiveWebSocketClient archiveWebSocketClient;
+    /** 后台*/
+    private static ManagerWebSocketClient managerWebSocketClient;
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        WebSocketService.meterWebSocketClient = applicationContext.getBean(MeterWebSocketClient.class);
+        WebSocketService.businessWebSocketClient = applicationContext.getBean(BusinessWebSocketClient.class);
+        WebSocketService.archiveWebSocketClient = applicationContext.getBean(ArchiveWebSocketClient.class);
+        WebSocketService.managerWebSocketClient = applicationContext.getBean(ManagerWebSocketClient.class);
+    }
 
     private static final Logger log = LoggerFactory.getLogger(WebSocketService.class);
 
     /**静态变量,用来记录当前在线用户数。应该把它设计成线程安全的。*/
     private static int onlineUserCount = 0;
+
     /**静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。*/
     private static int onlineLinkCount = 0;
+
     /**concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象*/
     private static ConcurrentHashMap<Long, Map<String, WebSocketClientInfo>> webSocketMap = new ConcurrentHashMap<>();
+
     /**concurrent包的线程安全Set,用来存放每个用户所在合同对应的session对象*/
-    private static ConcurrentHashMap<UserInfoVO, List<Session>> userInfoMap = new ConcurrentHashMap<>();
+    private static ConcurrentHashMap<UserInfoVO, CopyOnWriteArrayList<Session>> userInfoMap = new ConcurrentHashMap<>();
+
+    /** 计量系统session集合*/
+    private static Set<Session> measureSystemSessions = new CopyOnWriteArraySet<>();
+    /** 质检系统session集合*/
+    private static Set<Session> clientSystemSessions = new CopyOnWriteArraySet<>();
+    /** 档案系统session集合*/
+    private static Set<Session> archivesSystemSessions = new CopyOnWriteArraySet<>();
+
+//    /** 更新公告推送记录*/
+//    private static Set<UserSingleVO> updateMsgPushUsers = new HashSet<>();
+//    /** 普通公告推送记录*/
+//    private static Set<UserSingleVO> systemMsgPushUsers = new HashSet<>();
 
     /**锁的映射表*/
     private static final ConcurrentHashMap<Long, ReentrantLock> locks = new ConcurrentHashMap<>();
 
     /**与某个客户端的连接会话,需要通过它来给客户端发送数据*/
     private Session session;
-    /**接收userId*/
+    /**用户id*/
     private Long userId;
+    /**用户ip*/
+    private String userIp;
+    /**系统名称*/
+    private String system;
     /**用户系统项目合同信息*/
     private UserInfoVO vo;
 
-
     /**
      * 连接建立成功调用的方法
      */
     @OnOpen
     public void onOpen(Session session, @PathParam("system") String system, @PathParam("projectId") Long projectId,
                        @PathParam("contractId") Long contractId,@PathParam("userId") Long userId) {
-        if (meterWebSocketClient == null){
-            meterWebSocketClient = SpringUtil.getBean(MeterWebSocketClient.class);
-        }
         ReentrantLock lock = getLock(userId);
         lock.lock();
         this.session = session;
+        UndertowSession undertowSession = (UndertowSession) session;
+        this.userIp = undertowSession.getWebSocketChannel().getSourceAddress().getAddress().getHostAddress();
         this.userId= userId;
+        this.system = system;
         //用户的连接信息
         WebSocketClientInfo client = new WebSocketClientInfo();
         client.setSession(session);
@@ -83,25 +125,39 @@ public class WebSocketService {
         userMap.put(session.getId(),client);
         webSocketMap.put(userId, userMap);
         addOnlineLinkCount();
-        log.info("--------------------------------建立连接-----------------------------------------");
+        log.info("----------------------建立连接-------------------------------");
         log.info("用户连接:"+userId+",当前用户总连接数:"+userMap.size());
         log.info("当前在线人数为:" + getOnlineUserCount()+",当前总连接数:"+getOnlineLinkCount());
         try {
             sendMessage(JsonUtil.toJson(R.data(new MsgVO("msgLink","来自后台的反馈:连接成功"))));
             this.vo = new UserInfoVO(system,projectId,contractId,userId);
-//            int randomNumber = (int)(Math.random() * 11);
-//            Thread.sleep(randomNumber);
-            List<Session> sessions = userInfoMap.get(vo);
+            CopyOnWriteArrayList<Session> sessions = userInfoMap.get(vo);
             if (sessions == null){
-                sessions = new ArrayList<>();
+                sessions = new CopyOnWriteArrayList<>();
             }
             sessions.add(session);
             userInfoMap.put(vo,sessions);
+            /** 获取倒计时,如果当前有倒计时则推送*/
+            this.vo.setMsgType("3");
+            try {
+                managerWebSocketClient.pushMsg(vo);
+            }catch (Exception e){
+                log.info("用户:"+userId+",网络异常:"+e.getMessage());
+            }
             /** 向指定系统发送通知,如果当前用户有需要推送的消息则推送 */
             switch (system) {
                 case ClientIdConstant.METER_ID:
+                    measureSystemSessions.add(session);
                     meterWebSocketClient.pushMsg(vo);
                     break;
+                case ClientIdConstant.ARCHIVE_ID:
+                    archivesSystemSessions.add(session);
+                    break;
+                case ClientIdConstant.CLIENT_ID:
+                    clientSystemSessions.add(session);
+                    break;
+                default:
+                    log.error("未知的系统登录:"+system);
             }
         } catch (Exception e) {
             log.error("用户:"+userId+",网络异常:"+e.getMessage());
@@ -115,18 +171,27 @@ public class WebSocketService {
      */
     @OnClose
     public void onClose() {
-        //同一个userId,只能有一个线程操作
-//        try {
-//            Thread.sleep(10);
-//        } catch (InterruptedException e) {
-//            throw new RuntimeException(e);
-//        }
+        //同一个userId,只能有一个线程同时操作
         ReentrantLock lock = getLock(userId);
         lock.lock();
         try {
+            //先删除系统中存储的session
+            switch (system) {
+                case ClientIdConstant.METER_ID:
+                    measureSystemSessions.remove(session);
+                    break;
+                case ClientIdConstant.CLIENT_ID:
+                    clientSystemSessions.remove(session);
+                    break;
+                case ClientIdConstant.ARCHIVE_ID:
+                    archivesSystemSessions.remove(session);
+                    break;
+                default:
+                    log.error("未知的系统退出:"+system);
+            }
             Map<String, WebSocketClientInfo> userMap = webSocketMap.get(userId);
             if (userMap != null && userMap.size() > 0) {
-                log.info("--------------------------------断开连接---------------------------------------");
+                log.info("----------------------断开连接-----------------------------");
                 List<Session> sessions = userInfoMap.get(vo);
                 if (sessions != null && sessions.size() > 0){
                     sessions.remove(session);
@@ -157,10 +222,15 @@ public class WebSocketService {
     @OnMessage
     public void onMessage(String message, Session session) {
         log.info("收到用户消息:"+userId+",报文:"+message);
-        //可以群发消息
         //消息保存到数据库、redis
-        if(StringUtils.isNotBlank(message)){
-
+        if(WebsocketMsgConstant.GET_MSG.equals(message)){
+            /** 向系统公告发送通知,如果当前有公告则推送*/
+            try {
+                this.vo.setMsgType("12");
+                managerWebSocketClient.pushMsg(vo);
+            }catch (Exception e){
+                log.info("用户:"+userId+",网络异常:"+e.getMessage());
+            }
         }
     }
 
@@ -183,21 +253,29 @@ public class WebSocketService {
         }
     }
 
+    /**
+     *  推送指定的系统的所有在线用户
+     */
+    public void sendMessage(String msg,String system) throws Exception {
+        synchronized (session){
+            this.session.getBasicRemote().sendText(msg);
+        }
+    }
+
     /**
      * 向指定客户端推送指定用户消息
      */
     public void sendMessage(UserInfoVO vo2){
             List<Session> sessions = userInfoMap.get(vo2);
             if(sessions != null && sessions.size() > 0){
-                /** 此处不能使用迭代器,否则在推送消息时,当前用户又开启一个页面,集合发生变化迭代器会报错ConcurrentModificationException*/
-                /** 如果数组越界,则复制一份出来循环发送*/
-                for (int i = 0; i < sessions.size(); i++) {
-                    Session s = sessions.get(i);
+                /** 此处不能使用普通集合,否则在推送消息时,当前用户又开启一个页面,集合发生变化迭代器会报错ConcurrentModificationException*/
+                for (Session s : sessions) {
                     if (s == null){
                         continue;
                     }
                     RemoteEndpoint.Basic basicRemote = s.getBasicRemote();
-                    /** 推送消息时可能因为nginx配置的连接时间导致通道关闭,此时跳过推送给这个窗口*/
+                    /** 推送消息时可能因为nginx配置的连接时间,或者用户刚好断开连接,
+                     * 导致通道关闭,但是数组中使用的是快照,还存在这个连接,此时跳过推送给这个窗口*/
                     if (basicRemote != null){
                         try {
                             basicRemote.sendText(vo2.getMsg());
@@ -209,6 +287,84 @@ public class WebSocketService {
             }
     }
 
+    /**
+     * 推送系统公告
+     * @param vo
+     */
+    public void sendSystemMsg(SystMsgVO vo) {
+        log.info("------------------公告推送开始-------------------------");
+        Integer meterTotal = measureSystemSessions.size();
+        Integer clientTotal = clientSystemSessions.size();
+        Integer archivesTotal = archivesSystemSessions.size();
+        String pushSystem = vo.getPushSystem();
+        Integer msgType = vo.getMsgType();
+//        if (msgType == 1){
+//            updateMsgPushUsers.clear();
+//        }else {
+//            systemMsgPushUsers.clear();
+//        }
+        //处理消息类型
+        String msgTypeValue;
+        if (msgType == 1){
+            msgTypeValue = WebsocketMsgConstant.MSG_UPDATE_MSG;
+        }else if (msgType == 2){
+            msgTypeValue = WebsocketMsgConstant.MSG_SYSTEM_MSG;
+        }else {
+            msgTypeValue = WebsocketMsgConstant.MSG_COUNT_DOWN;
+        }
+        //提前转换消息格式
+        String msg = JsonUtil.toJson(R.data(new MsgVO(msgTypeValue,vo.getMsgContent())));
+        //异步推送各个系统,最后汇总统计
+        CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(
+                () -> sendAssignSystemMsg(pushSystem.contains(ClientIdConstant.METER_ID) ? measureSystemSessions : new HashSet<>(),msg), WebsocketExecutor);
+        CompletableFuture<Integer> cf2 = CompletableFuture.supplyAsync(
+                () -> sendAssignSystemMsg(pushSystem.contains(ClientIdConstant.CLIENT_ID) ? clientSystemSessions : new HashSet<>(),msg), WebsocketExecutor);
+        CompletableFuture<Integer> cf3 = CompletableFuture.supplyAsync(
+                () -> sendAssignSystemMsg(pushSystem.contains(ClientIdConstant.ARCHIVE_ID) ? archivesSystemSessions : new HashSet<>(),msg), WebsocketExecutor);
+
+        try {
+            CompletableFuture.allOf(cf1, cf2,cf3).get(10, TimeUnit.SECONDS);
+            String pushInfo = "推送系统{"+pushSystem+"}";
+            String pushResult = "推送结果"+"{计量在线"+meterTotal+"推送"+cf1.get()+",质检在线"+clientTotal+"推送"+cf2.get()+",档案在线"+archivesTotal+"推送"+cf3.get()+"}";
+            log.info(pushInfo);
+            log.info(pushResult);
+            log.info("------------------公告推送结束-------------------------");
+        } catch (TimeoutException e) {
+            log.error("推送公告超时,原因:"+e.getMessage());
+        } catch (Exception e){
+            log.error("推送公告报错,原因:"+e.getMessage());
+        }
+    }
+
+    /**
+     * 单个系统推送方法
+     */
+    public Integer sendAssignSystemMsg(Set<Session> sessions,String msg){
+        Integer total = 0;
+        if (sessions.size() > 0){
+            for (Session s : sessions) {
+                if (s == null){
+                    continue;
+                }
+                RemoteEndpoint.Basic basicRemote = s.getBasicRemote();
+                /** 推送消息时可能因为nginx配置的连接时间,或者用户刚好断开连接,
+                 * 导致通道关闭,但是数组中使用的是快照,还存在这个连接,此时跳过推送给这个窗口*/
+                if (basicRemote != null){
+                    try {
+                        basicRemote.sendText(msg);
+                        total++;
+                    } catch (IOException e) {
+                        log.error("推送公告失败,原因:"+e.getMessage());
+                    }
+                }
+            }
+        }
+        return total;
+    }
+
+
+
+
     /**
      *      获取锁的方法,如果锁不存在,则创建一个新的锁
       */
@@ -245,6 +401,4 @@ public class WebSocketService {
         WebSocketService.onlineLinkCount--;
     }
 
-
-
 }