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

Merge remote-tracking branch 'origin/master'

liuyc 2 лет назад
Родитель
Сommit
2cf2a6945e
15 измененных файлов с 400 добавлено и 181 удалено
  1. 7 2
      blade-common/src/main/java/org/springblade/common/constant/OssConstant.java
  2. 13 1
      blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/feign/NewIOSSClient.java
  3. 19 2
      blade-ops/blade-resource/src/main/java/org/springblade/resource/builder/ossre/AliossTemplateRe.java
  4. 1 1
      blade-ops/blade-resource/src/main/java/org/springblade/resource/builder/ossre/OssTemplateRe.java
  5. 2 2
      blade-ops/blade-resource/src/main/java/org/springblade/resource/feign/NewIOSSClientImpl.java
  6. 7 3
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/dto/FormData.java
  7. 2 2
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/IArchiveAutoPdfService.java
  8. 24 19
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveAutoPdfServiceImpl.java
  9. 24 24
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchivesAutoServiceImpl.java
  10. 91 0
      blade-service/blade-manager/src/main/java/com/mixsmart/utils/AhoCorasickFilter.java
  11. 1 1
      blade-service/blade-manager/src/main/java/com/mixsmart/utils/CustomFunction.java
  12. 60 2
      blade-service/blade-manager/src/main/java/com/mixsmart/utils/FormulaUtils.java
  13. 3 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ArchiveTreeController.java
  14. 22 16
      blade-service/blade-manager/src/main/java/org/springblade/manager/formula/impl/TableElementConverter.java
  15. 124 106
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/FormulaServiceImpl.java

+ 7 - 2
blade-common/src/main/java/org/springblade/common/constant/OssConstant.java

