浏览代码

Merge branch 'feature-lihb-bug' of http://219.151.181.73:3000/zhuwei/bladex into test-merge-02

# Conflicts:
#	blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/MessageWarningVO.java
#	blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/ArchivesAutoMapper.java
#	blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/ArchivesAutoMapper.xml
#	blade-service/blade-archive/src/main/java/org/springblade/archive/service/IArchivesAutoService.java
#	blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchivesAutoServiceImpl.java
#	blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java
LHB 3 月之前
父节点
当前提交
14785886d4
共有 32 个文件被更改,包括 904 次插入169 次删除
  1. 1 1
      blade-common/src/main/java/org/springblade/common/utils/AsyncConfigurer.java
  2. 26 0
      blade-common/src/main/java/org/springblade/common/utils/ForestNodeMergerEx.java
  3. 12 0
      blade-service-api/blade-archive-api/src/main/java/org/springblade/archive/trans/ArchiveTreeVo.java
  4. 8 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/ArchiveFile.java
  5. 3 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/MessageWarningVO.java
  6. 5 4
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/ArchiveTreeContract.java
  7. 3 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/feign/ArchiveTreeContractClient.java
  8. 5 1
      blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchiveFileAutoController.java
  9. 2 2
      blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/ArchivesAutoMapper.java
  10. 1 1
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/IArchivesAutoService.java
  11. 148 4
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveNameServiceImpl.java
  12. 339 74
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchivesAutoServiceImpl.java
  13. 1 1
      blade-service/blade-business/pom.xml
  14. 8 2
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/MetadataClassificationServiceImpl.java
  15. 2 1
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TaskServiceImpl.java
  16. 10 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/WeatherInfoServiceImpl.java
  17. 137 51
      blade-service/blade-e-visa/src/main/java/org/springblade/evisa/controller/ArchiveController.java
  18. 9 4
      blade-service/blade-e-visa/src/main/java/org/springblade/evisa/controller/EVController.java
  19. 1 1
      blade-service/blade-e-visa/src/main/java/org/springblade/evisa/service/EVisaService.java
  20. 11 6
      blade-service/blade-e-visa/src/main/java/org/springblade/evisa/service/impl/EVDataServiceImpl.java
  21. 32 5
      blade-service/blade-e-visa/src/main/java/org/springblade/evisa/service/impl/EVisaServiceImpl.java
  22. 1 1
      blade-service/blade-manager/pom.xml
  23. 2 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ArchiveTreeContractController.java
  24. 1 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java
  25. 7 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/feign/ArchiveTreeContractImpl.java
  26. 2 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ArchiveTreeContractMapper.java
  27. 38 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ArchiveTreeContractMapper.xml
  28. 2 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IArchiveTreeContractService.java
  29. 2 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ArTreeContractInitServiceImpl.java
  30. 80 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ArchiveTreeContractServiceImpl.java
  31. 4 4
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ArchiveTreeContractSyncImpl.java
  32. 1 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ExcelTabServiceImpl.java

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

@@ -15,7 +15,7 @@ public class AsyncConfigurer {
     /**
      * cpu 核心数量
      */
-    public static final int cpuNum = 3 ;//Runtime.getRuntime().availableProcessors();
+    public static final int cpuNum = 1 ;//Runtime.getRuntime().availableProcessors();
 
     /**
      * 线程池配置

+ 26 - 0
blade-common/src/main/java/org/springblade/common/utils/ForestNodeMergerEx.java

@@ -331,4 +331,30 @@ public class ForestNodeMergerEx {
     }
 
 
+    //芯的更新
+    public static <T extends INodeEx<T>> void InitTreeSortEx(T node, String parentTreeSort, int siblingIndex) {
+        // 计算当前节点排序值:100 + 兄弟索引
+        int currentSort = 100 + siblingIndex;
+
+        // 格式化为3位数字(100-999)
+        String sortStr = String.format("%03d", currentSort);
+
+        // 拼接树路径(无分隔符)
+        String currentTreeSort = parentTreeSort + sortStr;
+
+        // 检查是否需要更新
+        if (node.getTreeSort() == null || !node.getTreeSort().equals(currentTreeSort)) {
+            node.setFlag(1);
+            node.setTreeSort(currentTreeSort);
+        }
+
+        // 递归处理子节点
+        List<T> children = node.getChildren();
+        if (children != null && !children.isEmpty()) {
+            for (int i = 0; i < children.size(); i++) {
+                InitTreeSortEx(children.get(i), currentTreeSort, i);
+            }
+        }
+    }
+
 }

+ 12 - 0
blade-service-api/blade-archive-api/src/main/java/org/springblade/archive/trans/ArchiveTreeVo.java

@@ -43,6 +43,7 @@ public class ArchiveTreeVo {
     private String code;
     private String storageTime;
     private String secretLevel;
+    private Integer extNodeType;
 
     public String getId() {
         return id;
@@ -328,7 +329,18 @@ public class ArchiveTreeVo {
         return secretLevel;
     }
 
+
+
+
     public void setSecretLevel(String secretLevel) {
         this.secretLevel = secretLevel;
     }
+
+    public Integer getExtNodeType() {
+        return extNodeType;
+    }
+
+    public void setExtNodeType(Integer extNodeType) {
+        this.extNodeType = extNodeType;
+    }
 }

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

@@ -422,4 +422,12 @@ public class ArchiveFile extends BaseEntity {
         this.setIsDeleted(0);
 
     }
+
+    public void setFileTime(String fileTime) {
+        if (fileTime == null || fileTime.equals("null") ) {
+            this.fileTime = "";
+            return;
+        }
+        this.fileTime = fileTime.replaceAll("[^0-9]", "");
+    }
 }

+ 3 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/MessageWarningVO.java

@@ -48,6 +48,9 @@ public class MessageWarningVO extends MessageWarning {
     @ApiModelProperty("1废除, 2驳回")
     private String repealType;
 
+    @ApiModelProperty("1废除, 2驳回")
+    private String typeValue;
+
     @ApiModelProperty("任务催办未读数量")
     private Long typeOneNumber;
 

+ 5 - 4
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/ArchiveTreeContract.java

@@ -372,10 +372,11 @@ public class ArchiveTreeContract extends BaseEntity {
         this.projectType = archiveTree.getProjectType();
         this.storageType = archiveTree.getStorageType();
         this.expDataType = archiveTree.getExpDataType();
-        this.archiveAutoType = archiveTree.getArchiveAutoType();
-        this.archiveAutoNodeId = archiveTree.getArchiveAutoNodeId();
-        this.archiveAutoGroupId = archiveTree.getArchiveAutoGroupId();
-        this.archiveAutoGroupSelect = archiveTree.getArchiveAutoGroupSelect();
+        //TODO 0625
+//        this.archiveAutoType = archiveTree.getArchiveAutoType();
+//        this.archiveAutoNodeId = archiveTree.getArchiveAutoNodeId();
+//        this.archiveAutoGroupId = archiveTree.getArchiveAutoGroupId();
+//        this.archiveAutoGroupSelect = archiveTree.getArchiveAutoGroupSelect();
         this.isUploadFileDisplayConfigurationTree = archiveTree.getIsDisplayTree();
         this.classify = archiveTree.getClassify();
         this.treeSort =  archiveTree.getTreeSort();

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

@@ -48,6 +48,9 @@ public interface ArchiveTreeContractClient {
     @PostMapping(API_PREFIX + "/getArchiveTreeContractListByIds")
     List<ArchiveTreeContract> getArchiveTreeContractListByIds(@RequestParam String ids);
 
+    @PostMapping(API_PREFIX + "/getArchiveTreeContractListByList")
+    List<ArchiveTreeContract> getArchiveTreeContractListByList(@RequestBody List<Long> ids);
+
     @PostMapping(API_PREFIX + "/getFirstNodeByTreeCode")
     ArchiveTreeContract getFirstNodeByTreeCode(@RequestParam Long projectId,@RequestParam Integer type);
 

+ 5 - 1
blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchiveFileAutoController.java

@@ -339,12 +339,16 @@ ArchiveFileAutoController extends BladeController {
     @ApiOperation(value = "预览")
     public R<Object> mergePdf(@RequestParam String ids) {
         List<ArchiveFile> result = this.archiveFileClient.getArchiveFileByArchivesId(ids, "");
+        // 由于文件分解后,pdf文件会生成多个,所以需要合并
+        if(result!=null && result.size()>0){
+            result.sort(Comparator.comparing(ArchiveFile::getSort));
+        }
         List<String> pdfUrls = result.stream().map(archiveFile -> StringUtils.isNotEmpty(archiveFile.getPdfFileUrl()) ? archiveFile.getPdfFileUrl() : archiveFile.getFileUrl()).distinct().collect(Collectors.toList());
 
         //FileUtils.mergePdfPublicMethods(pdfUrls,"");
         /**
          * 案卷的只有一个文件,不合并先,需要的时候在把合并方法放出来
          * **/
-        return R.data(pdfUrls);
+        return R.data(pdfUrls.get(0));
     }
 }

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

@@ -225,8 +225,8 @@ public interface ArchivesAutoMapper extends BaseMapper<ArchivesAuto> {
 	 */
 	Map<String, BigDecimal> getAllArchiveByContractTypeSummary(@Param("projectId") Long projectId,@Param("type") String typ);
 
-    List<ArchivesAutoVO4> selectAllArchiveAuto(@Param("projectId")Long projectId, @Param("contractId") Long contractId, @Param("nodeIds") List<String> nodeIds,@Param("isArchive")Integer isArchive);
+	String getArchiveFileByParentId(@Param("nodeId") String nodeId,@Param("contractId") String contractId);
 
+    List<ArchivesAutoVO4> selectAllArchiveAuto(@Param("projectId")Long projectId, @Param("contractId") Long contractId, @Param("nodeIds") List<String> nodeIds,@Param("isArchive")Integer isArchive);
 
-    String getArchiveFileByParentId(@Param("nodeId") String nodeId,@Param("contractId") String contractId);
 }

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