@@ -5,11 +5,16 @@ public interface OssConstant {
     /**
      * 临时目录路径
      */
-    String TEMP_DIRECTORY = "/showtmp";
+    String TEMP_DIRECTORY = "showtmp";
     /**
      * 归档目录路径
      */
-    String ARCHIVE_DIRECTORY = "/archive";
+    String ARCHIVE_DIRECTORY = "archive";
+
+    /**
+     * 归档目录路径
+     */
+    String NORMAL_DIRECTORY = "upload";
 
     /**
      * 分隔符

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

@@ -27,8 +27,20 @@ public interface NewIOSSClient {
     @PostMapping(UPLOAD_FILE_INFO)
     BladeFile uploadFile(@RequestParam String fileName, @RequestParam String localFileUrl);
 
+    /**
+     *  规则  projectId/filePath/fileName,
+     *  如果projectId为空则为filePath/fileName
+     *  如果filePath为空,则为 upload/20230202/fileName
+     *  如果filePath为OssConstant.TEMP_DIRECTORY,一律放进临时目录 OssConstant.TEMP_DIRECTORY/fileName
+     * @param fileName
+     * @param localFileUrl
+     * @param filePath
+     * @param projectId
+     * @return
+     */
     @PostMapping(UPLOAD_FILE_INFO_WITH_PATH)
-    BladeFile uploadFile(@RequestParam String fileName, @RequestParam  String filePath, @RequestParam  String localFileUrl);
+    BladeFile uploadFile(@RequestParam String fileName, @RequestParam  String localFileUrl,
+                         @RequestParam(required=false)  String filePath,@RequestParam(required=false) Long projectId);
 
     @PostMapping(UPLOAD_FILE_INFO_BYTE)
     BladeFile updateFile(@RequestBody byte[] fileByte, @RequestParam String fileName);

+ 19 - 2
blade-ops/blade-resource/src/main/java/org/springblade/resource/builder/ossre/AliossTemplateRe.java

@@ -7,16 +7,19 @@ import com.aliyun.oss.model.*;
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
+import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
 import lombok.SneakyThrows;
+import org.springblade.common.constant.OssConstant;
 import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.oss.model.OssFile;
 import org.springblade.core.oss.props.OssProperties;
 import org.springblade.core.oss.rule.OssRule;
+import org.springblade.core.secure.utils.AuthUtil;
 import org.springblade.core.tool.jackson.JsonUtil;
 import org.springframework.util.StringUtils;
 import org.springframework.web.multipart.MultipartFile;
@@ -307,7 +310,7 @@ public class AliossTemplateRe implements OssTemplateRe {
         return initResult;
     }
 
-    public BladeFile putFileWithPath(String fileName, String filePath,InputStream stream) {
+    public BladeFile putFileWithPath(String fileName, String filePath,Long projectId, InputStream stream) {
         try {
 
             String suffix = "";
@@ -316,7 +319,6 @@ public class AliossTemplateRe implements OssTemplateRe {
                 suffix = fileName.substring(indexOfDot + 1);
             }
 
-
             String ossUrl = "";
             // 判断容器是否存在,不存在就创建
             String bucket=getBucketName();
@@ -327,6 +329,21 @@ public class AliossTemplateRe implements OssTemplateRe {
                 ossClient.createBucket(createBucketRequest);
             }
             // 设置文件路径和名称
+            //判断是否为存储成   upload/20230322/xxxx.pdf 还是指定目录 aaaa/bbbb.pdf
+            if (StringUtils.isEmpty(filePath)) {
+                Date now = new Date();
+                SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+                String formattedDate = sdf.format(now);
+                filePath = OssConstant.NORMAL_DIRECTORY + "/" + formattedDate;
+            }
+
+            //如果有项目ID,则存为 项目id/....  ,否则直接在最外层, 临时目录除外
+            if (!filePath.equals(OssConstant.TEMP_DIRECTORY)) {
+                if (projectId != null  ) {
+                    filePath = projectId + "/" + filePath;
+                }
+            }
+
             String fileUrl = filePath + "/" + fileName;
             ObjectMetadata objectMetadata = new ObjectMetadata();
             objectMetadata.setContentType(getcontentType(suffix));

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

@@ -19,5 +19,5 @@ public interface OssTemplateRe extends OssTemplate {
     InitiateMultipartUploadResult initiateMultipartUpload(InitiateMultipartUploadRequest request);
 
     //指定路径上传
-    BladeFile putFileWithPath(String fileName, String filePath,InputStream stream);
+    BladeFile putFileWithPath(String fileName, String filePath,Long projectId, InputStream stream);
 }

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

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

+ 7 - 3
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/dto/FormData.java

@@ -3,12 +3,9 @@ package org.springblade.manager.dto;
 
 
 import lombok.Data;
-import org.apache.commons.lang.StringUtils;
 import org.springblade.core.tool.utils.Func;
 import org.springblade.core.tool.utils.StringPool;
 import org.springblade.manager.entity.Formula;
-
-
 import java.util.*;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -85,6 +82,13 @@ public class FormData {
     public String info(){
         return getCode()+getEName()+(getFormula()==null?StringPool.EMPTY:getFormula().getFormula());
     }
+    /**去掉特殊符合无效词汇后的元素名称,用于匹配*/
+    public String getSimplifyName(){
+        if(eName!=null){
+            return eName.replaceAll("[::()()、\\s]","");
+        }
+        return "";
+    }
     public FormData() {
     }
     public FormData(String code, List<ElementData> values, Formula formula,String coords) {

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

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

+ 24 - 19
blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveAutoPdfServiceImpl.java

@@ -25,6 +25,7 @@ import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.common.vo.DataVO;
 import org.springblade.common.vo.FileSize;
 import org.springblade.core.oss.model.BladeFile;
+import org.springblade.core.secure.utils.AuthUtil;
 import org.springblade.core.tool.utils.ObjectUtil;
 import org.springblade.core.tool.utils.ResourceUtil;
 import org.springblade.core.tool.utils.StringUtil;
@@ -93,7 +94,7 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
         String key1 =  "2__"+ dataVO1.getY() + "_" + dataVO1.getX();
         DataInfo.put(key1,"hahahahaa");
         try {
-            String url = getBussPdfInfo(pkeyId.toString(),DataInfo,excelUrl,file_path);
+            String url = getBussPdfInfo(pkeyId.toString(),DataInfo,excelUrl,file_path,null,null);
         } catch (Exception e) {
             e.printStackTrace();
         }
@@ -312,11 +313,11 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
         if (multiLineconfig != null) {
             String coords = multiLineconfig.getCoords();
             String formula = multiLineconfig.getFormula();
-            handleArchiveFile(coords, formula, variables, file_path, excelUrl, dataInfo,urls,fileName);
+            handleArchiveFile(coords, formula, variables, file_path, excelUrl, dataInfo,urls,fileName, archivesAuto.getProjectId());
 
         }else {
             try {
-                String url = getBussPdfInfo(fileName, dataInfo, excelUrl, file_path);
+                String url = getBussPdfInfo(fileName, dataInfo, excelUrl, file_path,OssConstant.ARCHIVE_DIRECTORY,archivesAuto.getProjectId());
                 urls.add(url);
             } catch (Exception e) {
                 e.printStackTrace();
@@ -337,7 +338,7 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
      */
     private void handleArchiveFile(String coords, String formula,
                                    Map<String,Object> variables,String file_path,
-                                   String excelUrl, Map<String, Object> dataInfo,List<String> urls,String fileName){
+                                   String excelUrl, Map<String, Object> dataInfo,List<String> urls,String fileName,Long projectId){
         //todo  目录多页合并一页,文件名带上
 
 
@@ -380,7 +381,7 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
                         subIndex++;
                     }
                     try {
-                        String url = getBussPdfInfo(fileName + subIndex, pageMap, excelUrl, file_path);
+                        String url = getBussPdfInfo(fileName + subIndex, pageMap, excelUrl, file_path,OssConstant.ARCHIVE_DIRECTORY,projectId);
                         localUrls.add(url);
                     } catch (Exception e) {
                         e.printStackTrace();
@@ -398,11 +399,11 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
         //合并成一个
         if (localUrls.size() > 1) {
             Long id = SnowFlakeUtil.getId();
-            String trialPdf = file_path + "/pdf/" + id + ".pdf";
+            String localPdf = file_path + "/pdf/" + id + ".pdf";
 
             //合并当前所有选择的试验pdf
-            FileUtils.mergePdfPublicMethods(localUrls, trialPdf);
-            BladeFile bladeFile = this.newIOSSClient.uploadFile(fileName + ".pdf", trialPdf);
+            FileUtils.mergePdfPublicMethods(localUrls, localPdf);
+            BladeFile bladeFile = this.newIOSSClient.uploadFile(fileName + ".pdf", localPdf, OssConstant.ARCHIVE_DIRECTORY,projectId);
 
 
 //            ByteArrayOutputStream bos = new ByteArrayOutputStream();
@@ -455,19 +456,23 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
      * @param fileName   文件名
      * @param DataInfo  excel和数据
      * @param excelUrl  excel模板
-     * @param filePath  本地路径
+     * @param localPath  本地路径
+     * @param ossPath  oss上的路径
+     * @param projectId 项目ID
      * @return
      * @throws Exception
      */
-    public String getBussPdfInfo(String fileName,Map<String, Object> DataInfo,String excelUrl,String filePath) throws Exception{
+    public String getBussPdfInfo(String fileName,Map<String, Object> DataInfo,String excelUrl,String localPath,
+         String ossPath, Long projectId) throws Exception{
 
         if (fileName == null) {
             fileName = SnowFlakeUtil.getId().toString();
         }
 
-        String pdfPath = filePath + "/pdf//" + fileName + ".pdf";
-        String excelPath = filePath + "/pdf//" + fileName + ".xlsx";
-        File tabPdf = ResourceUtil.getFile(pdfPath);
+        //本地文件路径
+        String localPdfPath = localPath + "/pdf//" + fileName + ".pdf";
+        String excelPath = localPath + "/pdf//" + fileName + ".xlsx";
+        File tabPdf = ResourceUtil.getFile(localPdfPath);
         if (tabPdf.exists()) {
             tabPdf.delete();
         }
@@ -549,8 +554,8 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
 
         FileOutputStream outputStream = new FileOutputStream(excelPath);
         workbook.write(outputStream);
-        FileUtils.setExcelScaleToPdf(excelPath, pdfPath);
-        BladeFile bladeFile = newIOSSClient.uploadFile(fileName + ".pdf", OssConstant.TEMP_DIRECTORY, pdfPath);
+        FileUtils.setExcelScaleToPdf(excelPath, localPdfPath);
+        BladeFile bladeFile = newIOSSClient.uploadFile(fileName + ".pdf", localPdfPath,ossPath, projectId);
 
         String pdfLink = "";
         if (bladeFile!= null ){
@@ -743,14 +748,14 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
      * @param fileName
      * @return
      */
-    public String MergePdfAndUpload(List<String> urlList,String fileName,String filePath) {
+    public String MergePdfAndUpload(List<String> urlList,String fileName,String filePath,Long pojectId) {
        String url = "";
        Long id = SnowFlakeUtil.getId();
-       String trialPdf = FileUtils.LocalPath + "/pdf/" + id + ".pdf";
+       String localPdf = FileUtils.LocalPath + "/pdf/" + id + ".pdf";
 
        try {
             //合并pdf
-            FileUtils.mergePdfPublicMethods(urlList,trialPdf);
+            FileUtils.mergePdfPublicMethods(urlList,localPdf);
 
             if (StringUtils.isEmpty(filePath)) {
                 filePath = OssConstant.TEMP_DIRECTORY;
@@ -759,7 +764,7 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
             fileName += (OssConstant.SEPARATOR + id);
 
             //上传到oss
-            BladeFile file  = newIOSSClient.uploadFile(fileName+ ".pdf", filePath,trialPdf);
+            BladeFile file  = newIOSSClient.uploadFile(fileName+ ".pdf", localPdf,filePath,pojectId);
             url = file.getLink();
         } catch (Exception e) {
             e.printStackTrace();

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

@@ -75,7 +75,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 	private ContractClient contractClient;
 	private ProjectClient projectClient;
 
-	private Map<String,Integer> indexMap; //按立卷位区分和生成流水号
+	private Map<String,Integer> indexMap = new HashMap<>(); //按立卷位区分和生成流水号
 	private IArchiveAutoPdfService archiveAutoPdfService;
 
 
@@ -232,8 +232,8 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 
 	@Override
 	public void archiveAutoMethod(Long projectId){
-		//步骤一:把项目下未锁定的案卷拆卷。
-
+		//步骤一:把档号集合初始化
+		indexMap = new HashMap<>();
 		//步骤二:查询归档树节点。存在未归档文件的节点。
 		List<ArchiveTreeContract> list = archiveTreeContractClient.getHavedFileNodeByProjectID(projectId);
 		//步骤三:遍历归档树节点整理出 默认规则节点,分类并卷节点,单独组卷节点 三个集合。
@@ -257,7 +257,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		//步骤四:按照单独,分类,默认,分盒的顺序执行组卷流程。
 
 		//分盒文件集合
-		Map<Integer,List<ArchiveFile>> boxMap = new HashMap<>();
+		Map<Integer,List<ArchiveFile>> boxMap = new LinkedHashMap<>();
 
 		archiveAutoMethod3(list3,boxMap);//单独组卷
 		archiveAutoMethod2(list2,projectId,boxMap);//分类组卷
@@ -444,7 +444,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		if(isCrossNode){
 			archiveName=projectName;
 			//存在跨节点  项目名称+文件对应的所有节点名称
-			Set<String> nodeIdSet = new HashSet<>();
+			Set<String> nodeIdSet = new LinkedHashSet<>();
 			for(ArchiveFile file:waitArchiveFiles){
 				String nodeId = file.getNodeId();
 				nodeIdSet.add(nodeId);
@@ -466,10 +466,8 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		return archiveName;
 	}
 	private String builtFilePageNo(ArchivesAuto archivesAuto,List<ArchiveFile> waitArchiveFiles){
-		//TODO 生成文件对应的页码,返回url
-
+		//生成文件对应的页码,返回url
 		archiveAutoPdfService.builtFilePageNo(archivesAuto,waitArchiveFiles);
-
 		this.updateById(archivesAuto);
 
 		return "";
@@ -531,8 +529,6 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		for(ArchiveFile file:waitArchiveFiles){
 			pageN=pageN+file.getFilePage();
 		}
-
-
 		//默认组卷存在跨节点组卷  注意案卷归属节点,案卷命名方式
 		//获取案卷题名
 		String archiveName=builtArchiveName(waitArchiveFiles,node,true);//获取案卷题名
@@ -648,14 +644,13 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		for(ArchiveTreeContract node:list){
 			//步骤2:获取当前节点的案卷规格
 			String specificationStr = node.getSpecification();
+			if(StringUtils.isEmpty(specificationStr)){
+				specificationStr="30";
+			}
 			int specification = Integer.parseInt(specificationStr);
 			int specificationSize=specification*10;
 			//步骤3:查询节点下的未组卷文件
-			List<ArchiveFile> archiveFiles = archiveFileClient.listWrappers(Wrappers.<ArchiveFile>lambdaQuery()
-					.eq(ArchiveFile::getNodeId, node)
-					.eq(ArchiveFile::getIsArchive, 0)
-					.eq(ArchiveFile::getIsDeleted,0)
-					.orderByAsc(ArchiveFile::getSort));
+			List<ArchiveFile> archiveFiles = archiveFileClient.getListByNodeID(node.getId().toString(),0);
 			//步骤4:遍历未归档文件
 			//待组卷文件集合
 			List<ArchiveFile> waitArchiveFiles = new ArrayList<>();
@@ -666,7 +661,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 				for(ArchiveFile file:archiveFiles){
 					archiveFilesSize++;
 					//步骤5:判断文件是否存在分盒设置
-					if(file.getBoxNumber()!=null){
+					if(file.getBoxNumber()!=null && file.getBoxNumber()!=-1){
 						//添加到分盒文件集合
 						addBoxMap(file,boxMap);
 						if(archiveFilesSize==archiveFiles.size() && waitArchiveFiles.size()>0){
@@ -704,7 +699,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 							//如果waitArchiveFiles集合size>0,先将集合中文件组卷。再将当前文件放入集合
 							if(waitArchiveFiles.size()>0){
 								//将waitArchiveFiles组卷,
-								createArchive3(waitArchiveFiles,node,archivesSize);
+								createArchive3(waitArchiveFiles,node,archivesSize-filePage);
 								//然后将待组卷文件集合,总页数还原初始值,
 								waitArchiveFiles.clear();
 								//保存当前文件进入待组卷集合,待组卷页数=当前文件页数
@@ -827,22 +822,21 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 			if(waitArchiveFiles.size()==0){
 				//waitArchiveFiles待组卷文件为空时,按当前节点的规格
 				String specificationStr = node.getSpecification();
+				if(StringUtils.isEmpty(specificationStr)){
+					specificationStr="30";
+				}
 				int specification = Integer.parseInt(specificationStr);
 				specificationSize=specification*10;
 			}
 
 			//步骤3.2:查询出当前节点未组卷的文件
-			List<ArchiveFile> archiveFiles = archiveFileClient.listWrappers(Wrappers.<ArchiveFile>lambdaQuery()
-					.eq(ArchiveFile::getNodeId, node)
-					.eq(ArchiveFile::getIsArchive, 0)
-					.eq(ArchiveFile::getIsDeleted,0)
-					.orderByAsc(ArchiveFile::getSort));
+			List<ArchiveFile> archiveFiles = archiveFileClient.getListByNodeID(node.getId().toString(),0);
 			//步骤3.3:遍历未组卷文件
 			int archiveFilesSize=0;
 			for(ArchiveFile file:archiveFiles){
 				archiveFilesSize++;
 				//步骤3.4:判断文件是否存在分盒设置
-				if(file.getBoxNumber()!=null) {
+				if(file.getBoxNumber()!=null && file.getBoxNumber()!=-1) {
 					//添加到分盒文件集合
 					addBoxMap(file,boxMap);
 					if(nodeSize==list.size() && archiveFilesSize==archiveFiles.size()){
@@ -878,6 +872,9 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 						archivesSize=0;
 
 						String specificationStr = node.getSpecification();
+						if(StringUtils.isEmpty(specificationStr)){
+							specificationStr="30";
+						}
 						int specification = Integer.parseInt(specificationStr);
 						specificationSize=specification*10;//更新specificationSize待组卷规格为 当前节点的组卷规格
 					}
@@ -895,6 +892,9 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 							archivesSize=filePage;
 
 							String specificationStr = node.getSpecification();
+							if(StringUtils.isEmpty(specificationStr)){
+								specificationStr="30";
+							}
 							int specification = Integer.parseInt(specificationStr);
 							specificationSize=specification*10;//更新specificationSize待组卷规格为 当前节点的组卷规格
 
@@ -1042,7 +1042,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 				urlList.add(frontUrls[3]);
 			}
 
-			url = archiveAutoPdfService.MergePdfAndUpload(urlList,archivesAuto.getName(),null);
+			url = archiveAutoPdfService.MergePdfAndUpload(urlList,archivesAuto.getName(),null,archivesAuto.getProjectId());
 		}
 		return  url;
 	}

+ 91 - 0
blade-service/blade-manager/src/main/java/com/mixsmart/utils/AhoCorasickFilter.java

@@ -0,0 +1,91 @@
+package com.mixsmart.utils;
+
+import java.util.*;
+/**
+ * @author yangyj
+ * @Date 2023/4/26 10:15
+ * @description 删除无效词汇
+ */
+public class AhoCorasickFilter {
+    private final TrieNode root;
+    private final char replaceChar;
+
+    public AhoCorasickFilter(String[] sensitiveWords, char replaceChar) {
+        this.root = new TrieNode();
+        this.replaceChar = replaceChar;
+        buildTrie(sensitiveWords);
+        buildFailPath();
+    }
+
+    public String filter(String text) {
+        StringBuilder sb = new StringBuilder(text);
+        TrieNode cur = root;
+        for (int i = 0; i < sb.length(); i++) {
+            char ch = sb.charAt(i);
+            while (cur != root && !cur.next.containsKey(ch)) {
+                cur = cur.fail;
+            }
+            if (cur.next.containsKey(ch)) {
+                cur = cur.next.get(ch);
+                if (cur.isEnd) {
+                    for (int j = i - cur.length + 1; j <= i; j++) {
+                        sb.setCharAt(j, replaceChar);
+                    }
+                    cur = root;
+                }
+            }
+        }
+        return sb.toString().replace("*","");
+    }
+
+    private void buildTrie(String[] sensitiveWords) {
+        for (String word : sensitiveWords) {
+            TrieNode cur = root;
+            for (char ch : word.toCharArray()) {
+                if (!cur.next.containsKey(ch)) {
+                    cur.next.put(ch, new TrieNode());
+                }
+                cur = cur.next.get(ch);
+            }
+            cur.isEnd = true;
+            cur.length = word.length();
+        }
+    }
+
+    private void buildFailPath() {
+        Queue<TrieNode> queue = new LinkedList<>();
+        for (TrieNode child : root.next.values()) {
+            queue.offer(child);
+            child.fail = root;
+        }
+        while (!queue.isEmpty()) {
+            TrieNode cur = queue.poll();
+            for (char ch : cur.next.keySet()) {
+                TrieNode next = cur.next.get(ch);
+                queue.offer(next);
+                TrieNode failNode = cur.fail;
+                while (failNode != root && !failNode.next.containsKey(ch)) {
+                    failNode = failNode.fail;
+                }
+                if (failNode.next.containsKey(ch)) {
+                    failNode = failNode.next.get(ch);
+                }
+                next.fail = failNode;
+            }
+        }
+    }
+
+    private static class TrieNode {
+        Map<Character, TrieNode> next;
+        TrieNode fail;
+        boolean isEnd;
+        int length;
+
+        public TrieNode() {
+            this.next = new HashMap<>();
+            this.fail = null;
+            this.isEnd = false;
+            this.length = 0;
+        }
+    }
+}

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

@@ -2059,7 +2059,7 @@ public class CustomFunction {
 			/*外观质量,这种中文描述去重*/
 			if(list.stream().filter(CustomFunction::containsZH).anyMatch(e->e.toString().contains("\n"))){
 				AtomicInteger index= new AtomicInteger(1);
-				result=list.stream().flatMap(e-> Arrays.stream(e.toString().split("\\n+"))).map(String::trim).map(e->e.replaceAll("^\\d+[、.]","")).distinct().map(e->(index.getAndIncrement())+"、"+e+"\n").collect(Collectors.toList());
+				result=list.stream().flatMap(e-> Arrays.stream(e.toString().split("\\n+"))).map(String::trim).map(e->e.replaceAll("^\\d+[、.\\s]*","")).distinct().map(e->(index.getAndIncrement())+"、"+e+"\n").collect(Collectors.toList());
 			}else{
 				result=list.stream().distinct().collect(Collectors.toList());
 			}

+ 60 - 2
blade-service/blade-manager/src/main/java/com/mixsmart/utils/FormulaUtils.java

@@ -12,11 +12,19 @@ import org.springblade.manager.dto.ElementData;
 import org.springblade.manager.dto.FormData;
 import org.springblade.manager.entity.Formula;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.math.BigDecimal;
+import java.nio.charset.StandardCharsets;
 import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.Inflater;
+import java.util.zip.InflaterInputStream;
 
 /**
  * @author yangyj
@@ -315,14 +323,64 @@ public class FormulaUtils {
     }
 
     /**从元素名称中解析项目名称*/
+    public static final  Set<String> EX_WORD=new HashSet<String>(){{add("或");}};
     public static  String parseItemName(String eName){
-        String[] candidate= StringUtils.handleNull(eName).replaceAll("^[^\\u4e00-\\u9fa5]+","").replaceAll("\\s+","").split("[((].+[))]|_");
+        String[] candidate= StringUtils.handleNull(eName).replaceAll("[\\t\\n\\s+]","").split("[((_]");
         if(candidate.length>0){
-           return Arrays.stream(candidate).filter(e->!e.contains("实测项目")&&!e.contains("△")).findFirst().orElse(eName).replaceAll("实测值?|偏差值?|设计值?","");
+            return Arrays.stream(candidate).map(s->s.replaceAll("[^\\u4e00-\\u9fa5]+","").replaceAll("(在合格标准内|满足设计要求|质量评定|评定|判定|项目|总数|抽测|实测|偏差|设计|合格)[率值]?","")).filter(s->!EX_WORD.contains(s)&&StringUtils.isNotEmpty(s)).collect(Collectors.joining());
         }
         return eName;
     }
 
+    public static byte[] compress(String data) throws IOException {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        DeflaterOutputStream dos = new DeflaterOutputStream(bos, new Deflater(Deflater.BEST_COMPRESSION));
+        dos.write(data.getBytes(StandardCharsets.UTF_8));
+        dos.close();
+        return bos.toByteArray();
+    }
+
+    public static String decompress(byte[] data) throws IOException {
+        ByteArrayInputStream bis = new ByteArrayInputStream(data);
+        InflaterInputStream iis = new InflaterInputStream(bis, new Inflater());
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        byte[] buffer = new byte[1024];
+        int len;
+        while ((len = iis.read(buffer)) > 0) {
+            bos.write(buffer, 0, len);
+        }
+        iis.close();
+        bos.close();
+        return new String(bos.toByteArray(), StandardCharsets.UTF_8);
+    }
+
+
+//    public static void main(String[] args) {
+//        List<String> list =Arrays.asList(
+//                ""
+//                ,"压 实 度 (%)下路床 特重、极重交通荷载等级 设计值"
+//                ,"1△_压 实 度 (%)_下路床_轻、中及重交通 荷载等级_0.3m~0.8m_≧96_≧95_≧94_实测值或实测偏差值"
+//                ,"1△_压 实 度 (%)_下路提_轻、中及重交通 荷载等级_&gt;1.5m_≧93_≧92_≧90_实测值或实测偏差值"
+//                ,"1△_压 实 度 (%)_上路提_轻、中及重交通 荷载等级_0.8m~1.5m_≧94_≧94_≧93_实测值或实测偏差值"
+//                ,"压 实 度 (%)下路提 轻、中及重交通荷载等级 设计值"
+//                ,"压 实 度 (%)下路床 特重、极重交通荷载等级 合格率"
+//                ,"压 实 度 (%)下路提 轻、中及重交通荷载等级\t合格率"
+//                ,"5△_保护层 厚度 (mm)_基础、锚碇、墩台身、墩柱_±10_实测值或实测偏差值"
+//                ,"钢筋骨架尺寸宽、高或直径 (mm)_尺量:按骨架总数30%抽测_±5_实测值或实测偏差值"
+//                ,"钢筋骨架尺寸长 (mm)_±10_尺量:按骨架总数30%抽测_实测值或实测偏差值"
+//               , "受力钢筋间距 (mm)同排 梁、板、拱肋及拱上建筑	设计值"
+//               ,"受力钢筋间距 (mm)同排 梁、板、拱肋及拱上建筑	合格率"
+//               ," 箍筋、构造钢筋、螺旋筋间距(mm)	设计值"
+//               ,"箍筋、构造钢筋、螺旋筋间距(mm)	合格率"
+//                ,"实测项目_桩位 (mm)_群桩_≤100_质量评定_合格判定"
+//                 ,"实测项目_桩位 (mm)_群桩_≤100_实测值或实测偏差值"
+//                ,"实测项目_桩位 (mm)_排架桩_实测值或实测偏差值"
+//                ,"实测项目_桩位 (mm)_排架桩_质量评定_合格判定"
+//                ,"实测项目_桩位 (mm)_群桩_≤100_质量评定_合格率(%)"
+//                ,"实测项目_桩位 (mm)_排架桩_质量评定_合格率(%)"
+//        );
+//        list.stream().map(FormulaUtils::parseItemName).forEach(System.out::println);
+//    }
 
 
 }

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

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

+ 22 - 16
blade-service/blade-manager/src/main/java/org/springblade/manager/formula/impl/TableElementConverter.java

@@ -48,7 +48,7 @@ public class TableElementConverter implements ITableElementConverter {
     /**所有元素数据集*/
     Map<String,FormData> formDataMap = new HashMap<>();
     /**{tableName:{key:val}}*/
-    Map<String,Map<String,String>> coordinateMap;
+    Map<String,Map<String,String>> coordinateMap= new HashMap<>();
     /**{code:List<ElementData>}*/
     Map<String,ElementData> elementDataMap = new HashMap<>();
     /**跨表数据*/
@@ -60,7 +60,13 @@ public class TableElementConverter implements ITableElementConverter {
     /**记录表公式执行的日志*/
     StringBuilder log;
     /**当前执行环境全局变量*/
-    private   Map<String,Object> constantMap = new HashMap<>();
+    public   Map<String,Object> constantMap = new HashMap<>();
+    public   List<FormData> formDataList;
+
+
+    public    List<FormData> checkItems=new ArrayList<>();
+    public   List<FormData> checkDate=new ArrayList<>();
+    public   List<FormData> summary=new ArrayList<>();
 
 
 
@@ -89,20 +95,20 @@ public class TableElementConverter implements ITableElementConverter {
 
 
 
-    public void relyParse(Formula f){
-        if(Func.isNotBlank(f.getFormula())){
-            List<String> l = new ArrayList<>();
-            Matcher m = RP.matcher(f.getFormula());
-            while (m.find()){
-                l.add(m.group());
-            }
-            if(l.size()>0){
-                f.setRely(String.join(",", l));
-            }else{
-                f.setRely("");
-            }
-        }
-    }
+//    public void relyParse(Formula f){
+//        if(Func.isNotBlank(f.getFormula())){
+//            List<String> l = new ArrayList<>();
+//            Matcher m = RP.matcher(f.getFormula());
+//            while (m.find()){
+//                l.add(m.group());
+//            }
+//            if(l.size()>0){
+//                f.setRely(String.join(",", l));
+//            }else{
+//                f.setRely("");
+//            }
+//        }
+//    }
 
     public Boolean isPresent(){
         return BaseUtils.isNotNull(this.keyMappers,this.formulas,this.nodeId,this.contractId);

+ 124 - 106
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/FormulaServiceImpl.java

@@ -37,12 +37,14 @@ import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.web.context.WebApplicationContext;
 
+import javax.validation.constraints.NotNull;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Predicate;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
@@ -74,16 +76,11 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
 
     /**  private final Container env;*/
     private   TableElementConverter tec;
-    private   Map<String,Object> constantMap;
-    private   List<FormData> formDataList;
+//    private   Map<String,Object> constantMap;
+//    private   List<FormData> formDataList;
     private   Map<String,FormData> formDataMap;
     private   Map<String,Map<String,Object>> tableDataMaps;
 
-    private   List<FormData> checkItems;
-    private   List<FormData> checkDate;
-    private   List<FormData> summary;
-
-
 
     public final static String WP="WP";
     public final static String CHAIN="trees";
@@ -119,9 +116,6 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
 
     @Override
     public IFormulaService init() {
-        this.checkItems= new ArrayList<>();
-        this.checkDate= new ArrayList<>();
-        this.summary = new ArrayList<>();
         this.tableDataMaps=this.tec.getTableDataMaps();
         this.formDataMap=this.tec.getFormDataMap();
         List<FormData> list =this.tec.getFds();
@@ -129,17 +123,17 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
         CurrentNode one=this.tec.getCurrentNode();
         Long id =one.getId();
         Long primaryKeyId=one.getPkId();
-        this.constantMap=tec.getConstantMap();
-        this.formDataList=list;
-        this.constantMap.put("contractId",contractId);
-        keyWord(this.constantMap);
+//        tec.constantMap=tec.getConstantMap();
+        tec.formDataList=list;
+        tec.constantMap.put("contractId",contractId);
+        keyWord(tec.constantMap);
         ContractInfo info =this.contractInfoService.getById(contractId);
         /*合同段信息*/
-        this.constantMap.put(CTI,info);
+        tec.constantMap.put(CTI,info);
         /*项目信息*/
         ProjectInfo pji=this.projectInfoService.getById(info.getPId());
         tec.setProjectId(pji.getId());
-        this.constantMap.put(PJI,pji);
+        tec.constantMap.put(PJI,pji);
         /*wbs节点链*/
         List<WbsTreeContract> nodes = wpService.chain(contractId,id,primaryKeyId,null);
         if(Func.isEmpty(nodes)){
@@ -148,18 +142,18 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
         if(Func.isEmpty(nodes)){
             this.tec.getLog().append("【WBS信息缺失】");
         }
-        this.constantMap.put(CHAIN,nodes.stream().map(WbsTreeContract::getNodeName).collect(Collectors.toList()));
+        tec.constantMap.put(CHAIN,nodes.stream().map(WbsTreeContract::getNodeName).collect(Collectors.toList()));
         /*节点参数*/
-        this.constantMap.put(WP,getWpMap(one));
+        tec.constantMap.put(WP,getWpMap(one));
         /*表格名称*/
         List<AppWbsTreeContractVO> tableList =wbsTreeContractService.searchNodeAllTable(primaryKeyId.toString(), "1", contractId.toString(),info.getPId());
-        this.constantMap.put(TABLE_LIST,tableList);
+        tec.constantMap.put(TABLE_LIST,tableList);
         /*通过判断元素名称来确定,加入汇总公式延后执行*/
-      //  this.constantMap.put("tableNames",tableList.stream().filter(e->StringUtils.isEquals(e.getIsBussShow(),1)).map(WbsTreeContract::getNodeName).collect(Collectors.toList()));
-        this.constantMap.put("tableNames",tableList.stream().map(WbsTreeContract::getNodeName).collect(Collectors.toList()));
+      //  tec.constantMap.put("tableNames",tableList.stream().filter(e->StringUtils.isEquals(e.getIsBussShow(),1)).map(WbsTreeContract::getNodeName).collect(Collectors.toList()));
+        tec.constantMap.put("tableNames",tableList.stream().map(WbsTreeContract::getNodeName).collect(Collectors.toList()));
 
         List<String> missingList = new ArrayList<>();
-        this.formDataList.forEach(fd->{
+        tec.formDataList.forEach(fd->{
             if(fd.executable()){
                 relyParse(fd.getFormula());
                 Formula f= fd.getFormula();
@@ -185,56 +179,67 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                 "where a.p_key_id in("+this.tec.getTableAll().stream().map(AppWbsTreeContractVO::getPKeyId).map(Func::toStr).collect(Collectors.joining(","))+") and b.type=8 ");
         if(Func.isNotEmpty(textInfoMap)){
             Map<String,List<Map<String,Object>>> tmap = textInfoMap.stream().collect(Collectors.groupingBy(m->m.get("code").toString()));
-            this.constantMap.put(TEXT_INFO_MAP,tmap);
+            tec.constantMap.put(TEXT_INFO_MAP,tmap);
         }
         /*公式参数*/
         FormulaOption formulaOption = this.formulaOptionService.getOne(Wrappers.<FormulaOption>lambdaQuery().eq(FormulaOption::getParentId,one.getRelateId()).eq(FormulaOption::getContractId,contractId));
         if(formulaOption!=null){
            /*数据格式 {tablename:{keyxxx:{option:[1|0]}}}*/
-           this.constantMap.put(FMOT,JSON.parseObject(formulaOption.getVal(),LinkedHashMap.class));
+           tec.constantMap.put(FMOT,JSON.parseObject(formulaOption.getVal(),LinkedHashMap.class));
         }
         /*评定表*/
         assessmentForm();
         return this;
     }
 
+    public  FormulaDataBlock findFdb(){
+        AppWbsTreeContractVO one =tec.getTableAll().get(0);
+        List<String> ancestor=new ArrayList<>(Arrays.asList(one.getAncestors().split(",")));
+        Collections.reverse(ancestor);
+        FormulaDataBlock fdb=  this.formulaDataBlockService.queryOption(Long.parseLong(one.getContractId()),Long.parseLong(ancestor.get(1)),0);
+        if(fdb==null){
+            fdb=new FormulaDataBlock();
+            fdb.setContractId(tec.getContractId());
+            fdb.setSwId(Long.parseLong(ancestor.get(1)));
+            fdb.setType(0);
+            fdb.setVal("[]");
+        }
+        return fdb;
+    }
     public void assessmentForm(){
         if(tec.getTableAll().stream().anyMatch(e->StringUtils.isEquals(e.getTableType(),5))){
             /*评定节点*/
-            AppWbsTreeContractVO one =tec.getTableAll().get(0);
-            List<String> ancestor=new ArrayList<>(Arrays.asList(one.getAncestors().split(",")));
-            Collections.reverse(ancestor);
-            FormulaDataBlock fdb = this.formulaDataBlockService.queryOption(Long.parseLong(one.getContractId()),Long.parseLong(ancestor.get(1)),0);
-            if(fdb!=null&&Func.isNotBlank(fdb.getVal())){
+            FormulaDataBlock fdb = findFdb();
+            if(!StringUtils.isEquals("[]",fdb.getVal())){
                 List<ElementBlock> elementBlockList =JSON.parseArray(fdb.getVal(),ElementBlock.class);
                 Map<String, Measurement> itemsMap = new HashMap<>();
                 this.formDataMap.values().forEach(e->{
                     String eName=e.getEName();
-                    if(eName.contains("实测")&&!eName.contains("平均")){
+                    if(eName.contains("实测")&&!eName.contains("平均")&&!eName.contains("率")&&!eName.contains("判")){
                         String point  =FormulaUtils.parseItemName(eName);
                         Measurement measurement = itemsMap.computeIfAbsent(point,k->new Measurement(point));
-                        if(eName.contains("偏差")){
-                            measurement.setValue(e);
-                        }else if(eName.contains("率")){
-                            measurement.setPass(e);
-                        }else if(eName.contains("判")){
-                            measurement.setJudge(e);
-                        }
+                        measurement.setValue(e);
                     }
                 });
                 if(itemsMap.size()>0){
-                    itemsMap.values().forEach(i->{
-                        FormData vf=i.getValue();
-                        if(vf!=null){
-                            if(i.getPass()==null){
-                               i.setPass(tec.getFormDataMap().values().stream().filter(v->v.getTableName().equals(vf.getTableName())&&!v.getCode().equals(vf.getCode())).filter(v->v.getEName().contains(i.getPoint())&&v.getEName().contains("率")).findAny().orElse(null));
-                            }
-                            if(i.getJudge()==null){
-                                i.setJudge(tec.getFormDataMap().values().stream().filter(v->v.getTableName().equals(vf.getTableName())&&!v.getCode().equals(vf.getCode())).filter(v->v.getEName().contains(i.getPoint())&&v.getEName().contains("判")).findAny().orElse(null));
-                            }
-                        }
+                    tec.getFormDataMap().values().stream()
+                            .filter(v -> v.getEName().contains("率") || v.getEName().contains("判"))
+                            .forEach(v -> {
+                                itemsMap.values().stream()
+                                        .filter(i -> i.getPass() == null || i.getJudge() == null)
+                                        .filter(i -> {
+                                            FormData vf = i.getValue();
+                                            return vf != null && vf.getTableName().equals(v.getTableName()) && !vf.getCode().equals(v.getCode())&&FormulaUtils.similarity(v.getEName(),vf.getEName())>0.75;
+                                        }).max(Comparator.comparingDouble((Measurement i)->FormulaUtils.similarity(v.getEName(),i.getValue().getEName())))
+                                        .ifPresent(i->{
+                                               if (v.getEName().contains("率") && i.getPass() == null) {
+                                                   i.setPass(v);
+                                               } else if (v.getEName().contains("判") && i.getJudge() == null) {
+                                                   i.setJudge(v);
+                                               }
+                                         });
+                            });
 
-                    });
                     AtomicBoolean update= new AtomicBoolean(false);
                     itemsMap.values().stream().filter(Measurement::isMatching).forEach(t->{
                         ElementBlock g=null;
@@ -247,7 +252,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                            }
                         }
                         if(g==null){
-                            Optional<ElementBlock> op=   elementBlockList.stream().filter(w->FormulaUtils.similarity(w.getEName(),t.getPoint())>0.6).reduce((a, b) -> Comparator.<Double>reverseOrder().compare(FormulaUtils.similarity(a.getEName(),t.getPoint()), FormulaUtils.similarity(b.getEName(),t.getPoint())) <= 0 ? a : b);
+                            Optional<ElementBlock> op= elementBlockList.stream().filter(w->FormulaUtils.similarity(w.getEName(),t.getPoint())>0.6).reduce((a, b) -> Comparator.<Double>reverseOrder().compare(FormulaUtils.similarity(a.getEName(),t.getPoint()), FormulaUtils.similarity(b.getEName(),t.getPoint())) <= 0 ? a : b);
                             if(op.isPresent()){
                                 g=op.get();
                             }
@@ -298,7 +303,6 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                         this.formulaDataBlockService.saveOrUpdate(fdb);
                     }
                 }
-
             }
         }
     }
@@ -523,7 +527,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
         /*元素动态绑定*/
         this.formDataMap.values().stream().filter(e->e.getIsCurrentNodeElement()&&e.getFormula()==null).forEach(e->{
             /*执行列表里不存在,且元素的名称和节点参数名称匹配成功*/
-            total.stream().filter(p->e.getEName().contains(p.getName().replace("【水】","").trim())&&!this.formDataList.contains(e)).findAny().ifPresent(d->{
+            total.stream().filter(p->e.getEName().contains(p.getName().replace("【水】","").trim())&&!tec.formDataList.contains(e)).findAny().ifPresent(d->{
                 Formula  formula=new Formula();
                 formula.setOutm(Formula.FULL);
                 if(RegexUtil.match(ParamElements.LEVEL_REG,d.getV().trim())){
@@ -535,7 +539,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                 }
                 e.setFormula(formula);
                 tec.getLog().append("动态绑定参数:").append(e.getEName()).append(";");
-                this.formDataList.add(e);
+                tec.formDataList.add(e);
             });
         });
         return result;
@@ -543,22 +547,22 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
 
     @Override
     public IFormulaService sort() {
-        Map<Boolean,List<FormData>> map = this.formDataList.stream().collect(Collectors.partitioningBy(e->Func.isNotEmpty(e.getFormula())&&e.getFormula().getFormula().contains("E[")));
-        this.formDataList.clear();
+        Map<Boolean,List<FormData>> map = tec.formDataList.stream().collect(Collectors.partitioningBy(e->Func.isNotEmpty(e.getFormula())&&e.getFormula().getFormula().contains("E[")));
+        tec.formDataList.clear();
         /*没有依赖的*/
         List<FormData> simple=map.get(false);
         if(CollectionUtil.isNotEmpty(simple)){
-            this.formDataList.addAll(simple);
+            tec.formDataList.addAll(simple);
         }
         /*有依赖的*/
         List<FormData> rely= map.get(true);
         if(CollectionUtil.isNotEmpty(rely)){
             sort(rely,((rely.size()+1)/2)*rely.size());
-            this.formDataList.addAll(rely);
+            tec.formDataList.addAll(rely);
         }
         /*初始化排序值,每个点间隔1000,方便插入*/
         AtomicInteger sort= new AtomicInteger();
-        this.formDataList.forEach(e->e.setSort(sort.getAndAdd(1000)));
+        tec.formDataList.forEach(e->e.setSort(sort.getAndAdd(1000)));
         /*汇总阶段执行的公式*/
         summaryPre();
         return this;
@@ -566,20 +570,20 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
 
     /*汇总阶段执行的公式*/
     public void summaryPre(){
-        this.formDataList.stream().filter(FormData::executable).filter(e->StringUtils.isEquals("CKI",e.getFormula().getNumber())||StringUtils.isEquals("CKD",e.getFormula().getNumber())).forEach(t->this.summary.add(t));
-        this.formDataList.removeAll(this.summary);
+        tec.formDataList.stream().filter(FormData::executable).filter(e->StringUtils.isEquals("CKI",e.getFormula().getNumber())||StringUtils.isEquals("CKD",e.getFormula().getNumber())).forEach(t->tec.summary.add(t));
+        tec.formDataList.removeAll(tec.summary);
         /*监表的处理*/
         Optional<AppWbsTreeContractVO> aop=tec.getTableAll().stream().filter(e->e.getNodeName().contains("A15")).findAny();
         if(aop.isPresent()){
             /*存在监表,则需要收集检查项目和检查时间等元素*/
-            Optional<AppWbsTreeContractVO> wop=tec.getTableAll().stream().filter(e->e.getNodeName().contains("检验单")||e.getNodeName().contains("检验表")).findAny();
-            if(wop.isPresent()){
+            List<String> wop=tec.getTableAll().stream().filter(e->e.getNodeName().contains("检验单")||e.getNodeName().contains("检验表")).map(AppWbsTreeContractVO::getInitTableName).distinct().collect(Collectors.toList());
+            if(wop.size()>0){
                 /*存在检验表*/
-                tec.getKeyMappers().stream().filter(e->StringUtils.isEquals(wop.get().getInitTableName(),e.getTableName())&&this.formDataMap.containsKey(e.getCode())).forEach(k->{
+                tec.getKeyMappers().stream().filter(e->wop.contains(e.getTableName())&&this.formDataMap.containsKey(e.getCode())).forEach(k->{
                     if(k.getEName().contains("实测值")&&k.getEName().contains("偏差值")){
-                        this.checkItems.add(this.formDataMap.get(k.getCode()));
+                        tec.checkItems.add(this.formDataMap.get(k.getCode()));
                     }else if(k.getEName().contains("检验日期")){
-                        this.checkDate.add(this.formDataMap.get(k.getCode()));
+                        tec.checkDate.add(this.formDataMap.get(k.getCode()));
                     }
                 });
             }else{
@@ -588,20 +592,27 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                 tec.getKeyMappers().stream().filter(k->recordTable.contains(k.getTableName())).map(k->k.getCode()+"@"+k.getEName()).distinct().forEach(k->{
                     String[] ka=k.split("@");
                     if(ka[1].contains("实测值")){
-                        this.checkItems.add(this.formDataMap.get(ka[0]));
+                        tec.checkItems.add(this.formDataMap.get(ka[0]));
                     }else if(ka[1].contains("日期")||ka[1].contains("年月日")){
-                        this.checkDate.add(this.formDataMap.get(ka[0]));
+                        tec.checkDate.add(this.formDataMap.get(ka[0]));
                     }
                 });
 
             }
         }
+        if(tec.checkItems.size()>0){
+            /**排序*/
+            List<String> iniTableNames=tec.getTableAll().stream().map(AppWbsTreeContractVO::getInitTableName).distinct().collect(Collectors.toList());
+            tec.checkItems= tec.checkItems.stream().sorted(Comparator.comparingInt((FormData i)->iniTableNames.indexOf(i.getTableName())).thenComparingInt(FormData::getMaxRow)).collect(Collectors.toList());
+        }
+        System.out.println();
+
     }
 
     @Override
     public IFormulaService pre() {
-        if(CollectionUtil.isNotEmpty(this.formDataList)){
-            for(FormData fd:this.formDataList){
+        if(CollectionUtil.isNotEmpty(tec.formDataList)){
+            for(FormData fd:tec.formDataList){
                 /*预处理公式脚本,只做文本转换不做计算*/
                 if(!fd.executable()){
                     /*不存公式,则认为执行完成,不会再主动执行*/
@@ -644,7 +655,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
 
     @Override
     public IFormulaService special() {
-        for(FormData fd:this.formDataList) {
+        for(FormData fd:tec.formDataList) {
             try {
                 if(Func.isNotEmpty(fd.getFormula())) {
                     formulaStrategyFactory.get(fd).forEach(e -> e.execute(tec));
@@ -675,7 +686,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
         if(op.isPresent()){
             checkTable=op.get().getInitTableName();
         }
-        for(FormData fd:this.formDataList){
+        for(FormData fd:tec.formDataList){
             if(fd.verify()){
                 Formula formula =fd.getFormula();
                 String f=formula.getFormula();
@@ -684,7 +695,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                         /*非解析器自定义运算*/
                         preCalc(fd);
                         tmpFc(fd);
-                        Map<String, Object> currentMap = new HashMap<>(this.constantMap);
+                        Map<String, Object> currentMap = new HashMap<>(tec.constantMap);
                         List<String>  relyList = fd.getFormula().getRelyList();
                         if(CollectionUtil.isNotEmpty(relyList)){
                             List<FormData>  ele = new ArrayList<>();
@@ -716,7 +727,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                                 List<LocalVariable>  local= new ArrayList<>();
                                 while (cda.hasNext()){
                                     LinkedHashMap<String,ElementData> tip= cda.next();
-                                    Map<String, Object> variable = new HashMap<>(this.constantMap);
+                                    Map<String, Object> variable = new HashMap<>(tec.constantMap);
                                     Map<String,Object> em= (Map<String, Object>) variable.computeIfAbsent(E, k->new HashMap<>());
                                     int index= new ArrayList<>(tip.values()).get(0).getIndex();
                                     for(Map.Entry<String,ElementData> se:tip.entrySet()){
@@ -731,7 +742,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                                     local.add(new LocalVariable(index,f,variable));
                                 }
                                 if(local.size()>0){
-                                    List<Object> values = slice(local,this.constantMap,f);
+                                    List<Object> values = slice(local,tec.constantMap,f);
                                     if(fd.getTableName().equals(checkTable)){
                                         FormulaUtils.write(fd,values,false);
                                     }else{
@@ -836,7 +847,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                             if(tmp!=null){
                                 tmp.setIsCurrentNodeElement(true);
                                 this.formDataMap.put(tmp.getCode(),tmp);
-                                this.formDataList.add(tmp);
+                                tec.formDataList.add(tmp);
                             }
                         });
                         /*生成元素映射关系*/
@@ -883,11 +894,11 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                     Map<String,Object> copyMap= new HashMap<>();
                     if(sourceFds.size()>0){
                         sourceFds.forEach(d->{
-                            copyMap.put(d.getEName().trim(),d.getValues().stream().map(ElementData::getValue).filter(StringUtils::isNotEmpty).findAny().orElse(""));
+                            copyMap.put(d.getSimplifyName(),d.getValues().stream().map(ElementData::getValue).filter(StringUtils::isNotEmpty).findAny().orElse(""));
                         });
                     }
-                    subTableFds.stream().filter(s-> !SubTable.KEYS.contains(s.getEName().trim())).filter(s->copyMap.containsKey(s.getEName().trim())).forEach(t->{
-                         Object val = copyMap.get(t.getEName().trim());
+                    subTableFds.stream().filter(s-> !SubTable.KEYS.contains(s.getEName().trim())).filter(s->copyMap.containsKey(s.getSimplifyName())).forEach(t->{
+                         Object val = copyMap.get(t.getSimplifyName());
                          t.getValues().forEach(e->e.setValue(val));
                          t.setUpdate(1);
                     });
@@ -905,29 +916,29 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
     /**汇总处理*/
     public void summaryCalc(){
         try{
-            if(this.summary.size()>0){
+            if(tec.summary.size()>0){
                 /**/
-                List<String> result=this.checkItems.stream().filter(fdTmp->fdTmp.getValues().stream().map(ElementData::getValue).anyMatch(e->StringUtils.isNotEmpty(e)&&StringUtils.isNotEquals("/",e))).map(FormData::getEName).map(FormulaUtils::parseItemName).distinct().collect(Collectors.toList());
-                Optional<FormData> opk= this.summary.stream().filter(FormData::executable).filter(f->StringUtils.isEquals(f.getFormula().getNumber(),CHECK_ITEMS)).findAny();
+                List<String> result=tec.checkItems.stream().filter(fdTmp->fdTmp.getValues().stream().map(ElementData::getValue).anyMatch(e->StringUtils.isNotEmpty(e)&&StringUtils.isNotEquals("/",e))).map(FormData::getEName).map(FormulaUtils::parseItemName).distinct().collect(Collectors.toList());
+                Optional<FormData> opk= tec.summary.stream().filter(FormData::executable).filter(f->StringUtils.isEquals(f.getFormula().getNumber(),CHECK_ITEMS)).findAny();
                 List<String> history=null;
                 if(opk.isPresent()&&!opk.get().empty()){
                     /*假如已经存在内容,则需要筛选出手填部分*/
                     history=  Arrays.asList(opk.get().getValues().get(0).stringValue().replaceAll("[\\s\\n]+","").split("[,、,]"));
                 }
                 if(history!=null&&history.size()>0){
-                    List<String> itemAll=this.checkItems.stream().map(FormData::getEName).map(FormulaUtils::parseItemName).distinct().collect(Collectors.toList());
+                    List<String> itemAll=tec.checkItems.stream().map(FormData::getEName).map(FormulaUtils::parseItemName).distinct().collect(Collectors.toList());
                     List<String> customize=history.stream().filter(s->!itemAll.contains(s)).collect(Collectors.toList());
                     result.addAll(customize);
                 }
-                this.constantMap.put(CHECK_ITEMS,result);
-                this.constantMap.put("CKD",this.checkDate.stream().flatMap(k->k.getValues().stream()).map(ElementData::stringValue).filter(StringUtils::isNotEmpty).reduce((a, b) -> Comparator.<DateTime>reverseOrder().compare(new DateTime(a), new DateTime(b)) <= 0 ? a : b).orElse(null));
-                this.summary.forEach(e->{
+                tec.constantMap.put(CHECK_ITEMS,result);
+                tec.constantMap.put("CKD",tec.checkDate.stream().flatMap(k->k.getValues().stream()).map(ElementData::stringValue).filter(StringUtils::isNotEmpty).reduce((a, b) -> Comparator.<DateTime>reverseOrder().compare(new DateTime(a), new DateTime(b)) <= 0 ? a : b).orElse(null));
+                tec.summary.forEach(e->{
                     /*处理脚本*/
                     e.getFormula().setFormula(e.getFormula().getNumber());
                 });
-                this.summary.forEach(e->{
+                tec.summary.forEach(e->{
                     /*执行公式*/
-                    Object data = Expression.parse(e.getFormula().getFormula()).calculate(this.constantMap);
+                    Object data = Expression.parse(e.getFormula().getFormula()).calculate(tec.constantMap);
                     if(data!=null){
                         FormulaUtils.write(e,data,false);
                         e.setUpdate(1);
@@ -947,20 +958,10 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
     /**分项汇总数据*/
     public void   doForDataBlock(){
         try {
-            AppWbsTreeContractVO one =tec.getTableAll().get(0);
-            List<String> ancestor=new ArrayList<>(Arrays.asList(one.getAncestors().split(",")));
-            Collections.reverse(ancestor);
-            FormulaDataBlock fdb = this.formulaDataBlockService.queryOption(Long.parseLong(one.getContractId()),Long.parseLong(ancestor.get(1)),0);
+            FormulaDataBlock fdb=findFdb();
             List<ElementBlock> elementBlockList=new ArrayList<>();
             Map<String,ElementBlock> elementBlockMap =new HashMap<>();
             Map<String,ItemBlock>itemBlockMap =new HashMap<>();
-            if(fdb==null){
-                fdb=new FormulaDataBlock();
-                fdb.setContractId(tec.getContractId());
-                fdb.setSwId(Long.parseLong(ancestor.get(1)));
-                fdb.setType(0);
-                fdb.setVal("[]");
-            }
             if(Func.isNotBlank(fdb.getVal())) {
                 elementBlockList = JSON.parseArray(fdb.getVal(), ElementBlock.class);
                 elementBlockList.forEach(eb->{
@@ -975,14 +976,14 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                 });
             }
             List<ElementBlock> finalElementBlockList = elementBlockList;
-            this.checkItems.stream().filter(e->!e.empty()).forEach(c->{
+            tec.checkItems.stream().filter(e->!e.empty()).forEach(c->{
                      ElementBlock eb =elementBlockMap.get(c.getCode());
                      ItemBlock targetItem=itemBlockMap.get(c.getCode()+":"+tec.getCurrentNode().getPkId());
                      List<Object> list = c.getValues().stream().map(ElementData::getValue).filter(StringUtils::isNotEmpty).collect(Collectors.toList());
                      /*1.无任何记录,当前页无数据,则不需要处理 2.存在记录当前无数据,则要消除 3.没有记录当前有数据,则需要增加 4.有记录有当前记录,则需更新*/
                      if(Func.isNotEmpty(list)||targetItem!=null){
-                         FormData designList=tec.getFormDataMap().values().stream().filter(t->t.getEName().contains(FormulaUtils.parseItemName(c.getEName()))&&t.getEName().contains("设计")&&StringUtils.isEquals(t.getTableName(),c.getTableName())).collect(Collectors.toList()).get(0);
-                         FormData pass=tec.getFormDataMap().values().stream().filter(t->t.getEName().contains(FormulaUtils.parseItemName(c.getEName()))&&t.getEName().contains("合格")&&StringUtils.isEquals(t.getTableName(),c.getTableName())).collect(Collectors.toList()).get(0);
+                         FormData designList=itemMatch(c,0);
+                         FormData pass=itemMatch(c,1);
                          if(targetItem==null){
                              if(eb==null){
                                  eb=new ElementBlock();
@@ -1036,6 +1037,23 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
         }
     }
 
+    /**
+     * @Description 根据实测值元素匹配相关联的元素如设计值合格率
+     * @Param [measured:实测值, type:0设计值 1合格率]
+     * @Date 2023.04.25 14:41
+     **/
+    public FormData itemMatch(FormData measured,@NotNull Integer type){
+        Predicate<FormData> predicate =(FormData t)-> StringUtils.isEquals(t.getTableName(),measured.getTableName());
+        if(type ==0){
+            predicate=  predicate.and((FormData t)->t.getEName().contains("设计"));
+        }else {
+            predicate=   predicate.and((FormData t)->t.getEName().contains("合格"));
+        }
+        predicate= predicate.and((FormData t)->FormulaUtils.similarity(t.getEName(),measured.getEName())>0.75);
+        //FormData target=tec.getFormDataMap().values().stream().filter(t->StringUtils.isEquals(t.getTableName(),measured.getTableName())&&t.getEName().contains("设计")&&FormulaUtils.similarity(t.getEName(),measured.getEName())>0.75).max(Comparator.comparingDouble((FormData t)->FormulaUtils.similarity(t.getEName(),measured.getEName()))).orElse(null);
+        return tec.getFormDataMap().values().stream().filter(predicate).max(Comparator.comparingDouble((FormData t)->FormulaUtils.similarity(t.getEName(),measured.getEName()))).orElse(null);
+    }
+
     public  void write(FormData fd,Object data){
         /*如果需要向额外元素或对象输出数据,在此处修改*/
                fd.setUpdate(1);
@@ -1128,7 +1146,7 @@ public  List<ElementData> setScale(Integer scale,List<ElementData> data){
     @Override
     public void format() {
         /*数据格式化*/
-        for(FormData fd:this.formDataList){
+        for(FormData fd:tec.formDataList){
             if(fd.verify()){
                 /*保留小数位*/
                 if(fd.getFormula()!=null&&!fd.empty()&&fd.getValues().stream().map(ElementData::getValue).anyMatch(StringUtils::isDouble)){
@@ -1341,7 +1359,7 @@ public  List<ElementData> setScale(Integer scale,List<ElementData> data){
                            if(kOp.isPresent()){
                                /*表名+合同段+父节点*/
                                String findStr="OP['"+fd.getTableName()+"']['"+fd.getKey()+"']['TF']";
-                               flag=StringUtils.handleNull(Expression.parse(findStr).calculate(this.constantMap));
+                               flag=StringUtils.handleNull(Expression.parse(findStr).calculate(tec.constantMap));
                            }
                        }else if(flag.contains("E[")){
                            List<FormData> target = getFormDataByCode(flag);
@@ -1385,7 +1403,7 @@ public  List<ElementData> setScale(Integer scale,List<ElementData> data){
                      while (m.find()) {
                          Object data=null;
                          List<String> codeList = getCodeList(m.group(2));
-                         Map<String,List<Map<String,Object>>> textInfoMap= (Map<String, List<Map<String, Object>>>) this.constantMap.getOrDefault(TEXT_INFO_MAP,new HashMap<>());
+                         Map<String,List<Map<String,Object>>> textInfoMap= (Map<String, List<Map<String, Object>>>) tec.constantMap.getOrDefault(TEXT_INFO_MAP,new HashMap<>());
                          List<Map<String,Object>> tableColKeyVal= textInfoMap.get(codeList.get(0));
                          if(Func.isNotEmpty(tableColKeyVal)){
                              Optional<RangeInfo> op=tableColKeyVal.stream().map(map-> BeanUtil.toBean(JSON.parseObject(map.get("val").toString()),RangeInfo.class)).findFirst();
@@ -1422,7 +1440,7 @@ public  List<ElementData> setScale(Integer scale,List<ElementData> data){
 
 
    public Map<String,Object> createCurrentMap(String el){
-         Map<String,Object> currentMap= new HashMap<String,Object>(this.constantMap);
+         Map<String,Object> currentMap= new HashMap<String,Object>(tec.constantMap);
          List<FormData> fds= getFormDataByCode(String.join(",", getCodeByEl(el)));
          if(Func.isNotEmpty(fds)){
              Map<String,Object> Em= (Map<String, Object>) currentMap.computeIfAbsent(E, k->new HashMap<String,Object>());
@@ -1460,7 +1478,7 @@ public  List<ElementData> setScale(Integer scale,List<ElementData> data){
                         }
                         String key ="HA"+HashUtil.identityHashCode(data);
                         fd.getFormula().setFormula(key);
-                        this.constantMap.put(key,data);
+                        tec.constantMap.put(key,data);
                     }else{
                         fd.getFormula().setFormula(StringPool.EMPTY);
                     }
@@ -1498,7 +1516,7 @@ public  List<ElementData> setScale(Integer scale,List<ElementData> data){
     /**把计算结果放入固定常量集,创建key来引用*/
     public String putDataWithKey(Object data){
         String key ="HA"+HashUtil.identityHashCode(data);
-        this.constantMap.put(key,data);
+        tec.constantMap.put(key,data);
         return key;
     }