@@ -89,7 +89,7 @@ public interface IArchivesAutoService extends BaseService<ArchivesAuto> {
 	//刷新某个项目的档号
 	void refreshFileNumberNoSlipt(Long projectId,Long contractId,Long nodeId,boolean bforce, Long traceId);
 
-	void test();
+	void test666();
 
     List<DictBiz> getCarrierTypeByDict();
 

+ 148 - 4
blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveNameServiceImpl.java

@@ -61,12 +61,12 @@ public class ArchiveNameServiceImpl implements IArchiveNameService {
         // 4. 批量获取缺失的祖先节点
         List<ArchiveTreeContract> missingAncestors = Collections.emptyList();
         if (!missingAncestorIds.isEmpty()) {
-            String ancestorIdsStr = missingAncestorIds.stream()
-                    .map(String::valueOf)
-                    .collect(Collectors.joining(","));
+            // 直接使用Set<Long>,无需转换为字符串
+            List<Long> ancestorIdsList = new ArrayList<>(missingAncestorIds);
 
+            // 使用新方法调用
             missingAncestors = archiveTreeContractClient
-                    .getArchiveTreeContractListByIds(ancestorIdsStr);
+                    .getArchiveTreeContractListByList(ancestorIdsList);
 
             for (ArchiveTreeContract ancestor : missingAncestors) {
                 Long ancestorId = ancestor.getId();
@@ -208,6 +208,150 @@ public class ArchiveNameServiceImpl implements IArchiveNameService {
         // 1. 获取输入节点
         Map<Long, ArchiveTreeContract> allNodeMap = hierarchy.getAllNodeMap();
         List<ArchiveTreeContract> nodes = new ArrayList<>();
+        for (Long nodeId : nodeIds) {
+            ArchiveTreeContract node = allNodeMap.get(nodeId);
+            if (node != null) {
+                nodes.add(node);
+            }
+        }
+        if (nodes.isEmpty()) {
+            return "";
+        }
+
+        // 2. 按父节点分组 (一级分组)
+        Map<Long, List<ArchiveTreeContract>> parentGroups = new LinkedHashMap<>();
+        for (ArchiveTreeContract node : nodes) {
+            Long parentId = node.getParentId();
+            if (parentId == null) {
+                parentGroups.put(node.getId(), Collections.singletonList(node));
+            } else {
+                parentGroups.computeIfAbsent(parentId, k -> new ArrayList<>()).add(node);
+            }
+        }
+
+        // 3. 按祖父节点分组 (二级分组)
+        Map<Long, List<Map.Entry<Long, List<ArchiveTreeContract>>>> grandParentGroups = new LinkedHashMap<>();
+        for (Map.Entry<Long, List<ArchiveTreeContract>> entry : parentGroups.entrySet()) {
+            Long parentId = entry.getKey();
+            ArchiveTreeContract parentNode = allNodeMap.get(parentId);
+            Long grandParentId = (parentNode != null) ? parentNode.getParentId() : null;
+            grandParentGroups.computeIfAbsent(grandParentId, k -> new ArrayList<>()).add(entry);
+        }
+
+        // 4. 处理分组
+        List<String> nameParts = new ArrayList<>();
+        for (Map.Entry<Long, List<Map.Entry<Long, List<ArchiveTreeContract>>>> grandEntry : grandParentGroups.entrySet()) {
+            Long grandParentId = grandEntry.getKey();
+            List<Map.Entry<Long, List<ArchiveTreeContract>>> directParentGroups = grandEntry.getValue();
+
+            // 尝试在祖父节点级别合并
+            boolean canUseGrandParentName = false;
+            if (grandParentId != null) {
+                ArchiveTreeContract grandParentNode = allNodeMap.get(grandParentId);
+                if (grandParentNode != null) {
+                    // 获取祖父节点的所有直接子节点
+                    List<ArchiveTreeContract> grandChildren = hierarchy.getChildren(grandParentId);
+                    if (grandChildren != null && !grandChildren.isEmpty()) {
+                        // 检查是否覆盖所有直接子节点
+                        boolean allChildrenCovered = true;
+                        Set<Long> coveredParentIds = new HashSet<>();
+                        for (Map.Entry<Long, List<ArchiveTreeContract>> directEntry : directParentGroups) {
+                            coveredParentIds.add(directEntry.getKey());
+                        }
+
+                        // 验证所有子节点都被覆盖
+                        for (ArchiveTreeContract child : grandChildren) {
+                            if (!coveredParentIds.contains(child.getId())) {
+                                allChildrenCovered = false;
+                                break;
+                            }
+                        }
+
+                        // 验证每个被覆盖的子节点组是否都是全覆盖状态
+                        if (allChildrenCovered) {
+                            boolean allGroupsFullyCovered = true;
+                            for (Map.Entry<Long, List<ArchiveTreeContract>> directEntry : directParentGroups) {
+                                List<ArchiveTreeContract> groupNodes = directEntry.getValue();
+                                // 获取该父节点的所有子节点
+                                List<ArchiveTreeContract> childrenOfParent = hierarchy.getChildren(directEntry.getKey());
+                                int childrenCount = (childrenOfParent != null) ? childrenOfParent.size() : 0;
+
+                                // 检查是否全覆盖
+                                if (childrenCount == 0 || groupNodes.size() != childrenCount) {
+                                    allGroupsFullyCovered = false;
+                                    break;
+                                }
+                            }
+
+                            if (allGroupsFullyCovered) {
+                                nameParts.add(getLevelName(hierarchy, grandParentId));
+                                canUseGrandParentName = true;
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (canUseGrandParentName) {
+                continue; // 已使用祖父节点名称,跳过直接父节点处理
+            }
+
+            // 处理直接父节点组
+            boolean firstParentInGroup = true;
+            for (Map.Entry<Long, List<ArchiveTreeContract>> directEntry : directParentGroups) {
+                Long groupId = directEntry.getKey();
+                List<ArchiveTreeContract> groupNodes = directEntry.getValue();
+                ArchiveTreeContract parent = allNodeMap.get(groupId);
+
+                if (parent == null) {
+                    // 无父节点的情况:添加所有节点名称(用顿号分隔)
+                    String nodeNames = groupNodes.stream()
+                            .map(ArchiveTreeContract::getNodeName)
+                            .collect(Collectors.joining("、"));
+                    nameParts.add(nodeNames);
+                    continue;
+                }
+
+                // 获取直接子节点
+                List<ArchiveTreeContract> allChildren = hierarchy.getChildren(groupId);
+                int childrenCount = (allChildren != null) ? allChildren.size() : 0;
+
+                // 检查是否全覆盖所有子节点
+                if (childrenCount > 0 && groupNodes.size() == childrenCount) {
+                    // 只有组内第一个父节点使用完整层级名称
+                    String parentName = firstParentInGroup ?
+                            getLevelName(hierarchy, groupId) :
+                            parent.getNodeName();
+
+                    nameParts.add(parentName);
+                } else {
+                    // 获取父节点名称
+                    String parentName = firstParentInGroup ?
+                            getLevelName(hierarchy, groupId) :
+                            parent.getNodeName();
+
+                    // 部分覆盖:添加父节点名称+子节点名称(用顿号分隔)
+                    String childNames = groupNodes.stream()
+                            .map(ArchiveTreeContract::getNodeName)
+                            .collect(Collectors.joining("、"));
+                    nameParts.add(parentName + childNames);
+                }
+
+                // 后续节点不再是第一个
+                firstParentInGroup = false;
+            }
+        }
+
+        // 5. 拼接最终结果
+        return String.join("、", nameParts);
+    }
+    public String generateFullLevelName1(
+            List<Long> nodeIds,
+            NodeHierarchy hierarchy
+    ) {
+        // 1. 获取输入节点
+        Map<Long, ArchiveTreeContract> allNodeMap = hierarchy.getAllNodeMap();
+        List<ArchiveTreeContract> nodes = new ArrayList<>();
 
         for (Long nodeId : nodeIds) {
             ArchiveTreeContract node = allNodeMap.get(nodeId);

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

@@ -25,6 +25,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 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.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.itextpdf.text.*;
@@ -150,6 +151,8 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 
 	private final CommonFileClient commonFileClient;
 
+	private final IArchiveNameService archiveNameService;
+
 
 	@Override
 	public IPage<ArchivesAutoVO> selectArchivesAutoPage(IPage<ArchivesAutoVO> page, ArchivesAutoVO archivesAuto) {
@@ -471,51 +474,51 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 					}
 				}
 			}
-			List<ArchivesAutoVO.ApprovalFile> files = vo.getApprovalFileList();;
-			if (files != null) {
-				String tempId = null;
-				if (!files.isEmpty()) {
-					tempId = files.get(0).getId();
+		}
+		List<ArchivesAutoVO.ApprovalFile> files = vo.getApprovalFileList();;
+		if (files != null) {
+			String tempId = null;
+			if (!files.isEmpty()) {
+				tempId = files.get(0).getId();
+			}
+			if (front != null && front.getFileUrl() != null) {
+				if (front.getId() == null && tempId != null) {
+					front.setId(tempId + "_1");
 				}
-				if (front != null && front.getFileUrl() != null) {
-					if (front.getId() == null && tempId != null) {
-						front.setId(tempId + "_1");
-					}
-					if (front.getId() != null) {
-						front.setPdfFileUrl(front.getFileUrl());
-						files.add(0,front);
-					}
+				if (front.getId() != null) {
+					front.setPdfFileUrl(front.getFileUrl());
+					files.add(0,front);
 				}
-				if (cataLog != null && cataLog.getFileUrl() != null) {
-					if (cataLog.getId() == null && tempId != null) {
-						cataLog.setId(tempId  + "_2");
-					}
-					if (cataLog.getId() != null) {
-						cataLog.setPdfFileUrl(cataLog.getFileUrl());
-						if (front != null && front.getFileUrl() != null) {
-							files.add(1,cataLog);
-						} else {
-							files.add(0,cataLog);
-						}
-					}
+			}
+			if (cataLog != null && cataLog.getFileUrl() != null) {
+				if (cataLog.getId() == null && tempId != null) {
+					cataLog.setId(tempId  + "_2");
 				}
-				if (spare != null && spare.getFileUrl() != null) {
-					if (spare.getId() == null && tempId != null) {
-						spare.setId(tempId  + "_3");
-					}
-					if (spare.getId() != null) {
-						spare.setPdfFileUrl(spare.getFileUrl());
-						files.add(spare);
+				if (cataLog.getId() != null) {
+					cataLog.setPdfFileUrl(cataLog.getFileUrl());
+					if (front != null && front.getFileUrl() != null) {
+						files.add(1,cataLog);
+					} else {
+						files.add(0,cataLog);
 					}
 				}
-				if (back != null && back.getFileUrl() != null) {
-					if (back.getId() == null && tempId != null) {
-						back.setId(tempId  + "_4");
-					}
-					if (back.getId() != null) {
-						back.setPdfFileUrl(back.getFileUrl());
-						files.add(back);
-					}
+			}
+			if (spare != null && spare.getFileUrl() != null) {
+				if (spare.getId() == null && tempId != null) {
+					spare.setId(tempId  + "_3");
+				}
+				if (spare.getId() != null) {
+					spare.setPdfFileUrl(spare.getFileUrl());
+					files.add(spare);
+				}
+			}
+			if (back != null && back.getFileUrl() != null) {
+				if (back.getId() == null && tempId != null) {
+					back.setId(tempId  + "_4");
+				}
+				if (back.getId() != null) {
+					back.setPdfFileUrl(back.getFileUrl());
+					files.add(back);
 				}
 			}
 		}
@@ -1290,6 +1293,83 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		}
 	}
 
+
+	private String builtArchiveName_new(List<ArchiveFile> waitArchiveFiles, ArchiveTreeContract node, boolean isCrossNode
+	,IArchiveNameService.NodeHierarchy nameInfo) {
+
+		String archiveName = "";
+
+		Long projectId = node.getProjectId();
+		ProjectInfo projectInfo = projectClient.getById(String.valueOf(projectId));
+		String projectName = projectInfo.getProjectName();
+		String contractName = "";
+		Long contractId = node.getContractId();
+		if (contractId != null && contractId != -1) {
+			ContractInfo contract = contractClient.getContractById(contractId);
+			contractName = contract.getContractName();
+		}
+		//获取案卷题名
+		archiveName = projectName;
+		if (StringUtils.isNotEmpty(contractName)) {
+			archiveName = archiveName + contractName;
+		}
+
+
+		//--正常节点
+		Set<String> uniqueNodeIds = waitArchiveFiles.stream()
+				.map(ArchiveFile::getNodeId)
+				.filter(nodeId -> nodeId != null && !nodeId.isEmpty())
+				.collect(Collectors.toCollection(LinkedHashSet::new));
+
+		// 2. 将节点ID从String转换为Long(保持原始顺序)
+		List<Long> nodeIds = uniqueNodeIds.stream()
+				.map(this::safeParseLong)
+				.filter(Objects::nonNull)
+				.collect(Collectors.toList());
+
+
+		String fullPath =  archiveNameService.generateFullLevelName(nodeIds, nameInfo);
+
+		archiveName+=fullPath;
+
+//		if (archiveName.length() > 200) {
+//			// 从150位置开始查找第一个顿号
+//			int index = archiveName.indexOf('、', 200);
+//			if (index != -1) {
+//				// 找到顿号,截取到顿号位置(去掉顿号)并拼接“等文件”
+//				archiveName = archiveName.substring(0, index) + "等文件";
+//			} else {
+//				// 没有找到顿号,直接截取150个字符并拼接“等文件”
+//				archiveName = archiveName.substring(0, 200) + "等文件";
+//			}
+//		}
+
+		if (archiveName.length() > 1100) {
+			// 直接截取前1100个字符
+			archiveName = archiveName.substring(0, 1100);
+		}
+
+
+		//TODO wbs节点
+		//不存在跨节点 项目名称+案卷题名规则(在后台归档目录树设置的)+后缀
+		//存在跨节点  获取当前所有节点的父级节点题名规则+所有同层级跨节点并卷的节点名称拼接+后缀
+		String archiveNameSuffix = node.getArchiveNameSuffix();
+		if (archiveNameSuffix == null || archiveNameSuffix.equals("null")) {
+			archiveNameSuffix = "";
+		}
+		return archiveName + archiveNameSuffix;
+	}
+
+	// 安全解析Long的方法(处理格式异常)
+	private Long safeParseLong(String value) {
+		try {
+			return Long.parseLong(value);
+		} catch (NumberFormatException e) {
+			log.warn("无法转换的节点ID格式: {}", value);
+			return null;
+		}
+	}
+
 	private String builtArchiveName(List<ArchiveFile> waitArchiveFiles, ArchiveTreeContract node, boolean isCrossNode) {
 
 		String archiveName = "";
@@ -1400,29 +1480,94 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		}
 		archiveFileClient.updateArchiveFileForCreateArchive(waitArchiveFiles);
 		try {
-			for (ArchiveFile saveVo : waitArchiveFiles) {
-				metadataClassificationClient.createMetadataFile(saveVo.getId(), 0);
-			}
+//			for (ArchiveFile saveVo : waitArchiveFiles) {
+//				metadataClassificationClient.createMetadataFile(saveVo.getId(), 0);
+//			}
+			batchCreateMetadataFiles(waitArchiveFiles);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * 单独组卷规则组卷
+	 *
+	 * @param waitArchiveFiles
+	 * @param node             规格参数所在节点
+	 * @param pageN
+	 */
+	private void createArchive3_new(List<ArchiveFile> waitArchiveFiles, ArchiveTreeContract node, int pageN,IArchiveNameService.NodeHierarchy nameInfo) {
+
+		String archiveStartDateAndEndDate = getArchiveStartDateAndEndDate(waitArchiveFiles);
+		String[] split = archiveStartDateAndEndDate.split(",");
+		String startDate = split.length >= 1 ? split[0] : "";
+		String endDate = split.length >= 2 ? split[1] : "";
+		int fileN = waitArchiveFiles.size();
+		if (fileN == 0) {
+			return;
+		}
+
+		String archiveName = builtArchiveName_new(waitArchiveFiles, node, false,nameInfo);//获取案卷题名
+		//1.创建新案卷
+		ArchivesAuto archivesAuto = builtArchives(node, pageN, fileN, startDate, endDate, archiveName);
+		//2.设置文件所属案卷,组卷状态
+		Long archivesAutoId = archivesAuto.getId();
+
+		//封面和生成文件页码
+		archiveAutoPdfService.buildArchiveFrontPdfs(archivesAuto.getProjectId(), archivesAuto, waitArchiveFiles, false);
+
+		builtFilePageNo(archivesAuto, waitArchiveFiles);//生成文件页码
+
+
+		for (ArchiveFile file : waitArchiveFiles) {
+			file.setArchiveId(archivesAutoId);//设置文件所属案卷
+			file.setIsArchive(1);
+
+		}
+		archiveFileClient.updateArchiveFileForCreateArchive(waitArchiveFiles);
+		try {
+//			for (ArchiveFile saveVo : waitArchiveFiles) {
+//				metadataClassificationClient.createMetadataFile(saveVo.getId(), 0);
+//			}
+			batchCreateMetadataFiles(waitArchiveFiles);
 		} catch (Exception e) {
 			e.printStackTrace();
 		}
 	}
 
+
+
 	/**
 	 * 分类并卷组卷
 	 *
 	 * @param waitArchiveFiles
 	 * @param archiveAutoGroupId 分类并卷分组ID
 	 */
-	private void createArchive2(List<ArchiveFile> waitArchiveFiles, Long archiveAutoGroupId, Long projectId) {
+	private void createArchive2(List<ArchiveFile> waitArchiveFiles, Long archiveAutoGroupId, Long projectId,IArchiveNameService.NodeHierarchy nameInfo) {
 
 		//获取同一分类archiveAutoGroupId下设置的(设置规则时选中的)节点,排好序
-		List<ArchiveTreeContract> selectList = archiveTreeContractClient.getStorageNodeByGroupId(projectId, archiveAutoGroupId);
-		//分类并卷节点默认采用同类型下第一个存储节点为归属节点
-		if (selectList== null || selectList.size() == 0) {
+//		List<ArchiveTreeContract> selectList = archiveTreeContractClient.getStorageNodeByGroupId(projectId, archiveAutoGroupId);
+//		//分类并卷节点默认采用同类型下第一个存储节点为归属节点
+//		if (selectList== null || selectList.size() == 0) {
+//			return;
+//		}
+
+		if (waitArchiveFiles==null || waitArchiveFiles.size()== 0) {
 			return;
 		}
-		ArchiveTreeContract node = selectList.get(0);
+
+		String strfirstNodeId = waitArchiveFiles.get(0).getNodeId();
+
+		ArchiveTreeContract node = null;
+		if (StringUtils.isNotEmpty(strfirstNodeId)) {
+			Long firstNodeId = Long.parseLong(strfirstNodeId);
+			ArchiveTreeContract firstNode = archiveTreeContractClient.getArchiveTreeContractById(firstNodeId);
+			if (firstNode!= null) {
+				node = firstNode;
+			}
+		}
+
+
 		//获取案卷文件起止时间
 		String archiveStartDateAndEndDate = getArchiveStartDateAndEndDate(waitArchiveFiles);
 		String[] split = archiveStartDateAndEndDate.split(",");
@@ -1440,7 +1585,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		}
 		//默认组卷存在跨节点组卷  注意案卷归属节点,案卷命名方式
 		//获取案卷题名
-		String archiveName = builtArchiveName(waitArchiveFiles, node, true);//获取案卷题名
+		String archiveName = builtArchiveName_new(waitArchiveFiles, node, true,nameInfo);//获取案卷题名
 
 		//1.创建新案卷
 		ArchivesAuto archivesAuto = builtArchives(node, pageN, fileN, startDate, endDate, archiveName);
@@ -1458,9 +1603,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		}
 		archiveFileClient.updateArchiveFileForCreateArchive(waitArchiveFiles);
 		try {
-			for (ArchiveFile saveVo : waitArchiveFiles) {
-				metadataClassificationClient.createMetadataFile(saveVo.getId(), 0);
-			}
+			batchCreateMetadataFiles(waitArchiveFiles);
 		} catch (Exception e) {
 			e.printStackTrace();
 		}
@@ -1507,9 +1650,10 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		}
 		archiveFileClient.updateArchiveFileForCreateArchive(waitArchiveFiles);
 		try {
-			for (ArchiveFile saveVo : waitArchiveFiles) {
-				metadataClassificationClient.createMetadataFile(saveVo.getId(), 0);
-			}
+//			for (ArchiveFile saveVo : waitArchiveFiles) {
+//				metadataClassificationClient.createMetadataFile(saveVo.getId(), 0);
+//			}
+			batchCreateMetadataFiles(waitArchiveFiles);
 		} catch (Exception e) {
 			e.printStackTrace();
 		}
@@ -1562,9 +1706,10 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		}
 		archiveFileClient.updateArchiveFileForCreateArchive(waitArchiveFiles);
 		try {
-			for (ArchiveFile saveVo : waitArchiveFiles) {
-				metadataClassificationClient.createMetadataFile(saveVo.getId(), 0);
-			}
+//			for (ArchiveFile saveVo : waitArchiveFiles) {
+//				metadataClassificationClient.createMetadataFile(saveVo.getId(), 0);
+//			}
+			batchCreateMetadataFiles(waitArchiveFiles);
 		} catch (Exception e) {
 			e.printStackTrace();
 		}
@@ -1669,6 +1814,10 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 
 	private void archiveAutoMethod3(List<ArchiveTreeContract> list, Map<String, List<ArchiveFile>> boxMap,
 									Map<Long, String> boxFileMap, Long traceId) {
+
+		// 4. 构建节点层级关系
+		IArchiveNameService.NodeHierarchy nameInfo =
+				archiveNameService.buildNodeHierarchy(list);
 		// 步骤1:遍历节点集合
 		for (ArchiveTreeContract node : list) {
 			// 步骤2:获取当前节点的案卷规格
@@ -1704,7 +1853,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 
 					// 如果是最后一个文件且有待组卷文件,则组卷
 					if (archiveFilesSize == archiveFiles.size() && !waitArchiveFiles.isEmpty()) {
-						createArchive3(waitArchiveFiles, node, archivesSize);
+						createArchive3_new(waitArchiveFiles, node, archivesSize,nameInfo);
 						waitArchiveFiles.clear();
 						archivesSize = 0;
 					}
@@ -1723,7 +1872,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 
 						// 最后一个文件直接组卷
 						if (archiveFilesSize == archiveFiles.size()) {
-							createArchive3(waitArchiveFiles, node, archivesSize);
+							createArchive3_new(waitArchiveFiles, node, archivesSize,nameInfo);
 							waitArchiveFiles.clear();
 							archivesSize = 0;
 						}
@@ -1732,7 +1881,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 					else if (checkStatus == 1) {
 						waitArchiveFiles.add(file);
 						archivesSize = tempTotalSize;
-						createArchive3(waitArchiveFiles, node, archivesSize);
+						createArchive3_new(waitArchiveFiles, node, archivesSize,nameInfo);
 
 						// 重置待组卷集合
 						waitArchiveFiles.clear();
@@ -1742,7 +1891,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 					else if (checkStatus == -1) {
 						if (!waitArchiveFiles.isEmpty()) {
 							// 先将现有集合组卷(不含当前文件)
-							createArchive3(waitArchiveFiles, node, archivesSize);
+							createArchive3_new(waitArchiveFiles, node, archivesSize,nameInfo);
 
 							// 新建集合存放当前文件
 							waitArchiveFiles.clear();
@@ -1751,7 +1900,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 
 							// 最后一个文件直接组卷
 							if (archiveFilesSize == archiveFiles.size()) {
-								createArchive3(waitArchiveFiles, node, archivesSize);
+								createArchive3_new(waitArchiveFiles, node, archivesSize,nameInfo);
 								waitArchiveFiles.clear();
 								archivesSize = 0;
 							}
@@ -1759,7 +1908,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 							// 当前文件单独成卷
 							waitArchiveFiles.add(file);
 							archivesSize = filePage;
-							createArchive3(waitArchiveFiles, node, archivesSize);
+							createArchive3_new(waitArchiveFiles, node, archivesSize,nameInfo);
 
 							// 重置集合
 							waitArchiveFiles.clear();
@@ -1873,15 +2022,19 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 			//一个archiveAutoGroupId组成一个案卷  案卷归属同个key的归档树节点select=1的第一个groupId2NodeIdMap
 			//createArchive2(archiveFiles, archiveAutoGroupId, projectId);
 
-			archiveAutoMethodGroup(archiveFiles, archiveAutoGroupId, projectId);
+			archiveAutoMethodGroup(archiveFiles, archiveAutoGroupId, projectId,null);
 		}
 
 	}
 
-
 	private void archiveAutoMethod2_new(List<ArchiveTreeContract> list, List<ArchiveTreeContract> topList, Long projectId,
 										Map<String, List<ArchiveFile>> boxMap, Map<Long, String> boxFileMap, Long traceId) {
 
+		// 构建TOP节点ID集合(提前计算提高效率)
+		Set<Long> topIdSet = topList.stream()
+				.map(ArchiveTreeContract::getId)
+				.collect(Collectors.toSet());
+
 		// 分类并卷集合<groupId, List<文件>>
 		Map<Long, List<ArchiveFile>> archiveMap = new LinkedHashMap<>();
 		// 记录同个分组id对应的第一个节点ID(案卷归属节点)
@@ -1892,6 +2045,114 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		// 当前顶层节点对应的分组ID
 		Long currArchiveAutoGroupId = null;
 
+		// 4. 构建节点层级关系
+		IArchiveNameService.NodeHierarchy nameInfo =
+				archiveNameService.buildNodeHierarchy(list);
+
+		// 步骤1:遍历节点集合
+		for (ArchiveTreeContract node : list) {
+			// 初始化当前节点的分组ID和顶层节点ID
+			Long archiveAutoGroupId = node.getArchiveAutoGroupId();
+			Long nodeTopId = 0L;
+
+			String ancestors = node.getAncestors();
+			if (ancestors != null && !ancestors.trim().isEmpty()) {
+				// 分割祖先字符串并转换为Long列表
+				List<Long> ancestorIds = Arrays.stream(ancestors.split(","))
+						.map(String::trim)
+						.filter(s -> !s.isEmpty())
+						.map(s -> {
+							try {
+								return Long.parseLong(s);
+							} catch (NumberFormatException e) {
+								return null;
+							}
+						})
+						.filter(Objects::nonNull)
+						.collect(Collectors.toList());
+
+				// 从上到下遍历:根节点(开始) → 最近祖先(末尾)
+				// 查找最后一个匹配的TOP节点(离当前节点最近的)
+				for (int i = ancestorIds.size() - 1; i >= 0; i--) {
+					Long ancestorId = ancestorIds.get(i);
+					if (topIdSet.contains(ancestorId)) {
+						nodeTopId = ancestorId;
+						break;
+					}
+				}
+			}
+			// =========== 关键修改结束 ===========
+
+			// 步骤3:确定当前节点的分组ID
+			if (curTopId != null && curTopId.equals(nodeTopId) && nodeTopId != 0) {
+				// 如果属于同一个非零顶层节点,使用之前的分组ID
+				archiveAutoGroupId = currArchiveAutoGroupId;
+			} else {
+				// 新顶层节点或没有顶层节点,更新当前分组信息
+				curTopId = nodeTopId;
+				currArchiveAutoGroupId = archiveAutoGroupId;
+			}
+
+			// 步骤4:查询节点下的未归档文件(保持原逻辑)
+			List<ArchiveFile> archiveFiles = archiveFileClient.getListByNodeID(node.getId().toString());
+
+			if (archiveFiles != null && !archiveFiles.isEmpty()) {
+				// 记录日志(每个节点只记录一次)
+				String completeMsg = "[自动组卷] 分类组卷:" + "-traceId:" + traceId + "节点:" + node.getNodeName() + " 文件数量:" + archiveFiles.size();
+				iTraceLogService.saveLog(traceId, completeMsg);
+
+				// 步骤5:遍历未归档文件
+				for (ArchiveFile file : archiveFiles) {
+					// 步骤6:判断文件是否存在分盒设置
+					if (file.getBoxNumber() != null && file.getBoxNumber() != -1) {
+						// 添加到分盒文件集合
+						addBoxMap(file, boxMap, boxFileMap);
+					} else {
+						// 分类并卷流程
+						// 步骤7:将文件按照<groupId,List<文件>>放入集合
+						//改用top分组了
+						archiveAutoGroupId = curTopId;
+						if (archiveMap.containsKey(archiveAutoGroupId)) {
+							List<ArchiveFile> groupList = archiveMap.get(archiveAutoGroupId);
+							groupList.add(file);
+						} else {
+							List<ArchiveFile> groupList = new ArrayList<>();
+							groupList.add(file);
+							archiveMap.put(archiveAutoGroupId, groupList);
+							groupId2NodeIdMap.put(archiveAutoGroupId, node.getId());
+						}
+					}
+				}
+			}
+		}
+
+		// 步骤8:按集合创建案卷(保持原逻辑)
+		for (Map.Entry<Long, List<ArchiveFile>> entry : archiveMap.entrySet()) {
+			Long archiveAutoGroupId = entry.getKey();
+			List<ArchiveFile> archiveFiles = entry.getValue();
+
+			// 同一个分组ID下的文件分组组卷
+			archiveAutoMethodGroup(archiveFiles, archiveAutoGroupId, projectId,nameInfo);
+		}
+	}
+
+	private void archiveAutoMethod2_new1(List<ArchiveTreeContract> list, List<ArchiveTreeContract> topList, Long projectId,
+										Map<String, List<ArchiveFile>> boxMap, Map<Long, String> boxFileMap, Long traceId) {
+
+		// 分类并卷集合<groupId, List<文件>>
+		Map<Long, List<ArchiveFile>> archiveMap = new LinkedHashMap<>();
+		// 记录同个分组id对应的第一个节点ID(案卷归属节点)
+		Map<Long, Long> groupId2NodeIdMap = new HashMap<>();
+
+		// 当前处理的顶层节点ID
+		Long curTopId = null;
+		// 当前顶层节点对应的分组ID
+		Long currArchiveAutoGroupId = null;
+
+		// 4. 构建节点层级关系
+		IArchiveNameService.NodeHierarchy nameInfo =
+				archiveNameService.buildNodeHierarchy(list);
+
 		// 步骤1:遍历节点集合
 		for (ArchiveTreeContract node : list) {
 			// 初始化当前节点的分组ID和顶层节点ID
@@ -1956,11 +2217,15 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 			List<ArchiveFile> archiveFiles = entry.getValue();
 
 			// 同一个分组ID下的文件分组组卷
-			archiveAutoMethodGroup(archiveFiles, archiveAutoGroupId, projectId);
+			archiveAutoMethodGroup(archiveFiles, archiveAutoGroupId, projectId,nameInfo);
 		}
 	}
 
-	private void archiveAutoMethodGroup(List<ArchiveFile> archiveFiles, Long archiveAutoGroupId, Long projectId) {
+
+
+
+
+	private void archiveAutoMethodGroup(List<ArchiveFile> archiveFiles, Long archiveAutoGroupId, Long projectId,IArchiveNameService.NodeHierarchy nameInfo) {
 		if (archiveFiles.size()==0) {
 			return;
 		}
@@ -2008,13 +2273,13 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 					waitArchiveFiles.add(file);
 					archivesSize = tempTotalSize;
 					if (fileIndex == totalFiles) { // 是最后一个文件
-						createArchive2(waitArchiveFiles, archiveAutoGroupId, projectId);
+						createArchive2(waitArchiveFiles, archiveAutoGroupId, projectId,nameInfo);
 					}
 					break;
 
 				case 1: // 达到规格
 					waitArchiveFiles.add(file);
-					createArchive2(waitArchiveFiles, archiveAutoGroupId, projectId);
+					createArchive2(waitArchiveFiles, archiveAutoGroupId, projectId,nameInfo);
 					waitArchiveFiles = new ArrayList<>();
 					archivesSize = 0;
 					break;
@@ -2022,10 +2287,10 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 				case -1: // 超出规格
 					if (waitArchiveFiles.isEmpty()) {
 						// 当前文件单独成卷
-						createArchive2(Collections.singletonList(file), archiveAutoGroupId, projectId);
+						createArchive2(Collections.singletonList(file), archiveAutoGroupId, projectId,nameInfo);
 					} else {
 						// 先将现有文件组卷
-						createArchive2(waitArchiveFiles, archiveAutoGroupId, projectId);
+						createArchive2(waitArchiveFiles, archiveAutoGroupId, projectId,nameInfo);
 
 						// 创建新的待组卷集合
 						waitArchiveFiles = new ArrayList<>();
@@ -2033,7 +2298,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 						archivesSize = filePage;
 
 						if (fileIndex == totalFiles) { // 是最后一个文件
-							createArchive2(waitArchiveFiles, archiveAutoGroupId, projectId);
+							createArchive2(waitArchiveFiles, archiveAutoGroupId, projectId,nameInfo);
 						}
 					}
 					break;
@@ -2922,7 +3187,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 	}
 
 
-	public void test() {
+	public void test666() {
 		Long projectId = 0L;
 		List<ArchiveTreeContract> archiveTreeContracts = archiveTreeContractClient.getListByProjectId(projectId);
 

+ 1 - 1
blade-service/blade-business/pom.xml

@@ -194,7 +194,7 @@
                     <target>${java.version}</target>
                     <encoding>${project.build.sourceEncoding}</encoding>
                     <compilerArguments>
-                        <bootclasspath>${java.home}/lib/rt.jar;${java.home}/lib/jce.jar;${java.home}/lib/jsse.jar
+                        <bootclasspath>${java.home}/lib/rt.jar:${java.home}/lib/jce.jar:${java.home}/lib/jsse.jar
                         </bootclasspath>
                     </compilerArguments>
                 </configuration>

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

@@ -711,8 +711,14 @@ public class MetadataClassificationServiceImpl
             if (!uniqueNodeIds.isEmpty()) {
                 try {
                     // 1. 批量获取所有节点
-                    String nodeIdsStr = String.join(",", uniqueNodeIds);
-                    List<ArchiveTreeContract> nodeList = archiveTreeContractClient.getArchiveTreeContractListByIds(nodeIdsStr);
+                    // 1. 将字符串ID转换为Long列表
+                    List<Long> nodeIdList = uniqueNodeIds.stream()
+                            .map(Long::valueOf) // 将字符串转换为Long
+                            .collect(Collectors.toList());
+
+                    // 2. 使用新方法批量获取节点
+                    List<ArchiveTreeContract> nodeList = archiveTreeContractClient
+                            .getArchiveTreeContractListByList(nodeIdList);
 
                     // 2. 直接使用nodeList中的节点(避免重复添加当前节点ID)
                     Map<Long, ArchiveTreeContract> allAncestorsMap = new HashMap<>();

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

@@ -1788,7 +1788,8 @@ public class TaskServiceImpl extends BaseServiceImpl<TaskMapper, Task> implement
                 } else //电签完成
                 {
                     try {
-                        archiveTreeContractClient.writeBusinessData(query.getWbsId(), query.getContractId(), formDataId, query.getClassify());
+                        //组卷前同步即可
+                        //archiveTreeContractClient.writeBusinessData(query.getWbsId(), query.getContractId(), formDataId, query.getClassify());
                     } catch (Exception e) {
                     }
                 }

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

@@ -16,6 +16,7 @@ import org.springblade.business.entity.WeatherInfo;
 import org.springblade.business.mapper.WeatherInfoMapper;
 import org.springblade.business.service.WeatherInfoService;
 import org.springblade.common.utils.BaiduApiUtil;
+import org.springblade.common.utils.SystemUtils;
 import org.springblade.common.utils.YiKeYunApiUtils;
 import org.springblade.core.mp.support.Condition;
 import org.springblade.core.tool.utils.DateUtil;
@@ -121,6 +122,9 @@ public class WeatherInfoServiceImpl extends ServiceImpl<WeatherInfoMapper, Weath
      */
     @Scheduled(cron = "0 18 10 * * ?")
     public void syncWeatherInfo() {
+        if (!SystemUtils.isLinux()) {
+            return;
+        }
         //获取所有合同段的定位信息
         List<ProjectContractArea> areaList = this.projectContractAreaClient.queryAllContractArea();
         Map<String, Map<String, String>> cachedWeatherMap = new HashMap<>();
@@ -176,6 +180,9 @@ public class WeatherInfoServiceImpl extends ServiceImpl<WeatherInfoMapper, Weath
      */
     @Scheduled(cron = "0 0 8 * * ?")
     public void syncHistoryWeatherInfo() {
+        if (!SystemUtils.isLinux()) {
+            return;
+        }
         //获取所有合同段的定位信息
         List<ProjectContractArea> areaList = this.projectContractAreaClient.queryAllContractArea();
 
@@ -290,6 +297,9 @@ public class WeatherInfoServiceImpl extends ServiceImpl<WeatherInfoMapper, Weath
     //去除重复天气,并填充每个合同段缺失的天气
     @Scheduled(cron = "0 0 9 * * ?")
     public void scanMissWeather(){
+        if (!SystemUtils.isLinux()) {
+            return;
+        }
         //获取所有项目的合同段
         List<ContractInfoVO> contractInfos = baseMapper.getAllContract();
         for (ContractInfoVO contract : contractInfos) {

+ 137 - 51
blade-service/blade-e-visa/src/main/java/org/springblade/evisa/controller/ArchiveController.java

@@ -22,10 +22,12 @@ import org.springframework.data.redis.core.StringRedisTemplate;
 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.RestController;
 
 import javax.annotation.Resource;
 import java.io.*;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CompletableFuture;
@@ -76,7 +78,7 @@ public class ArchiveController {
                     if (!aBoolean) {
 
                         if (!aBoolean) {
-                            RedisTemplate.opsForValue().set("splitpng-" + dataInfo.getArchiveId(), "1", 7200, TimeUnit.SECONDS);
+                            RedisTemplate.opsForValue().set("splitpng-" + dataInfo.getArchiveId(), "1", 600, TimeUnit.SECONDS);
                             CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> {
                                 try {
                                     /*===============执行批量任务===============*/
@@ -103,35 +105,55 @@ public class ArchiveController {
             String archiveId = taskSign.getArchiveId();
             String id = taskSign.getId();
             String taskId = taskSign.getTaskId();
+            List<String> listPdf = new ArrayList<>();
+            int startPage = 0;
+            for (int i = 2; i <= 10; i++) {
+                // 获取pdf第二页的数据
+                String firstUrl = FileUtils.getSysLocalFileUrl() + "archiveSplit/" + archiveId + "first__"+i+"__.pdf";
+                File file = new File(firstUrl);
+                if (!file.exists()) {
+                    getPdfByPage(i, i, fileUrl, firstUrl);
+                }
 
-            // 获取pdf第二页的数据
-            String firstUrl = FileUtils.getSysLocalFileUrl() + "archiveSplit/" + archiveId + "_001.pdf";
-            File file = new File(firstUrl);
-            if (!file.exists()) {
-                getPdfByPage(2, 2, fileUrl, firstUrl);
-            }
-
-            // 保存第一页为300DPI图片
-            String imagePath = FileUtils.getSysLocalFileUrl() + "archiveSplit/" + archiveId + "_001.png";
-            File imgfile = new File(imagePath);
-            if (!imgfile.exists()) {
-                savePdfAsImage(1, firstUrl, imagePath);
+                // 保存第一页为300DPI图片
+                String imagePath = FileUtils.getSysLocalFileUrl() + "archiveSplit/" + archiveId + "first__"+i+"__.png";
+                File imgfile = new File(imagePath);
+                if (!imgfile.exists()) {
+                    savePdfAsImage(1, firstUrl, imagePath);
+                }
+                // 删除pdf
+                file.delete();
+                String state = OcrTitle(imagePath,"1");
+                if(state.equals("1")){
+                    if(startPage<2){
+                        startPage = i ;
+                    }
+                    listPdf.add(imagePath);
+                }else{
+                    imgfile.delete();
+                    break;
+                }
             }
-
+            System.out.println(listPdf.size());
+            String filePath = startPage+"--"+(listPdf.size()+1);
             //判断
             List<Map<String, Object>> mapList = jdbcTemplate.queryForList("select * from u_archives_split_info where id=" + id + "");
             if (mapList != null && Func.isNotEmpty(mapList) && mapList.size() >= 1) {
                 String status = mapList.get(0).get("status") + "";
                 if (status.equals("3")) {
-                    String updateSql = "update u_archives_auto set split_status=1 where id=" + id;
+                    String updateSql = "update u_archives_auto set split_status=1 where id=" + archiveId;
                     jdbcTemplate.execute(updateSql);
                 }
             } else {
-                String sql22 = "insert into u_archives_split_info(id,status,file_url,first_file_url,task_id,archive_id,create_time) VALUES(" + id + ",2,'" + fileUrl + "','" + imagePath + "'," + taskId + "," + archiveId + ",SYSDATE())";
+                String sql22 = "insert into u_archives_split_info(id,status,file_url,first_file_url,task_id,archive_id,create_time) VALUES(" + id + ",2,'" + fileUrl + "','" + filePath + "'," + taskId + "," + archiveId + ",SYSDATE())";
                 jdbcTemplate.execute(sql22);
-                String updateSql = "update u_archives_auto set split_status=2 where id=" + id;
+                String updateSql = "update u_archives_auto set split_status=2 where id=" + archiveId;
                 jdbcTemplate.execute(updateSql);
             }
+
+            String sql = "delete from u_archive_file where id<>'"+id+"' and archive_id='"+archiveId+"'";
+            jdbcTemplate.execute(sql);
+
             RedisTemplate.delete("splitpng-" + archiveId);
         } catch (Exception e) {
             e.printStackTrace();
@@ -154,7 +176,7 @@ public class ArchiveController {
                     if (!aBoolean) {
 
                         if (!aBoolean) {
-                            RedisTemplate.opsForValue().set("splithtml-" + dataInfo.getArchiveId(), "1", 600, TimeUnit.SECONDS);
+                            RedisTemplate.opsForValue().set("splithtml-" + dataInfo.getArchiveId(), "1", 1200, TimeUnit.SECONDS);
                             CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> {
                                 try {
                                     /*===============执行批量任务===============*/
@@ -179,72 +201,103 @@ public class ArchiveController {
             String archiveId = taskSign.getArchiveId();
             String fileUlr = taskSign.getFileUrl();
             String firstPage = FileUtils.getSysLocalFileUrl() + "archiveSplit/";
+            String firstFileUrl = taskSign.getFirstFileUrl();
+            String firstUrl[] = firstFileUrl.split("--");
+            int basePage = Integer.parseInt(firstUrl[1]);
+            int baseStart = Integer.parseInt(firstUrl[0]);
+            String dutyUser = "";
             int bkb = 0 ;
             //将imagePath 的数据转成一个可解析的html
-            String htmlUrl = pngToHtml(firstPage, archiveId);
-            /*String htmlUrl2 = pngToHtml(firstPage, archiveId);
-            String htmlUrl = "";
-            if (htmlUrl1.equals(htmlUrl2) && htmlUrl1.indexOf("_001.html") >= 0 && htmlUrl1.indexOf("archiveSplit") >= 0) {
-                htmlUrl = htmlUrl2;
-            }*/
+            String htmlUrl = pngToHtml(firstPage, archiveId,taskSign.getFirstFileUrl());
+
 
             if (htmlUrl.indexOf("_001.html") >= 0 && htmlUrl.indexOf("archiveSplit") >= 0) {
                 String htmlString = IoUtil.readToString(new FileInputStream(htmlUrl));
                 Document doc = Jsoup.parse(htmlString);
                 Element table = doc.select("table").first();
                 Elements trs = table.select("tr");
+                //由于解析已经成功,可能数据已经分解过,需要删除
+                if(trs!=null && trs.size()>=1){
+                    String sql = "delete from u_archive_file where id<>'"+taskSign.getId()+"' and archive_id='"+archiveId+"'";
+                    jdbcTemplate.execute(sql);
+                }
 
-                for (int i = 1; i <= trs.size() - 1; i++) {
+                for (int i = 0; i <= trs.size() - 1; i++) {
                     Element tr = trs.get(i);
                     String zrz = tr.select("td").get(0).text();
                     String wjtm = tr.select("td").get(1).text();
                     String rq = tr.select("td").get(2).text();
                     String ym = tr.select("td").get(3).text();
+                   if(zrz.equals("责任者") && wjtm.equals("文件题名") && rq.equals("日期")){
+                        continue;
+                   }
                     int startYm = 0;
                     int endYm = 0;
                     if(i<trs.size()-1){
                         startYm = Func.toInt(ym);
                         String enData = trs.get(i+1).select("td").get(3).text();
-                        if(enData.indexOf("-")>=0){
-                            endYm = Func.toInt(enData.split("-")[0])-1;
-                        }else{
-                            endYm = Func.toInt(enData)-1;
+                        if(enData.indexOf("页")>=0){
+                            enData = trs.get(i+2).select("td").get(3).text();
+                        }
+
+                        String[] parts = enData.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
+                        if(parts!=null && parts.length>=1){
+                            endYm = Func.toInt(parts[0]);
                         }
                     }else{
-                        if(ym.indexOf("-")>=0){
-                            String[] split = ym.split("-");
+                        String[] split = ym.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
+                        if(split!=null && split.length>=3){
                             startYm = Func.toInt(split[0]);
-                            endYm = Func.toInt(split[1]);
+                            endYm = Func.toInt(split[2]);
+                        }else{
+                            startYm = Func.toInt(split[0]);
+                            endYm = Func.toInt(split[0]);
                         }
                     }
-                    startYm = startYm + 2 ;
-                    endYm = endYm + 2 ;
-                    System.out.println(zrz + " " + wjtm + " " + rq + " " + ym);
+                    startYm = basePage+startYm ;
+                    endYm = basePage+endYm ;
+                    dutyUser = zrz;
+                    System.out.println("序号="+i+"--文件提名:"+wjtm +"--开始("+startYm+"-"+endYm+")---页数"+(endYm-startYm+1));
                     // 分解文件
                     String fmlUrl = FileUtils.getSysLocalFileUrl() + "archiveSplit/"+archiveId+"_cf_00"+i+".pdf";
                     getPdfByPage(startYm,endYm,fileUlr,fmlUrl);
-                    saveDataToMysql(fmlUrl,wjtm,taskSign.getId(),endYm-startYm+1);
+                    saveDataToMysql(fmlUrl,wjtm,taskSign.getId(),endYm-startYm+1,i,zrz);
                     bkb =  endYm ;
                 }
-
             } else {
-
+                return;
             }
 
             // 添加封面信息
             String fmlUrl = FileUtils.getSysLocalFileUrl() + "archiveSplit/"+archiveId+"_fm_001.pdf";
             getPdfByPage(1,1,fileUlr,fmlUrl);
-            saveDataToMysql(fmlUrl,"封面",taskSign.getId(),1);
+            saveDataToMysql(fmlUrl,"封面",taskSign.getId(),1,-4,dutyUser);
 
             // 卷内目录
             String jnmuUrl = FileUtils.getSysLocalFileUrl() + "archiveSplit/"+archiveId+"_jnml_001.pdf";
-            getPdfByPage(2,2,fileUlr,jnmuUrl);
-            saveDataToMysql(jnmuUrl,"卷内目录",taskSign.getId(),1);
+            getPdfByPage(baseStart,basePage,fileUlr,jnmuUrl);
+            saveDataToMysql(jnmuUrl,"卷内目录",taskSign.getId(),1,-3,dutyUser);
 
             // 卷内备考表
             String jnbkbUrl = FileUtils.getSysLocalFileUrl() + "archiveSplit/"+archiveId+"_jnbkb_001.pdf";
             getPdfByPage(bkb+1,bkb+1,fileUlr,jnbkbUrl);
-            saveDataToMysql(jnbkbUrl,"卷内备考表",taskSign.getId(),1);
+            saveDataToMysql(jnbkbUrl,"卷内备考表",taskSign.getId(),1,100,dutyUser);
+
+            // 背脊表
+            String bjbUrl = FileUtils.getSysLocalFileUrl() + "archiveSplit/"+archiveId+"_beiji_001.pdf";
+            String bjbUrlPng = FileUtils.getSysLocalFileUrl() + "archiveSplit/"+archiveId+"_beiji_001.png";
+            getPdfByPage(bkb+2,bkb+2,fileUlr,bjbUrl);
+
+            File bgImgFile = new File(bjbUrl);
+            if (!bgImgFile.exists()) {
+                savePdfAsImage(1, bjbUrl, bjbUrlPng);
+            }
+            String state = OcrTitle(bjbUrl,"3");
+            if(state.equals("1")){
+                saveDataToMysql(jnbkbUrl,"背脊表",taskSign.getId(),1,101,dutyUser);
+            }
+            bgImgFile.delete();
+
 
             // 修改任务状态
             String updateSql = "update u_archives_split_info set status=3 where id=" + taskSign.getId();
@@ -260,20 +313,19 @@ public class ArchiveController {
             jdbcTemplate.execute(taxkSql2);
 
             // 修改完成情况
-
             RedisTemplate.delete("splithtml-" + archiveId);
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
     }
 
-    public static String pngToHtml(String fileUrl, String pKeyId) {
+    public static String pngToHtml(String fileUrl, String pKeyId,String pageNum) {
         String lasHhtmlUrl = "";
         try {
             // 定义Python解释器路径和脚本路径
             String pythonScript = "/Users/hongchuangyanfa/Desktop/PycharmProjects/splitPngToHtml.py";
             // 构建命令
-            ProcessBuilder pb = new ProcessBuilder("python3", pythonScript, fileUrl, pKeyId);
+            ProcessBuilder pb = new ProcessBuilder("python3", pythonScript, fileUrl, pKeyId, pageNum);
             Process process = pb.start();
 
             // 读取Python脚本输出
@@ -281,7 +333,6 @@ public class ArchiveController {
                     new InputStreamReader(process.getInputStream()));
             String htmlUrl;
             while ((htmlUrl = reader.readLine()) != null) {
-                System.out.println("222" + htmlUrl);
                 if (htmlUrl.indexOf("html文件路径") >= 0 && htmlUrl.indexOf("_001.html") >= 0 && htmlUrl.indexOf("archiveSplit") >= 0) {
                     lasHhtmlUrl = htmlUrl.replace("html文件路径", "");
                 }
@@ -299,6 +350,38 @@ public class ArchiveController {
         }
     }
 
+    public String OcrTitle(String fileUrl, String type) {
+        String lasHhtmlUrl = "";
+        try {
+            // 定义Python解释器路径和脚本路径
+            String pythonScript = "/Users/hongchuangyanfa/Desktop/PycharmProjects/splitPngByTitle.py";
+            // 构建命令
+            ProcessBuilder pb = new ProcessBuilder("python3", pythonScript, fileUrl, type);
+            Process process = pb.start();
+
+            // 读取Python脚本输出
+            BufferedReader reader = new BufferedReader(
+                    new InputStreamReader(process.getInputStream()));
+            String htmlUrl;
+            while ((htmlUrl = reader.readLine()) != null) {
+                System.out.println("222" + htmlUrl);
+                if (htmlUrl.indexOf("图片中是否有卷内目录") >= 0 && htmlUrl.indexOf("True") >=0) {
+                    return "1";
+                }
+            }
+            // 等待进程结束
+            int exitCode = process.waitFor();
+            if (exitCode == 0) {
+                return lasHhtmlUrl;
+            } else {
+                return "1";
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            return "1";
+        }
+    }
+
 
     public static void getPdfByPage(int startPage, int endPage, String filePath, String savePath) {
         try {
@@ -329,7 +412,7 @@ public class ArchiveController {
         }
     }
 
-    public void savePdfAsImage(int pageNum, String filePath, String outputPath) {
+    public static void savePdfAsImage(int pageNum, String filePath, String outputPath) {
         try (InputStream inputStream = FileUtils.getInputStreamByUrl(filePath);
              PDDocument document = PDDocument.load(inputStream)) {
 
@@ -362,7 +445,8 @@ public class ArchiveController {
         }
     }
 
-    public int saveDataToMysql(String upFileUrl,String fileName,String fileId,int filePage) {
+    public int saveDataToMysql(String upFileUrl,String fileName,String fileId,int filePage,int sort,String dutyUser) {
+
         // 获取封面信息
         long newPkId = SnowFlakeUtil.getId(); //主键Id
         File fmfile = new File(upFileUrl);
@@ -375,13 +459,13 @@ public class ArchiveController {
                         " drawing_no,cite_change_number,certification_time,e_visa_file,node_ext_id,file_type,archive_id,origin_id,filming_time,filmingor_time,tag_id,pic_code,refer_code,film_code,width,height,ftime,utime,del_time,sort,box_name,box_number,is_auto_file,is_archive,page_num, " +
                         " file_size,source_type,is_element,pdf_page_url,fid,rectification,classify,m_wbs_tree_contract_p_key_id,u_image_classification_file_id,archive_file_storage_type,node_tree_structure,date_name,archive_file_stroage_type,out_id,sort_num " +
                         "   ) " +
-                        " SELECT "+newPkId+",project_id,contract_id,node_id,file_number,'" + fileName + "',file_time,'" + FmPdfUrl + "','" + FmPdfUrl + "',"+filePage+",is_approval,is_certification,is_need_certification,duty_user,create_user,create_dept,create_time,update_user,update_time,status,is_deleted,sheet_type,sheet_source, " +
-                        "        drawing_no,cite_change_number,certification_time,e_visa_file,node_ext_id,file_type,archive_id,origin_id,filming_time,filmingor_time,tag_id,pic_code,refer_code,film_code,width,height,ftime,utime,del_time,sort,box_name,box_number,is_auto_file,is_archive,page_num, " +
+                        " SELECT "+newPkId+",project_id,contract_id,node_id,file_number,'" + fileName + "',file_time,'" + FmPdfUrl + "','" + FmPdfUrl + "',"+filePage+",is_approval,is_certification,is_need_certification,'"+dutyUser+"',create_user,create_dept,create_time,update_user,update_time,status,is_deleted,sheet_type,sheet_source, " +
+                        "        drawing_no,cite_change_number,certification_time,e_visa_file,node_ext_id,file_type,archive_id,origin_id,filming_time,filmingor_time,tag_id,pic_code,refer_code,film_code,width,height,ftime,utime,del_time,"+sort+",box_name,box_number,is_auto_file,is_archive,page_num, " +
                         "        file_size,source_type,is_element,pdf_page_url,fid,rectification,classify,m_wbs_tree_contract_p_key_id,u_image_classification_file_id,archive_file_storage_type,node_tree_structure,date_name,archive_file_stroage_type,out_id,sort_num " +
                         " from u_archive_file where id=" + fileId;
                 System.out.println(fileName + "----" + sql);
                 jdbcTemplate.execute(sql);
-                return 200;
+
             } else {
                 // 检查一下oss是否启动
                 System.out.println("oss服务未启动,无法上传文件到oss");
@@ -390,5 +474,7 @@ public class ArchiveController {
         }else{
             return 404;
         }
+        fmfile.delete();
+        return 200;
     }
 }

+ 9 - 4
blade-service/blade-e-visa/src/main/java/org/springblade/evisa/controller/EVController.java

@@ -58,7 +58,7 @@ public class EVController {
     @Resource(name = "taskExecutor1")
     private ThreadPoolExecutor executor;
 
-   // @Scheduled(cron = "0/10 * * * * ?")
+    @Scheduled(cron = "0/10 * * * * ?")
     public void SignInfo() {
         //执行代码
 
@@ -71,8 +71,9 @@ public class EVController {
                 "JSON_UNQUOTE(JSON_EXTRACT(json_data, '$.flag')) as flag," +
                 "GROUP_CONCAT(create_user) as userId," +
                 "GROUP_CONCAT(nick_name) as nickName," +
-                "sign_type as sigType," +
-                "(select count(0) from u_task_parallel b where a.task_parallel_id = b.process_instance_id and b.is_deleted = 0 and (b.status = 1 or b.initiative = 1)) isSignature" +
+                "sign_type as sigType ," +
+                "(select count(0) from u_task_parallel b INNER JOIN u_task c on b.process_instance_id = c.process_instance_id " +
+                "where c.id = JSON_UNQUOTE(JSON_EXTRACT(a.json_data, '$.taskId')) and b.is_deleted = 0 and (b.status = 1 or b.initiative = 1)) isSignature" +
                 " from u_task_batch a where is_deleted=0 GROUP BY JSON_EXTRACT(json_data, '$.formDataId'),sign_type ORDER BY sign_type DESC ";
                 //and JSON_UNQUOTE(JSON_EXTRACT(json_data,'$.taskId')) in(SELECT id from u_task where project_id =1792760669353865218 and is_deleted =0 and approval_type=1 )
         List<TaskSignInfoVO> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(TaskSignInfoVO.class));
@@ -82,7 +83,7 @@ public class EVController {
                 if(dataInfo.getSigType() == 2 && dataInfo.getIsSignature() > 0){
                     continue;
                 }
-                if (executor.getQueue().size() <= 10) {
+                if (executor.getQueue().size() <= 20) {
                     Boolean aBoolean = RedisTemplate.hasKey("sign-" + dataInfo.getFormDataId());
                     if (!aBoolean) {
                         if (dataInfo.getSigType() == 2) {
@@ -102,6 +103,10 @@ public class EVController {
                                 try {
                                     /*===============执行批量任务===============*/
                                     evDataService.signTaskBatch(dataInfo);
+                                    System.out.println("队列数量" + executor.getQueue().size());
+                                    System.out.println("活跃数量" + executor.getActiveCount());
+                                    System.out.println("总共数量" + executor.getTaskCount());
+                                    System.out.println("完成数量" + executor.getCompletedTaskCount());
                                 } catch (Exception e) {
                                     e.printStackTrace();
                                 }

+ 1 - 1
blade-service/blade-e-visa/src/main/java/org/springblade/evisa/service/EVisaService.java

@@ -50,5 +50,5 @@ public interface EVisaService {
 
     Object[] signPdfByAXQZ(SealPdfVO pdfVO, String loPdfurl,String outPdfUrl);
 
-    String signPdfByDFZX(HashMap<String, Object> daMa);
+    String signPdfByDFZX(HashMap<String, Object> daMa,String signPdfByDFZX,String contractId);
 }

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

@@ -129,11 +129,11 @@ public class EVDataServiceImpl implements EVDataService {
                 if (taskApp.getSigState() != 1) {
                     return;
                 }
-            } else if (taskApp.getRemarkType().equals("2")) { //东方中讯
+            } else if (taskApp.getRemarkType().equals("2") || taskApp.getRemarkType().equals("3")) { //东方中讯
                 //添加电签策略
                 List<Map<String, Object>> strategyListByDFZX = getStrategyListByDFZX(taskApp, ids);
                 //调用签字逻辑
-                String s = signTaskBatchByDFZX(strategyListByDFZX, fileUrl, taskApp.getSigType());
+                String s = signTaskBatchByDFZX(strategyListByDFZX, fileUrl, taskApp.getSigType(),taskApp.getRemarkType(),taskApp.getContractId());
                 if (s.contains("sucess")) {
                     taskApp.setLastFilePdfUrl(s.split("@@@@")[1]);
                     taskApp.setSigState(1);
@@ -492,7 +492,9 @@ public class EVDataServiceImpl implements EVDataService {
                 Integer remarkType = projectInfo.getRemarkType();
                 if (remarkType != null && Func.isNotEmpty(remarkType) && remarkType == 2) {
                     taskApp.setRemarkType("2");
-                } else {
+                }else if (remarkType != null && Func.isNotEmpty(remarkType) && remarkType == 3) {
+                    taskApp.setRemarkType("3");
+                }else {
                     taskApp.setRemarkType("1");
                 }
             }
@@ -663,7 +665,7 @@ public class EVDataServiceImpl implements EVDataService {
     }
 
     // 添加电签策略 -- 东方中讯
-    public String signTaskBatchByDFZX(List<Map<String, Object>> maps, String pdfUrl, int type) {
+    public String signTaskBatchByDFZX(List<Map<String, Object>> maps, String pdfUrl, int type,String remarkType,String contractId) {
         if (maps != null && maps.size() > 0) {
             String fileUrl = pdfUrl;
             for (Map<String, Object> dataMap : maps) {
@@ -671,7 +673,7 @@ public class EVDataServiceImpl implements EVDataService {
                 daMa.put("keyWord", dataMap.get("keyWord"));
                 daMa.put("sealId", dataMap.get("sealId"));
                 // 设置图片显示大小
-                if (type != 2) { //章
+                if (type != 2 && !remarkType.equals("3")) { //章
                     daMa.put("showHeight", 30);
                     daMa.put("showWidth", 60);
                 }
@@ -702,7 +704,10 @@ public class EVDataServiceImpl implements EVDataService {
                 } catch (Exception e) {
                     throw new RuntimeException(e);
                 }
-                String reData = eVisaService.signPdfByDFZX(daMa);
+
+
+                String reData = eVisaService.signPdfByDFZX(daMa,remarkType,contractId);
+
                 if (reData.indexOf("success@") >= 0) {
                     fileUrl = reData.split("@@@@")[1];
                 } else {

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

@@ -68,6 +68,9 @@ import org.springblade.system.cache.ParamCache;
 import org.springblade.system.user.entity.User;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
 import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
 import org.springframework.http.converter.HttpMessageConverter;
 import org.springframework.http.converter.StringHttpMessageConverter;
@@ -313,7 +316,7 @@ public class EVisaServiceImpl implements EVisaService {
                             String originalFileB64 = Base64.toBase64String(fileByte);
                             daMa.put("fileB64", originalFileB64);
                             daMa.put("lastSignFlag", false);
-                            String reData = signPdfByDFZX(daMa);
+                            String reData = signPdfByDFZX(daMa,reType,contractId);
                             if (reData.indexOf("success@") >= 0) {
                                 fileUrl = reData.split("@@@@")[1];
                             } else {
@@ -517,7 +520,7 @@ public class EVisaServiceImpl implements EVisaService {
                             String originalFileB64 = Base64.toBase64String(fileByte);
                             daMa.put("fileB64", originalFileB64);
                             daMa.put("lastSignFlag", false);
-                            String reData = signPdfByDFZX(daMa);
+                            String reData = signPdfByDFZX(daMa,"2",contractId);
                             if (reData.indexOf("success@") >= 0) {
                                 fileUrl = reData.split("@@@@")[1];
                             } else {
@@ -788,12 +791,17 @@ public class EVisaServiceImpl implements EVisaService {
      * 东方 中讯
      * @throws Exception
      */
-    public String signPdfByDFZX(HashMap<String, Object> request) {
+    public String signPdfByDFZX(HashMap<String, Object> paramsMap,String signPdfByDFZX,String contractId) {
         String url = "http://localhost:9125/FrontSys/SealServicezx/FileSignByKeyWord";
         String sys_isonline = ParamCache.getValue(CommonConstant.SYS_ISONLINE);
         if ("20".equals(sys_isonline) || SystemUtils.isWindows() || SystemUtils.isMacOs()) {
             url = "http://219.151.181.73:9125/FrontSys/SealServicezx/FileSignByKeyWord";
         }
+        if(signPdfByDFZX.equals("3")){
+            url = "http://113.250.191.72:9125/FrontSys/SealServicezx/FileSignByKeyWord";
+        }
+
+
         String sysLocalFileUrl = FileUtils.getSysLocalFileUrl();
         String filecode = SnowFlakeUtil.getId() + "";
         String dataFileUrl = sysLocalFileUrl + "/pdf/" + filecode + ".pdf";
@@ -802,7 +810,9 @@ public class EVisaServiceImpl implements EVisaService {
             httpRequestFactory.setConnectionRequestTimeout(30000);
             httpRequestFactory.setConnectTimeout(30000);
             httpRequestFactory.setReadTimeout(30000);
+
             RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
+
             // 设置编码格式为UTF-8
             List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters();
             HttpMessageConverter<?> converterTarget = null;
@@ -818,16 +828,33 @@ public class EVisaServiceImpl implements EVisaService {
             }
             HttpMessageConverter<?> converter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
             converterList.add(1, converter);
+            HashMap<String, Object> retData;
+            if(signPdfByDFZX.equals("3")){
+                Map<String, Object> stringObj = jdbcTemplate.queryForMap("SELECT seal_project_id,seal_account_id,seal_customer_id,seal_comm_key from m_contract_info  where id = " + contractId);
+                System.out.println(contractId);
+                HttpHeaders headers = new HttpHeaders();
+                // 添加自定义头(示例:设置Authorization和Content-Type)
+                headers.add("project_id", stringObj.get("seal_project_id")+"");  // 替换为实际
+                headers.add("account_id", stringObj.get("seal_account_id")+"");  // 替换为实际
+                headers.add("customer_id", stringObj.get("seal_customer_id")+"");  // 替换为实际
+                headers.add("commKey", stringObj.get("seal_comm_key")+"");  // 替换为实际
+                headers.setContentType(MediaType.APPLICATION_JSON);  // 指定请求体为JSON格式
+
+                HttpEntity<HashMap<String, Object>> httpEntity = new HttpEntity<>(paramsMap, headers);
+
+                retData = restTemplate.postForObject(url, httpEntity, HashMap.class);
+            }else{
+                retData = restTemplate.postForObject(url, paramsMap, HashMap.class);
+            }
 
-            HashMap<String, Object> retData = restTemplate.postForObject(url, request, HashMap.class);
             System.out.println("东方中讯uRL" + url);
             String code = retData.get("code").toString();
             String msg = retData.get("msg").toString();
 
             if (!"0".equals(code)) {
+                System.out.println(retData);
                 return ERROR + "@@@@" + msg;
             }
-
             String fileB642 = retData.get("fileB64").toString();
 
             FileOutputStream fout = new FileOutputStream(dataFileUrl);

+ 1 - 1
blade-service/blade-manager/pom.xml

@@ -240,7 +240,7 @@
                     <target>${java.version}</target>
                     <encoding>${project.build.sourceEncoding}</encoding>
                     <compilerArguments>
-                        <bootclasspath>${java.home}/lib/rt.jar;${java.home}/lib/jce.jar;${java.home}/lib/jsse.jar
+                        <bootclasspath>${java.home}/lib/rt.jar:${java.home}/lib/jce.jar:${java.home}/lib/jsse.jar
                         </bootclasspath>
                     </compilerArguments>
                 </configuration>

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

@@ -398,7 +398,8 @@ public class ArchiveTreeContractController extends BladeController {
 
         //TODO 待节点都同步完了以后,再去设置wbs节点的组卷规则。(方式:客户级wbs节点-》项目级wbs节点-》wbs项目级组卷规则-》设置规则到客户级wbs节点以及子节点)
         if (b) {
-            archiveTreeContractService.updateWbsRuleNodes(archiveTree.getProjectId());
+            //todo 0625 暂时去掉项目级组卷规则同步客户级
+            //archiveTreeContractService.updateWbsRuleNodes(archiveTree.getProjectId());
         }
 
         if (b) {

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

@@ -798,7 +798,7 @@ public class ExcelTabController extends BladeController {
                 List<WbsFormElement> list = this.wbsFormElementService.list(Wrappers.<WbsFormElement>lambdaQuery().select(WbsFormElement::getEKey, WbsFormElement::getELength)
                         .eq(WbsFormElement::getFId, tableInfo.getId()).eq(WbsFormElement::getIsDeleted, 0));
                 if (list != null && !list.isEmpty()) {
-                    Map<String, Integer> keyNameMap = list.stream().collect(Collectors.toMap(WbsFormElement::getEKey, WbsFormElement::getELength));
+                    Map<String, Integer> keyNameMap = list.stream().filter(wbsFormElement -> wbsFormElement.getELength() != null).collect(Collectors.toMap(WbsFormElement::getEKey, WbsFormElement::getELength, (v1, v2) -> v1 > v2 ? v1 : v2));
                     Elements keyNames = table.getElementsByAttribute("keyname");
                     keyNames.forEach(element -> {
                         String key = element.attr("keyname");

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

@@ -48,7 +48,7 @@ public class ArchiveTreeContractImpl implements ArchiveTreeContractClient {
      */
     @Override
     public List<ArchiveTreeContract> getHavedFileNodeByProjectID(Long projectId) {
-        List<ArchiveTreeContract> list = archiveTreeContractMapper.getHavedFileNodeByProjectID(projectId);
+        List<ArchiveTreeContract> list = archiveTreeContractMapper.getHavedFileNodeByProjectID1(projectId);
         Map<Long,String> map = new HashMap<>();
         for (ArchiveTreeContract box: list) {
             map.put(box.getId(),"1");
@@ -103,6 +103,12 @@ public class ArchiveTreeContractImpl implements ArchiveTreeContractClient {
         return archiveTreeContractService.getArchiveTreeContractListByIds(ids);
     }
 
+    @Override
+    public List<ArchiveTreeContract> getArchiveTreeContractListByList(List<Long> ids) {
+
+        return archiveTreeContractService.getArchiveTreeContractListByList(ids);
+    }
+
     @Override
     public ArchiveTreeContract getFirstNodeByTreeCode(Long projectId,Integer type) {
         ArchiveTreeContract contract = new ArchiveTreeContract();

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

@@ -80,6 +80,8 @@ public interface ArchiveTreeContractMapper extends BaseMapper<ArchiveTreeContrac
 
     List<ArchiveTreeContract> getHavedFileNodeByProjectID(@Param("projectId") Long projectId);
 
+    List<ArchiveTreeContract> getHavedFileNodeByProjectID1(@Param("projectId") Long projectId);
+
     List<ArchiveTreeContract> getHavedBoxFileNodeByProjectID(@Param("projectId") Long projectId);
 
     List<ArchiveTreeContract> getListByProjectId(@Param("projectId") Long projectId);

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

@@ -358,6 +358,43 @@
         order by ancestors asc,tree_sort asc
     </select>
 
+    <select id="getHavedFileNodeByProjectID1" resultMap="archiveTreeContractResultMap">
+        SELECT
+            *
+        FROM
+            m_archive_tree_contract
+        WHERE
+            1 = 1
+          AND project_id = #{projectId}
+          AND is_deleted = 0
+          AND archive_auto_type IS NOT NULL
+          AND id IN (
+            SELECT
+                node_id
+            FROM
+                u_archive_file uaf
+            WHERE
+                1 = 1
+              AND uaf.project_id = #{projectId}
+              AND uaf.is_deleted = 0
+              AND uaf.node_id IS NOT NULL
+              AND (
+                -- 条件1:标记为未归档的文件
+
+                    -- 条件2:未关联有效案卷的文件
+                        NOT EXISTS (
+                                SELECT 1
+                                FROM u_archives_auto uaa
+                                WHERE
+                                    uaa.id = uaf.archive_id
+                                  AND uaa.project_id = uaf.project_id
+                                  AND uaa.is_deleted = 0
+                            )
+                )
+        )
+        ORDER BY tree_sort,sort
+    </select>
+
 
     <select id="getTopAutoTypeNodeByProjectID" resultMap="archiveTreeContractResultMap">
         SELECT
@@ -394,7 +431,7 @@
               AND node_id IS NOT NULL
               AND (box_number IS NOT NULL and box_number != -1 )
         )
-        order by ancestors asc,tree_sort asc
+        order by tree_sort,sort
     </select>
 
 

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

@@ -113,6 +113,8 @@ public interface IArchiveTreeContractService extends BaseService<ArchiveTreeCont
 
     List<ArchiveTreeContract> getArchiveTreeContractListByIds(String ids);
 
+    List<ArchiveTreeContract> getArchiveTreeContractListByList(List<Long> ids);
+
     List<ArchiveTreeContract> getWbsAssociatedNodes(String contractId);
 
     void updateAllSonNodeIdsForArchiveAutoRule(ArchiveTreeContract archiveTreeContract);

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

@@ -235,7 +235,8 @@ public class ArTreeContractInitServiceImpl {
 
         InitTreeSort(trees.get(0), "", 0);
 
-        archiveAutoRuleSync.syncArchiveTreeContractList(vo2Map, proVo2Trees);
+        //todo 0625 暂时去掉项目级组卷规则同步客户级
+        //archiveAutoRuleSync.syncArchiveTreeContractList(vo2Map, proVo2Trees);
 
         List<ArchiveTreeContract> upList = new ArrayList<>();
 

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

@@ -405,6 +405,13 @@ public class ArchiveTreeContractServiceImpl extends BaseServiceImpl<ArchiveTreeC
 		return baseMapper.getArchiveTreeContractListByIds(idsList);
 	}
 
+	@Override
+	public List<ArchiveTreeContract> getArchiveTreeContractListByList(List<Long> ids) {
+		// 将List<Long>转换成List<String>
+		List<String> stringIds = ids.stream().map(Object::toString).collect(Collectors.toList());
+		return baseMapper.getArchiveTreeContractListByIds(stringIds);
+	}
+
 	/**
 	 *  同步项目级
 	 * @param dstNode
@@ -497,6 +504,9 @@ public class ArchiveTreeContractServiceImpl extends BaseServiceImpl<ArchiveTreeC
 		this.saveBatch(saveList);
 		this.updateBatchById(upList);
 
+		//再刷新一次treesort
+		sortChildren(dstNode);
+
 		return true;
 	}
 
@@ -1710,4 +1720,74 @@ public class ArchiveTreeContractServiceImpl extends BaseServiceImpl<ArchiveTreeC
 	}
 
 
+	/**
+	 * 刷新某个节点下的treesort
+	 * @param archiveTreeContract
+	 */
+	void sortChildren(ArchiveTreeContract archiveTreeContract) {
+		if (archiveTreeContract == null) {
+			return;
+		}
+
+		// 获取整个项目的树
+		List<ArchiveTreeContractVO2> trees = this.tree2Root(
+				AuthUtil.getTenantId(),
+				null,
+				null,
+				archiveTreeContract.getProjectId(),
+				null
+		);
+
+		if (trees.isEmpty()) {
+			return;
+		}
+		ArchiveTreeContractVO2 tree = trees.get(0);
+
+		// 初始化整棵树的排序 (只设置内存中的 treeSort 和 flag)
+		ForestNodeMergerEx.InitTreeSortEx(tree, "", 0);
+
+		// 获取当前节点对应的子树
+		ArchiveTreeContractVO2 subTree = ForestNodeMergerEx.getSubTree(tree, archiveTreeContract.getId());
+		if (subTree == null) {
+			return; // 没找到子树
+		}
+
+		// 收集子树中所有节点 (用于后续筛选)
+		List<ArchiveTreeContractVO2> allNodes = new ArrayList<>();
+		ForestNodeMergerEx.getTreeList(subTree, allNodes);
+
+		// 筛选需要更新的节点 (flag == 1)
+		List<ArchiveTreeContractVO2> changeList = new ArrayList<>();
+		for (ArchiveTreeContractVO2 node : allNodes) {
+			if (node.getFlag() == 1) {
+				changeList.add(node);
+			}
+		}
+
+		if (changeList.isEmpty()) {
+			return; // 没有需要更新的节点
+		}
+
+		// 构建 ID 映射
+		Map<Long, ArchiveTreeContractVO2> map = new HashMap<>();
+		List<Long> ids = new ArrayList<>();
+		for (ArchiveTreeContractVO2 ar : changeList) {
+			ids.add(ar.getId());
+			map.put(ar.getId(), ar);
+		}
+
+		// 从数据库查询需要更新的实体
+		List<ArchiveTreeContract> changeArchiveList = baseMapper.selectBatchIds(ids);
+		for (ArchiveTreeContract changeNode : changeArchiveList) {
+			ArchiveTreeContractVO2 ar = map.get(changeNode.getId());
+			if (ar != null) {
+				changeNode.setTreeSort(ar.getTreeSort());
+			}
+		}
+
+		// 批量更新数据库
+		this.saveOrUpdateBatch(changeArchiveList);
+	}
+
+
 }

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

@@ -200,10 +200,10 @@ public class ArchiveTreeContractSyncImpl {
         //排序
         ForestNodeMergerEx.InitAncestors(tree, "0");
 
-        ForestNodeMergerEx.InitTreeSort(tree, "", 0);
+        ForestNodeMergerEx.InitTreeSortEx(tree, "", 0);
 
-        //更新自动组卷节点
-        archiveAutoRuleSync.syncArchiveTreeContractList(vo2Map, proVo2Trees);
+        //更新自动组卷节点 todo 0625 暂时去掉项目级组卷规则同步客户级
+        //archiveAutoRuleSync.syncArchiveTreeContractList(vo2Map, proVo2Trees);
 
         //根据vo的排序和自动组卷信息,刷新新增节点,根据修改标识生成更新节点
         arTreeContractInitService.handleAddAndUpList(vo2Map, allAddList, upList);
@@ -597,7 +597,7 @@ public class ArchiveTreeContractSyncImpl {
                     else  if ( (info.getNodePdfUrl() != null && !info.getNodePdfUrl().equals(archiveFile.getPdfFileUrl()))
                                 || (sort != null && !sort.equals(archiveFile.getSort()))
                                 || (nodeId != null && !nodeId.toString().equals(archiveFile.getNodeId()))
-                                || (StringUtils.isNotEmpty(info.getBusinessTime() ) && !info.getBusinessTime().equals(archiveFile.getFileTime()))
+                                || (StringUtils.isNotEmpty(info.getBusinessTime() ) && !info.getBusinessTime().replaceAll("[^0-9]", "").equals(archiveFile.getFileTime()))
                                 || (info.getEVisaPdfSize()!= null && info.getEVisaPdfSize() > 0L && !info.getEVisaPdfSize().equals(archiveFile.getFileSize()))
                     ) {
 

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

@@ -1248,7 +1248,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
                     if (wbsTreeContractByP != null) {
                         //处理文件提名
                         String fileName = this.wbsParamService.createFileTitle(wbsTreeContractByP);
-                        if(wbsTreeContract.getMajorDataType()!=null&&wbsTreeContract.getMajorDataType()==6){
+                        if(wbsTreeContractByP.getMajorDataType()!=null&&wbsTreeContractByP.getMajorDataType()==4){
                             String sql1="Select sg_suffix,jl_suffix from m_project_info where id="+wbsTreeContractByP.getProjectId()+" and is_deleted=0";
                             List<ProjectInfo> query = jdbcTemplate.query(sql1, new BeanPropertyRowMapper<>(ProjectInfo.class));
                             if(query.size()>0){