Jelajahi Sumber

Merge branch 'lihb' of http://219.151.181.73:3000/zhuwei/bladex into test-trial

# Conflicts:
#	blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java
#	blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/TextdictInfoServiceImpl.java
lvy 1 bulan lalu
induk
melakukan
9fe951d2b0
22 mengubah file dengan 945 tambahan dan 178 penghapusan
  1. 2 2
      blade-ops/blade-resource/src/main/java/org/springblade/resource/endpoint/LargeFileEndpoint.java
  2. 51 0
      blade-service-api/blade-e-visa-api/src/main/java/org/springblade/evisa/vo/ArchivesSplitInfoVO.java
  3. 8 0
      blade-service-api/blade-e-visa-api/src/main/java/org/springblade/evisa/vo/TaskArchiveSplitVO.java
  4. 14 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/WbsTreeContractVO6.java
  5. 16 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchivesAutoServiceImpl.java
  6. 1 1
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/ArchiveFileMapper.xml
  7. 1 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TaskServiceImpl.java
  8. 252 27
      blade-service/blade-e-visa/src/main/java/org/springblade/evisa/controller/ArchiveController.java
  9. 21 57
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java
  10. 24 21
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreeSynchronousRecordController.java
  11. 14 4
      blade-service/blade-manager/src/main/java/org/springblade/manager/job/SystemMsgJob.java
  12. 3 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ContractInfoMapper.xml
  13. 6 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreeContractMapper.java
  14. 7 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreeContractMapper.xml
  15. 2 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreePrivateMapper.java
  16. 7 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreePrivateMapper.xml
  17. 54 5
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ArchiveTreeContractSyncImpl.java
  18. 1 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/TextdictInfoServiceImpl.java
  19. 96 4
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsSynchronousEViSaServiceImpl.java
  20. 97 47
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsSynchronousServiceImpl.java
  21. 260 9
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeContractServiceImpl.java
  22. 8 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeSynchronousRecordServiceImpl.java

+ 2 - 2
blade-ops/blade-resource/src/main/java/org/springblade/resource/endpoint/LargeFileEndpoint.java

@@ -486,7 +486,7 @@ public class LargeFileEndpoint {
      *
      * @param mappedByteBuffer
      */
-    private static void freeMappedByteBuffer(final MappedByteBuffer mappedByteBuffer) {
+/*    private static void freeMappedByteBuffer(final MappedByteBuffer mappedByteBuffer) {
         try {
             if (mappedByteBuffer == null) {
                 return;
@@ -512,7 +512,7 @@ public class LargeFileEndpoint {
         } catch (Exception e) {
             e.printStackTrace();
         }
-    }
+    }*/
 
     private static String getFileName(MultipartFileParam param) {
         String extension;

+ 51 - 0
blade-service-api/blade-e-visa-api/src/main/java/org/springblade/evisa/vo/ArchivesSplitInfoVO.java

@@ -0,0 +1,51 @@
+/*
+ *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *  Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the dreamlu.net developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: Chill 庄骞 (smallchill@163.com)
+ */
+package org.springblade.evisa.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+/**
+ * 视图实体类
+ *
+ * @author BladeX
+ * @since 2025-06-10
+ */
+@Data
+public class ArchivesSplitInfoVO {
+	// u_archv_file 主键id
+	@ApiModelProperty("id")
+	private String id;
+
+	// 文件Id
+	@ApiModelProperty("first_file_url")
+	private String firstFileUrl;
+
+	//需要分解的文件url
+	@ApiModelProperty("file_url")
+	private String fileUrl;
+
+	//需要分解的文件url
+	@ApiModelProperty("status")
+	private String status;
+
+	//分解任务主键ID
+	@ApiModelProperty("task_id")
+	private String taskId;
+
+	@ApiModelProperty("archive_id")
+	private String archiveId;
+}

+ 8 - 0
blade-service-api/blade-e-visa-api/src/main/java/org/springblade/evisa/vo/TaskArchiveSplitVO.java

@@ -6,13 +6,21 @@ import lombok.Data;
 @Data
 public class TaskArchiveSplitVO {
 
+    // u_archv_file 主键id
     @ApiModelProperty("id")
     private String id;
 
+    // u_archv_auto 主键id
     @ApiModelProperty("archiveId")
     private String archiveId;
 
+    //需要分解的文件url
     @ApiModelProperty("fileUrl")
     private String fileUrl;
 
+    //分解任务主键ID
+    @ApiModelProperty("taskId")
+    private String taskId;
+
+
 }

+ 14 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/WbsTreeContractVO6.java

@@ -3,6 +3,7 @@ package org.springblade.manager.vo;
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import org.springblade.core.tool.node.INode;
 import org.springblade.core.tool.node.TreeNode;
@@ -40,6 +41,10 @@ public class WbsTreeContractVO6 extends WbsTreeContract implements INode<WbsTree
 
     private Integer sort;
 
+    @ApiModelProperty(value = "1 水利工程 2是数字化")
+    private Integer nodeClass;
+
+
     @JsonInclude(JsonInclude.Include.NON_EMPTY)
     private Boolean hasChildren;
 
@@ -131,6 +136,15 @@ public class WbsTreeContractVO6 extends WbsTreeContract implements INode<WbsTree
         this.sort = sort;
     }
 
+    public Integer getNodeClass() {
+        return nodeClass;
+    }
+
+    public void setNodeClass(Integer nodeClass) {
+        this.nodeClass = nodeClass;
+    }
+
+
     @Override
     public String toString() {
         return "WbsTreeContractVO{" +

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

@@ -1363,7 +1363,23 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		if (selectList== null || selectList.size() == 0) {
 			return;
 		}
+
+		if (waitArchiveFiles==null || waitArchiveFiles.size()== 0) {
+			return;
+		}
+
+		String strfirstNodeId = waitArchiveFiles.get(0).getNodeId();
+
 		ArchiveTreeContract node = selectList.get(0);
+		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(",");

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

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

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

@@ -691,6 +691,7 @@ public class TaskServiceImpl extends BaseServiceImpl<TaskMapper, Task> implement
                         jdbcTemplate.execute("update u_contract_log set status=3 where id='"+taskApp.getFormDataId()+"'");
                     }else if (taskApp.getApprovalType()==8) {
                         this.jdbcTemplate.execute("update u_entrust_info set status=1 where id=(SELECT wbs_id from u_information_query where id='"+taskApp.getFormDataId()+"')");
+                        this.jdbcTemplate.execute("update u_information_query set status=3 where id='"+taskApp.getFormDataId()+"'");
                     }else {
                         jdbcTemplate.execute("update u_information_query set e_visa_pdf_url='',status=3 where id='"+taskApp.getFormDataId()+"'");
                         InformationQuery informationQuery = informationQueryService.getById(taskApp.getFormDataId());

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

@@ -5,10 +5,18 @@ import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.PDPage;
-import org.springblade.business.vo.TaskSignInfoVO;
-import org.springblade.evisa.service.EVDataService;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+import org.springblade.common.utils.SnowFlakeUtil;
+import org.springblade.core.oss.model.BladeFile;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.IoUtil;
 import org.springblade.evisa.utils.FileUtils;
+import org.springblade.evisa.vo.ArchivesSplitInfoVO;
 import org.springblade.evisa.vo.TaskArchiveSplitVO;
+import org.springblade.resource.feign.NewIOSSClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
@@ -17,8 +25,7 @@ import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
-import java.io.File;
-import java.io.InputStream;
+import java.io.*;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CompletableFuture;
@@ -26,6 +33,7 @@ import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.pdfbox.rendering.PDFRenderer;
+
 import java.awt.image.BufferedImage;
 import javax.imageio.ImageIO;
 
@@ -47,34 +55,32 @@ public class ArchiveController {
     // jdbc
     private final JdbcTemplate jdbcTemplate;
 
-    //电签服务类
-    private final EVDataService evDataService;
+    private final NewIOSSClient newIOSSClient;
 
     // 线程池
     @Resource(name = "taskExecutor1")
     private ThreadPoolExecutor executor;
 
-    @Scheduled(cron = "0/10 * * * * ?")
+   @Scheduled(cron = "0 0/1 * * * ?")
     public void SignInfo() {
         //执行代码
 
-        log.info("扫描开始");
-
-        String sql = "SELECT a.id,a.archive_id as archiveId,a.file_url as fileUrl from u_archive_file a, u_task_split b where FIND_IN_SET(a.archive_id,b.ids) and b.type=3 ";
+        log.info("分解pdf专图片");
+        String sql = "SELECT distinct b.id,b.archive_id as archiveId ,b.file_url as fileUrl,c.id as taskId from u_archives_auto a , u_archive_file b ,u_task_split c  where a.id=b.archive_id and ((FIND_IN_SET(a.id,c.ids) and c.type=3) or (a.contract_id=c.contract_id and c.type=2)) and a.is_deleted=0 and b.is_deleted=0 and a.split_status not in(1,2) ";
         List<TaskArchiveSplitVO> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(TaskArchiveSplitVO.class));
 
         if (query != null && query.size() >= 1) {
             for (TaskArchiveSplitVO dataInfo : query) {
                 if (executor.getQueue().size() <= 10) {
-                    Boolean aBoolean = RedisTemplate.hasKey("sign-" + dataInfo.getArchiveId());
+                    Boolean aBoolean = RedisTemplate.hasKey("splitpng-" + dataInfo.getArchiveId());
                     if (!aBoolean) {
 
-                        if(!aBoolean){
-                            RedisTemplate.opsForValue().set("sign-" + dataInfo.getArchiveId(), "1", 7200, TimeUnit.SECONDS);
+                        if (!aBoolean) {
+                            RedisTemplate.opsForValue().set("splitpng-" + dataInfo.getArchiveId(), "1", 7200, TimeUnit.SECONDS);
                             CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> {
                                 try {
                                     /*===============执行批量任务===============*/
-                                    signTaskBatch(dataInfo);
+                                    signTaskBatchpngToHtml(dataInfo);
                                 } catch (Exception e) {
                                     e.printStackTrace();
                                 }
@@ -84,31 +90,217 @@ public class ArchiveController {
                 }
             }
         }
-
-        System.out.println("队列数量" + executor.getQueue().size());
-        System.out.println("活跃数量" + executor.getActiveCount());
-        System.out.println("总共数量" + executor.getTaskCount());
-        System.out.println("完成数量" + executor.getCompletedTaskCount());
+        System.out.println("队列数量_img" + executor.getQueue().size());
+        System.out.println("活跃数量_img" + executor.getActiveCount());
+        System.out.println("总共数量_img" + executor.getTaskCount());
+        System.out.println("完成数量_img" + executor.getCompletedTaskCount());
     }
 
-    public void signTaskBatch(TaskArchiveSplitVO taskSign) {
+    // 分解第一页的任务
+    public void signTaskBatchpngToHtml(TaskArchiveSplitVO taskSign) {
         try {
             String fileUrl = taskSign.getFileUrl();
             String archiveId = taskSign.getArchiveId();
             String id = taskSign.getId();
-            // 获取pdf第一页的数据
-            String firstUrl = FileUtils.getSysLocalFileUrl()+"archiveSplit/"+archiveId+"_001.pdf";
-            getPdfByPage(2,2,fileUrl,firstUrl);
+            String taskId = taskSign.getTaskId();
+
+            // 获取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";
-            savePdfAsImage(1, firstUrl, imagePath);
+            File imgfile = new File(imagePath);
+            if (!imgfile.exists()) {
+                savePdfAsImage(1, firstUrl, imagePath);
+            }
 
+            //判断
+            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;
+                    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())";
+                jdbcTemplate.execute(sql22);
+                String updateSql = "update u_archives_auto set split_status=2 where id=" + id;
+                jdbcTemplate.execute(updateSql);
+            }
+            RedisTemplate.delete("splitpng-" + archiveId);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    @Scheduled(cron = "0/30 * * * * ?")
+    public void SplitPdfInfo() {
+        //执行代码
+
+        log.info("分解html开始");
+        String sql = "select  * from u_archives_split_info where status =2 "; // and TIMESTAMPDIFF(MINUTE, create_time, NOW()) >=3";
+        List<ArchivesSplitInfoVO> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(ArchivesSplitInfoVO.class));
+
+        if (query != null && query.size() >= 1) {
+            for (ArchivesSplitInfoVO dataInfo : query) {
+                if (executor.getQueue().size() <= 10) {
+                    Boolean aBoolean = RedisTemplate.hasKey("splithtml-" + dataInfo.getArchiveId());
+                    if (!aBoolean) {
+
+                        if (!aBoolean) {
+                            RedisTemplate.opsForValue().set("splithtml-" + dataInfo.getArchiveId(), "1", 600, TimeUnit.SECONDS);
+                            CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> {
+                                try {
+                                    /*===============执行批量任务===============*/
+                                    signTaskBatchpng(dataInfo);
+                                } catch (Exception e) {
+                                    e.printStackTrace();
+                                }
+                            }, executor);
+                        }
+                    }
+                }
+            }
+        }
+        System.out.println("队列数量_html" + executor.getQueue().size());
+        System.out.println("活跃数量_html" + executor.getActiveCount());
+        System.out.println("总共数量_html" + executor.getTaskCount());
+        System.out.println("完成数量_html" + executor.getCompletedTaskCount());
+    }
+
+    public void signTaskBatchpng(ArchivesSplitInfoVO taskSign) {
+        try {
+            String archiveId = taskSign.getArchiveId();
+            String fileUlr = taskSign.getFileUrl();
+            String firstPage = FileUtils.getSysLocalFileUrl() + "archiveSplit/";
+            int bkb = 0 ;
+            //将imagePath 的数据转成一个可解析的html
+            String htmlUrl1 = 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;
+            }
+
+            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");
+
+                for (int i = 1; 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();
+                    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;
+                        }
+                    }else{
+                        if(ym.indexOf("-")>=0){
+                            String[] split = ym.split("-");
+                            startYm = Func.toInt(split[0]);
+                            endYm = Func.toInt(split[1]);
+                        }
+                    }
+                    startYm = startYm + 2 ;
+                    endYm = endYm + 2 ;
+                    System.out.println(zrz + " " + wjtm + " " + rq + " " + ym);
+                    // 分解文件
+                    String fmlUrl = FileUtils.getSysLocalFileUrl() + "archiveSplit/"+archiveId+"_cf_00"+i+".pdf";
+                    getPdfByPage(startYm,endYm,fileUlr,fmlUrl);
+                    saveDataToMysql(fmlUrl,wjtm,taskSign.getId(),endYm-startYm+1);
+                    bkb =  endYm ;
+                }
+
+            } else {
+
+            }
+
+            // 添加封面信息
+            String fmlUrl = FileUtils.getSysLocalFileUrl() + "archiveSplit/"+archiveId+"_fm_001.pdf";
+            getPdfByPage(1,1,fileUlr,fmlUrl);
+            saveDataToMysql(fmlUrl,"封面",taskSign.getId(),1);
+
+            // 卷内目录
+            String jnmuUrl = FileUtils.getSysLocalFileUrl() + "archiveSplit/"+archiveId+"_jnml_001.pdf";
+            getPdfByPage(2,2,fileUlr,jnmuUrl);
+            saveDataToMysql(jnmuUrl,"卷内目录",taskSign.getId(),1);
+
+            // 卷内备考表
+            String jnbkbUrl = FileUtils.getSysLocalFileUrl() + "archiveSplit/"+archiveId+"_jnbkb_001.pdf";
+            getPdfByPage(bkb+1,bkb+1,fileUlr,jnbkbUrl);
+            saveDataToMysql(jnbkbUrl,"卷内备考表",taskSign.getId(),1);
+
+            // 修改任务状态
+            String updateSql = "update u_archives_split_info set status=3 where id=" + taskSign.getId();
+            jdbcTemplate.execute(updateSql);
+            // 修改 u_archives_auto 为 已经分解
+            String updateSqlAuto = "update u_archives_auto set split_status=1 where id=" + taskSign.getArchiveId();
+            jdbcTemplate.execute(updateSqlAuto);
+
+            // 统计各个任务的结果
+            String taxkSql = "UPDATE u_task_split a set finished = (SELECT count(1) from u_archives_auto b where FIND_IN_SET(b.id,a.ids) and b.split_status=1) where FIND_IN_SET("+taskSign.getArchiveId()+",a.ids)  and a.type=3";
+            String taxkSql2 = "UPDATE u_task_split a set finished = (SELECT count(1) from u_archives_auto b where a.contract_id=b.contract_id) where a.id="+taskSign.getTaskId()+" and a.type=2";
+            jdbcTemplate.execute(taxkSql);
+            jdbcTemplate.execute(taxkSql2);
+
+            // 修改完成情况
+
+            RedisTemplate.delete("splithtml-" + archiveId);
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
     }
 
-    public void getPdfByPage(int startPage, int endPage, String filePath, String savePath) {
+    public static String pngToHtml(String fileUrl, String pKeyId) {
+        String lasHhtmlUrl = "";
+        try {
+            // 定义Python解释器路径和脚本路径
+            String pythonScript = "/Users/hongchuangyanfa/Desktop/PycharmProjects/splitPngToHtml.py";
+            // 构建命令
+            ProcessBuilder pb = new ProcessBuilder("python3", pythonScript, fileUrl, pKeyId);
+            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("html文件路径") >= 0 && htmlUrl.indexOf("_001.html") >= 0 && htmlUrl.indexOf("archiveSplit") >= 0) {
+                    lasHhtmlUrl = htmlUrl.replace("html文件路径", "");
+                }
+            }
+            // 等待进程结束
+            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 {
             InputStream inputStreamByUrl = FileUtils.getInputStreamByUrl(filePath);
             // 加载PDF文件
@@ -152,18 +344,51 @@ public class ArchiveController {
             final int DPI = 300;
 
             // 渲染指定页面(注意PDFBox使用0-based索引)
-            BufferedImage image = renderer.renderImage(pageNum - 1, DPI / 72f);
-
+            //BufferedImage image = renderer.renderImage(pageNum - 1, DPI / 72f);
+            BufferedImage image = renderer.renderImageWithDPI(0, DPI); // 0 表示第一页
             // 确保输出目录存在
             File outputFile = new File(outputPath);
             outputFile.getParentFile().mkdirs();
 
             // 保存为PNG格式(可改为JPG等)
             ImageIO.write(image, "PNG", outputFile);
+
             log.info("PDF页面已成功保存为图片: {}", outputPath);
+            inputStream.close();
+            document.close();
         } catch (Exception e) {
             log.error("PDF转图片失败", e);
             throw new RuntimeException("PDF转图片失败", e);
         }
     }
+
+    public int saveDataToMysql(String upFileUrl,String fileName,String fileId,int filePage) {
+        // 获取封面信息
+        long newPkId = SnowFlakeUtil.getId(); //主键Id
+        File fmfile = new File(upFileUrl);
+        if (fmfile.exists()) {
+            BladeFile bladeFile = this.newIOSSClient.uploadFile(fileName+".pdf", upFileUrl);
+            if (bladeFile != null && Func.isNotEmpty(bladeFile.getLink())) {
+                String FmPdfUrl = bladeFile.getLink();
+                String sql = " insert into u_archive_file( " +
+                        " id,project_id,contract_id,node_id,file_number,file_name,file_time,file_url,pdf_file_url,file_page,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, " +
+                        " 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, " +
+                        "        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");
+                return 500;
+            }
+        }else{
+            return 404;
+        }
+    }
 }

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

@@ -3107,7 +3107,25 @@ public class ExcelTabController extends BladeController {
                         InputStream inputStreamByUrl = FileUtils.getInputStreamByUrl(tableNode2.getHtmlUrl());
                         String htmlString = IoUtil.readToString(inputStreamByUrl);
                         Document doc = Jsoup.parse(htmlString);
-                        List<Elements> allElements = getBiaoTou(doc);
+                        // 模糊匹配
+                        Elements cbdw = doc.select("el-select[placeholder*=承包单位]");
+                        Elements htd = doc.select("el-select[placeholder*=合同段]");
+                        Elements jldw = doc.select("el-input[placeholder*=监理单位]");
+                        Elements jljg = doc.select("el-select[placeholder*=监理机构]");
+                        Elements jlr = doc.select("el-input[placeholder*=记录人]");
+                        Elements rq = doc.select("el-date-picker[placeholder*=日期]");
+                        Elements shr = doc.select("el-input[placeholder*=审核人]");
+                        Elements tqqk = doc.select("el-input[placeholder*=天气情况]");
+                        List<Elements> allElements=new ArrayList<>();
+                        allElements.add(cbdw);
+                        allElements.add(htd);
+                        allElements.add(jldw);
+                        allElements.add(jljg);
+                        allElements.add(jlr);
+                        allElements.add(rq);
+                        allElements.add(shr);
+                        allElements.add(tqqk);
+                        allElements=allElements.stream().filter(o->o!=null&&o.size()>0).collect(Collectors.toList());
                         if(allElements.size()>0){
                             for (String key : businessDataMap.get(0).keySet()) {
                                 String tabVal = businessDataMap.get(0).get(key) + "";
@@ -3162,10 +3180,8 @@ public class ExcelTabController extends BladeController {
                                 }
                             }
                             for (Elements element : allElements) {
-                                for (Element element1 : element) {
-                                    if(reData.containsKey(element1.attr("keyname"))){
-                                        resultMapList.put(element1.attr("keyname"),reData.get(element1.attr("keyname")));
-                                    }
+                                if(reData.containsKey(element.attr("keyname"))){
+                                    resultMapList.put(element.attr("keyname"),reData.get(element.attr("keyname")));
                                 }
                             }
                         }
@@ -3178,58 +3194,6 @@ public class ExcelTabController extends BladeController {
         return R.data(resultMapList);
     }
 
-    public List<Elements> getBiaoTou(Document doc){
-        // 模糊匹配
-        Elements cbdw = doc.select("el-select[placeholder*=承包单位]");
-        Elements cbdw1 = doc.select("el-input[placeholder*=承包单位]");
-        Elements htd = doc.select("el-select[placeholder*=合同段]");
-        Elements htd1 = doc.select("el-input[placeholder*=合同段]");
-        Elements jldw = doc.select("el-input[placeholder*=监理单位]");
-        Elements jljg = doc.select("el-select[placeholder*=监理机构]");
-        Elements jljg1 = doc.select("el-input[placeholder*=监理机构]");
-        Elements jlr = doc.select("el-input[placeholder*=记录人]");
-        Elements rq = doc.select("el-date-picker[placeholder*=日期]");
-        Elements shr = doc.select("el-input[placeholder*=审核人]");
-        Elements tqqk = doc.select("el-input[placeholder*=天气情况]");
-        Elements dwgc = doc.select("el-input[placeholder*=单位工程]");
-        Elements fxgc = doc.select("el-input[placeholder*=分项工程]");
-        Elements fbgc = doc.select("el-input[placeholder*=分部工程]");
-        Elements zh = doc.select("el-input[placeholder*=桩号]");
-        Elements bw = doc.select("el-input[placeholder*=部位]");
-        Elements xq = doc.select("el-select[placeholder*=星期]");
-        Elements tq = doc.select("el-input[placeholder*=天气]");
-        Elements qw = doc.select("el-input[placeholder*=气温_最高]");
-        Elements qw1 = doc.select("el-input[placeholder*=气温_最低]");
-        Elements sgdw = doc.select("el-input[placeholder*=施工单位]");
-        Elements hth = doc.select("el-input[placeholder*=合同号]");
-        Elements bh = doc.select("el-input[placeholder*=编号]");
-        List<Elements> allElements=new ArrayList<>();
-        allElements.add(cbdw);
-        allElements.add(cbdw1);
-        allElements.add(htd);
-        allElements.add(htd1);
-        allElements.add(jldw);
-        allElements.add(jljg);
-        allElements.add(jljg1);
-        allElements.add(jlr);
-        allElements.add(rq);
-        allElements.add(shr);
-        allElements.add(tqqk);
-        allElements.add(dwgc);
-        allElements.add(fxgc);
-        allElements.add(fbgc);
-        allElements.add(zh);
-        allElements.add(bw);
-        allElements.add(xq);
-        allElements.add(tq);
-        allElements.add(qw);
-        allElements.add(qw1);
-        allElements.add(sgdw);
-        allElements.add(hth);
-        allElements.add(bh);
-        return allElements.stream().filter(o->o!=null&&o.size()>0).distinct().collect(Collectors.toList());
-    }
-
 
 
     /**

+ 24 - 21
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreeSynchronousRecordController.java

@@ -93,29 +93,32 @@ public class WbsTreeSynchronousRecordController {
      */
     @PostMapping("add")
     public R<WbsTreeSynchronousRecord> insert(@RequestBody WbsTreeSynchronousRecord mWbsTreeSynchronousRecord) {
-        if (StringUtil.isBlank(mWbsTreeSynchronousRecord.getNodeId())) {
-            return R.fail("节点不能为空");
-        }else{
-            String[] split = mWbsTreeSynchronousRecord.getNodeId().split(",");
-            if(split.length > 100){
-                return R.fail("节点过多,如果勾选了父节点,请勿带子节点!");
+
+        if (mWbsTreeSynchronousRecord.getRange() == 1 || mWbsTreeSynchronousRecord.getRange() == 2) {
+            if (StringUtil.isBlank(mWbsTreeSynchronousRecord.getNodeId())) {
+                return R.fail("节点不能为空");
+            } else {
+                String[] split = mWbsTreeSynchronousRecord.getNodeId().split(",");
+                if (split.length > 100) {
+                    return R.fail("节点过多,如果勾选了父节点,请勿带子节点!");
+                }
+            }
+            if (StringUtil.isBlank(mWbsTreeSynchronousRecord.getType())) {
+                return R.fail("请选择同步类型");
+            }
+            if (mWbsTreeSynchronousRecord.getRange() == null) {
+                return R.fail("请选择同步范围");
             }
-        }
-        if (StringUtil.isBlank(mWbsTreeSynchronousRecord.getType())) {
-            return R.fail("请选择同步类型");
-        }
-        if (mWbsTreeSynchronousRecord.getRange() == null) {
-            return R.fail("请选择同步范围");
-        }
 
-        if (mWbsTreeSynchronousRecord.getRange() == 2 && StringUtil.isBlank(mWbsTreeSynchronousRecord.getContractRange())) {
-            return R.fail("请选择合同同步范围");
-        }
-        if (mWbsTreeSynchronousRecord.getProjectId() == null) {
-            return R.fail("项目Id为空");
-        }
-        if (mWbsTreeSynchronousRecord.getRange() == 1 && mWbsTreeSynchronousRecord.getTemplateId() == null) {
-            return R.fail("同步源为空");
+            if (mWbsTreeSynchronousRecord.getRange() == 2 && StringUtil.isBlank(mWbsTreeSynchronousRecord.getContractRange())) {
+                return R.fail("请选择合同同步范围");
+            }
+            if (mWbsTreeSynchronousRecord.getProjectId() == null) {
+                return R.fail("项目Id为空");
+            }
+            if (mWbsTreeSynchronousRecord.getRange() == 1 && mWbsTreeSynchronousRecord.getTemplateId() == null) {
+                return R.fail("同步源为空");
+            }
         }
 
         return R.data(this.mWbsTreeSynchronousRecordService.insert(mWbsTreeSynchronousRecord));

+ 14 - 4
blade-service/blade-manager/src/main/java/org/springblade/manager/job/SystemMsgJob.java

@@ -10,6 +10,7 @@ import org.springblade.manager.entity.SystemMsg;
 import org.springblade.manager.service.ISystemMsgService;
 import org.springblade.websocket.vo.MsgVO;
 import org.springblade.websocket.vo.SystMsgVO;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.scheduling.annotation.Scheduled;
@@ -34,13 +35,20 @@ public class SystemMsgJob {
 
     private final JdbcTemplate jdbcTemplate;
 
+    // 读取配置并设置默认值
+    @Value("${scheduler.enabled:true}")
+    private boolean schedulerEnabled;
+
     /**
      *  定时推送公告-取消公告-修改公告状态,不想污染日志,使用jdbc
      */
-    @Scheduled(cron = "0 */1 * * * ?")
+    @Scheduled(cron = "0/10 * * * * ?")
     public void autoUpdateMsgStatus(){
+        // 本地环境跳过执行(可添加日志输出)
+        if (!schedulerEnabled) return;
+
         /** 普通公告推送*/
-        String sql1 = "select * from m_system_msg where is_deleted = 0 and msg_type = 2 and push_status = 1 and push_date_time <= TIMESTAMPADD(SECOND, 1, NOW()) and push_end_date_time >= now()";
+        String sql1 = "select * from m_system_msg where is_deleted = 0 and msg_type = 2 and push_status = 1 and push_end_date_time >= now()";
         List<SystemMsg> list1 = jdbcTemplate.query(sql1,new BeanPropertyRowMapper<>(SystemMsg.class));
         if (list1.size() > 0){
             for (SystemMsg msg : list1) {
@@ -51,7 +59,8 @@ public class SystemMsgJob {
                     .in(SystemMsg::getId,list1.stream().map(SystemMsg::getId).collect(Collectors.toList())));
         }
         /** 维护公告推送*/
-        String sql2 = "select * from m_system_msg where is_deleted = 0 and msg_type = 1 and status = 1 and push_status = 1 and push_date_time >= now() and push_warn_date_time <= TIMESTAMPADD(SECOND, 1, NOW())";
+        //String sql2 = "select * from m_system_msg where is_deleted = 0 and msg_type = 1 and status = 1 and push_status = 1 and push_date_time >= now() and push_warn_date_time <= TIMESTAMPADD(SECOND, 1, NOW())";
+        String sql2 = "select * from m_system_msg where is_deleted = 0 and msg_type = 1 and status = 1 and push_status = 1 and push_warn_date_time>=NOW() ";
         List<SystemMsg> list2 = jdbcTemplate.query(sql2,new BeanPropertyRowMapper<>(SystemMsg.class));
         if (list2.size() > 0){
             for (SystemMsg msg : list2) {
@@ -62,7 +71,8 @@ public class SystemMsgJob {
                     .in(SystemMsg::getId,list2.stream().map(SystemMsg::getId).collect(Collectors.toList())));
         }
         /** 维护倒计时*/
-        String sql3 = "select * from m_system_msg where is_deleted = 0 and msg_type = 1 and status != 3 and TIMESTAMPADD(SECOND, 1, NOW()) >= push_count_down_date_time and now() < push_date_time ";
+      //  String sql3 = "select * from m_system_msg where is_deleted = 0 and msg_type = 1 and status != 3 and TIMESTAMPADD(SECOND, 1, NOW()) >= push_count_down_date_time and now() < push_date_time ";
+        String sql3 = "select * from m_system_msg where is_deleted = 0 and msg_type = 1 and status != 3 and push_count_down_date_time >=NOW() ";
         List<SystemMsg> list3 = jdbcTemplate.query(sql3,new BeanPropertyRowMapper<>(SystemMsg.class));
         if (list3.size() > 0){
             SystemMsg msg = list3.get(0);

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

@@ -77,6 +77,7 @@
         <result column="major_data_type" property="majorDataType"/>
         <result column="old_id" property="oldId"/>
         <result column="sort" property="sort"/>
+        <result column="node_class" property="nodeClass"/>
     </resultMap>
 
 
@@ -472,7 +473,8 @@
         d.id AS "key",
         old_id,
         major_data_type,
-        sort
+        sort,
+        node_class
         FROM m_wbs_tree_contract d
         WHERE
         d.is_deleted = 0

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

@@ -149,4 +149,10 @@ public interface WbsTreeContractMapper extends EasyBaseMapper<WbsTreeContract> {
 
     void updateSortByPId(@Param("pId") Long pId,
                          @Param("sort") Integer sort);
+
+    /**
+     * 批量修改排序
+     * @param resourceData
+     */
+    void updateSortBatchByPKeyId(List<WbsTreeContract> resourceData);
 }

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

@@ -823,6 +823,13 @@
             sort = sort +1
         where p_id = #{pId} and sort >= #{sort}
     </update>
+    <update id="updateSortBatchByPKeyId">
+        <foreach item="item" collection="list" separator=";">
+            UPDATE m_wbs_tree_contract
+            <set>sort = #{item.sort}</set>
+            where p_key_id = #{item.pKeyId}
+        </foreach>
+    </update>
 
     <select id="selectQueryValueLikeNodeName" resultMap="ResultMap">
         select *

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

@@ -146,4 +146,6 @@ public interface WbsTreePrivateMapper extends EasyBaseMapper<WbsTreePrivate> {
 
     void updateSortByPId(@Param("pId") Long pId,
                          @Param("sort") Integer sort);
+
+    void updateSortBatchByPKeyId(List<WbsTreePrivate> resourceData);
 }

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

@@ -934,6 +934,13 @@
         set sort = sort + 1
         where p_id = #{pId} and sort >= #{sort}
     </update>
+    <update id="updateSortBatchByPKeyId">
+        <foreach item="item" collection="list" separator=";">
+            UPDATE m_wbs_tree_private
+            <set>sort = #{item.sort}</set>
+            where p_key_id = #{item.pKeyId}
+        </foreach>
+    </update>
 
     <select id="linkNodeTreeBynodeId" resultType="java.lang.Long" >
         select p_key_id from m_wbs_tree_private where `type` = 1 and is_deleted = 0

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

@@ -574,8 +574,11 @@ public class ArchiveTreeContractSyncImpl {
                     continue;
                 }
                 if (treeContractVO6.getMajorDataType()!= null) {
-                    if (!majarDataType.contains(treeContractVO6.getMajorDataType().toString())) {
-                        continue;
+//                    if (!majarDataType.contains(treeContractVO6.getMajorDataType().toString())) {
+//                        continue;
+//                    }
+                    if (!shouldIncludeTreeContract(treeContractVO6, majarDataType)) {
+                        continue; // 跳过不符合条件的项
                     }
                 }
 
@@ -644,13 +647,19 @@ public class ArchiveTreeContractSyncImpl {
             //向上找到符合条件的level
             Long levelKeyId = findPKeyIdByNodeType(wbsTreeContractVO6Map,id,level);
 
+            Integer nodeClass = 1;
+            WbsTreeContractVO6 treeContractVO6 = wbsTreeContractVO6Map.get(id);
+            if (treeContractVO6!= null && treeContractVO6.getNodeClass()!= null ) {
+                nodeClass = treeContractVO6.getNodeClass();
+            }
+
             //根据map获取到对应的归档树节点nodeid
             Long nodeId = archiveTreeContractIdMap.get(levelKeyId);
             if (nodeId == null) {
                 continue;
             }
             //生成新增的归档文件
-            ArchiveFile archiveFile = getArchiveFile(info,nodeId,info.getWbsId(),contractIndfo,classify);
+            ArchiveFile archiveFile = getArchiveFile(info,nodeId,info.getWbsId(),contractIndfo,classify,nodeClass);
             if (archiveFile != null) {
                 newArchiveFiles.add(archiveFile);
             }
@@ -660,6 +669,46 @@ public class ArchiveTreeContractSyncImpl {
         handleAddandUpdateFiles(newArchiveFiles,updateArchiveFiles);
     }
 
+
+    /**
+     * 针对质量评定的处理
+     * @param treeContractVO6
+     * @param majarDataType
+     * @return
+     */
+    public boolean shouldIncludeTreeContract(WbsTreeContractVO6 treeContractVO6, String majarDataType) {
+        if (treeContractVO6.getMajorDataType() == null) {
+            return false; // 如果 majorDataType 为空,过滤
+        }
+
+        String currentMajor = treeContractVO6.getMajorDataType().toString();
+
+        // 检查是否是特殊类型 (2,8,9)
+        if (currentMajor.equals("2") || currentMajor.equals("8") || currentMajor.equals("9")) {
+            // 特殊类型处理:根据 nodeType 匹配对应的数字
+            if (treeContractVO6.getNodeType() != null) {
+                switch (treeContractVO6.getNodeType()) {
+                    case 1: // 单位工程 → 匹配 2
+                        return majarDataType.contains("2");
+                    case 2: // 分部工程 → 匹配 8
+                    case 3: // 子分部工程 → 匹配 8
+                        return majarDataType.contains("8");
+                    case 4: // 分项工程 → 匹配 9
+                    case 5: // 子分项工程 → 匹配 9
+                        return majarDataType.contains("9");
+                    default:
+                        return majarDataType.contains(currentMajor);
+                }
+            } else {
+                // nodeType 为空时,按原逻辑处理
+                return majarDataType.contains(currentMajor);
+            }
+        } else {
+            // 非特殊类型 (1,4 等):直接匹配
+            return majarDataType.contains(currentMajor);
+        }
+    }
+
     /**
      * 刷新文件
      * @param newArchiveFiles
@@ -732,7 +781,7 @@ public class ArchiveTreeContractSyncImpl {
         }
     }
 
-    public ArchiveFile getArchiveFile(InformationQuery query,Long nodeId,Long keyId,ContractInfo contractIndfo,Integer classify) {
+    public ArchiveFile getArchiveFile(InformationQuery query,Long nodeId,Long keyId,ContractInfo contractIndfo,Integer classify,Integer nodeClass) {
         ArchiveFile archiveFile = new ArchiveFile();
         archiveFile.setNodeId(nodeId.toString());
         archiveFile.setNodeExtId(keyId);
@@ -759,7 +808,7 @@ public class ArchiveTreeContractSyncImpl {
             archiveFile.setFileTime(businessTime);
         }
 
-        archiveFile.setSourceType(1);
+        archiveFile.setSourceType(nodeClass);
         archiveFile.setIsArchive(0);
 
         //设置认证

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

@@ -39,6 +39,7 @@ import org.springblade.manager.utils.FileUtils;
 import org.springblade.manager.vo.TextdictBy345VO;
 import org.springblade.manager.vo.TextdictInfoVO;
 import org.springblade.system.cache.ParamCache;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 

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

@@ -1,6 +1,7 @@
 package org.springblade.manager.service.impl;
 
 import cn.hutool.core.date.DateTime;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.core.tool.utils.CollectionUtil;
@@ -13,6 +14,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -64,10 +66,15 @@ public class WbsSynchronousEViSaServiceImpl {
 
     @Transactional(rollbackFor = Exception.class)
     public void syncPrivateForceForm(WbsTreePrivate wbsTreePrivate, String nodeId, Long id) {
+        WbsTreePrivate wbsTreePrivate1 = wbsTreePrivateMapper.selectById(nodeId);
+
         wbsTreePrivateMapper.update(null, Wrappers.<WbsTreePrivate>lambdaUpdate()
                 .set(WbsTreePrivate::getExcelId, wbsTreePrivate.getExcelId())
                 .set(WbsTreePrivate::getInitTableName, wbsTreePrivate.getInitTableName())
+                .set(WbsTreePrivate::getInitTableId, wbsTreePrivate.getInitTableId())
                 .set(WbsTreePrivate::getHtmlUrl, wbsTreePrivate.getHtmlUrl())
+                .set(StringUtils.isBlank(wbsTreePrivate.getFullName()),WbsTreePrivate::getFullName, wbsTreePrivate1.getNodeName())
+                .set(WbsTreePrivate::getNodeName, wbsTreePrivate.getNodeName())
                 .in(WbsTreePrivate::getPKeyId, nodeId)
         );
         synchronousRecordMapper.update(null, Wrappers.<WbsTreeSynchronousRecord>lambdaUpdate()
@@ -80,28 +87,113 @@ public class WbsSynchronousEViSaServiceImpl {
 
 
     @Transactional(rollbackFor = Exception.class)
-    public void updatePrivate(Long createUserId, List<WbsTreePrivate> list ) {
+    public void updatePrivate(String type, Long pId, Long createUserId, List<WbsTreePrivate> list) {
+        //排序调整
+        if (type.contains("7")) {
+            list.sort(Comparator.comparingInt(WbsTreePrivate::getSort));
+            List<Long> pKeyIds = list.stream().map(WbsTreePrivate::getPKeyId).collect(Collectors.toList());
+            //获取节点下的当前表单
+            List<WbsTreePrivate> resourceData = wbsTreePrivateMapper.selectList(Wrappers.<WbsTreePrivate>lambdaQuery()
+                    .select(WbsTreePrivate::getPKeyId, WbsTreePrivate::getSort)
+                    .eq(WbsTreePrivate::getPId, pId)
+                    .eq(WbsTreePrivate::getIsDeleted, 0)
+                    .notIn(WbsTreePrivate::getPKeyId, pKeyIds)
+                    .orderByAsc(WbsTreePrivate::getSort));
+            if (CollectionUtil.isNotEmpty(resourceData)) {
+                for (int i = 0; i < resourceData.size(); i++) {
+                    resourceData.get(i).setSort(i + 1);
+                }
+                //修改排序为连续排序
+                wbsTreePrivateMapper.updateSortBatchByPKeyId(resourceData);
+
+            }
+
+            for (WbsTreePrivate wbsTreePrivate : list) {
+                wbsTreePrivateMapper.updateSortByPId(pId, wbsTreePrivate.getSort());
+            }
+        }
+
         for (WbsTreePrivate treePrivate : list) {
             treePrivate.setUpdateTime(DateTime.now());
             treePrivate.setUpdateUser(createUserId);
             wbsTreePrivateMapper.updateById(treePrivate);
         }
+
+        //更新之后再去修改所有的排序
+        if (type.contains("7")) {
+            //获取节点下的当前表单
+            List<WbsTreePrivate> resourceData = wbsTreePrivateMapper.selectList(Wrappers.<WbsTreePrivate>lambdaQuery()
+                    .select(WbsTreePrivate::getPKeyId, WbsTreePrivate::getSort)
+                    .eq(WbsTreePrivate::getPId, pId)
+                    .eq(WbsTreePrivate::getIsDeleted, 0)
+                    .orderByAsc(WbsTreePrivate::getSort));
+            if (CollectionUtil.isNotEmpty(resourceData)) {
+                for (int i = 0; i < resourceData.size(); i++) {
+                    resourceData.get(i).setSort(i + 1);
+                }
+                //修改排序为连续排序
+                wbsTreePrivateMapper.updateSortBatchByPKeyId(resourceData);
+            }
+        }
+
     }
 
     @Transactional(rollbackFor = Exception.class)
-    public void updateContract(Long createUserId, List<WbsTreeContract> list) {
+    public void updateContract(String type, Long pId, Long createUserId, List<WbsTreeContract> list) {
+        //排序调整
+        if (type.contains("7")) {
+            list.sort(Comparator.comparingInt(WbsTreeContract::getSort));
+
+            List<Long> pKeyIds = list.stream().map(WbsTreeContract::getPKeyId).collect(Collectors.toList());
+            //获取节点下的当前表单
+            List<WbsTreeContract> resourceData = wbsTreeContractMapper.selectList(Wrappers.<WbsTreeContract>lambdaQuery()
+                    .select(WbsTreeContract::getPKeyId, WbsTreeContract::getSort)
+                    .eq(WbsTreeContract::getPId, pId)
+                    .eq(WbsTreeContract::getIsDeleted, 0)
+                    .notIn(WbsTreeContract::getPKeyId, pKeyIds)
+                    .orderByAsc(WbsTreeContract::getSort));
+            if (CollectionUtil.isNotEmpty(resourceData)) {
+                for (int i = 0; i < resourceData.size(); i++) {
+                    resourceData.get(i).setSort(i + 1);
+                }
+                //修改排序为连续排序
+                wbsTreeContractMapper.updateSortBatchByPKeyId(resourceData);
+            }
+
+            for (WbsTreeContract wbsTreePrivate : list) {
+                wbsTreeContractMapper.updateSortByPId(pId, wbsTreePrivate.getSort());
+            }
+        }
+
         for (WbsTreeContract treeContract : list) {
             treeContract.setUpdateTime(DateTime.now());
             treeContract.setUpdateUser(createUserId);
             wbsTreeContractMapper.updateById(treeContract);
         }
+
+        //排序调整
+        if (type.contains("7")) {
+            //获取节点下的当前表单
+            List<WbsTreeContract> resourceData = wbsTreeContractMapper.selectList(Wrappers.<WbsTreeContract>lambdaQuery()
+                    .select(WbsTreeContract::getPKeyId, WbsTreeContract::getSort)
+                    .eq(WbsTreeContract::getPId, pId)
+                    .eq(WbsTreeContract::getIsDeleted, 0)
+                    .orderByAsc(WbsTreeContract::getSort));
+            if (CollectionUtil.isNotEmpty(resourceData)) {
+                for (int i = 0; i < resourceData.size(); i++) {
+                    resourceData.get(i).setSort(i + 1);
+                }
+                //修改排序为连续排序
+                wbsTreeContractMapper.updateSortBatchByPKeyId(resourceData);
+            }
+        }
     }
 
     @Transactional(rollbackFor = Exception.class)
-    public void saveFormula(WbsTreeSynchronousRecord wbsTreeSynchronousRecord, List<WbsTreePrivate> list){
+    public void saveFormula(WbsTreeSynchronousRecord wbsTreeSynchronousRecord, List<WbsTreePrivate> list) {
         Map<Long, List<WbsTreePrivate>> collect = list.stream().collect(Collectors.groupingBy(WbsTreePrivate::getParentId));
         Set<Long> ids = collect.keySet();
-        if(CollectionUtil.isEmpty(ids)){
+        if (CollectionUtil.isEmpty(ids)) {
             return;
         }
         List<ElementFormulaMapping> elementFormulaMappings = elementFormulaMappingService.list(Wrappers.<ElementFormulaMapping>lambdaQuery()

+ 97 - 47
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsSynchronousServiceImpl.java

@@ -170,6 +170,9 @@ public class WbsSynchronousServiceImpl {
             throw new ServiceException("不能选中多个节点");
         }
         String formIds = wbsTreeSynchronousRecord.getFormIds();
+        if (formIds.contains(",")) {
+            throw new ServiceException("不能选中多个节点");
+        }
         //选中的表单
         WbsTreePrivate wbsTreePrivate = wbsTreePrivateMapper.selectById(formIds);
         if (wbsTreePrivate == null) {
@@ -513,16 +516,9 @@ public class WbsSynchronousServiceImpl {
         for (Long pId : pIds) {
             nodeNumEnd++;
             List<WbsTreePrivate> list = collect1.get(pId);
-            //排序调整
-            if (wbsTreeSynchronousRecord.getType().contains("7")) {
-                list.sort(Comparator.comparingInt(WbsTreePrivate::getSort));
-                for (WbsTreePrivate wbsTreePrivate : list) {
-                    wbsTreePrivateMapper.updateSortByPId(pId, wbsTreePrivate.getSort());
-                }
-            }
 
             //更新最新节点
-            wbsSynchronousEViSaService.updatePrivate(wbsTreeSynchronousRecord.getCreateUserId(), list);
+            wbsSynchronousEViSaService.updatePrivate(wbsTreeSynchronousRecord.getType(), pId, wbsTreeSynchronousRecord.getCreateUserId(), list);
 
             synchronousRecordMapper.update(null, Wrappers.<WbsTreeSynchronousRecord>lambdaUpdate()
                     .set(WbsTreeSynchronousRecord::getNodeNumEnd, nodeNumEnd)
@@ -798,15 +794,8 @@ public class WbsSynchronousServiceImpl {
         for (Long pId : pIds) {
             nodeNumEnd++;
             List<WbsTreeContract> list = collect1.get(pId);
-            //排序调整
-            if (wbsTreeSynchronousRecord.getType().contains("7")) {
-                list.sort(Comparator.comparingInt(WbsTreeContract::getSort));
-                for (WbsTreeContract wbsTreeContract : list) {
-                    wbsTreePrivateMapper.updateSortByPId(pId, wbsTreeContract.getSort());
-                }
-            }
 
-            wbsSynchronousEViSaService.updateContract(wbsTreeSynchronousRecord.getCreateUserId(), list);
+            wbsSynchronousEViSaService.updateContract(wbsTreeSynchronousRecord.getType(), pId, wbsTreeSynchronousRecord.getCreateUserId(), list);
             synchronousRecordMapper.update(null, Wrappers.<WbsTreeSynchronousRecord>lambdaUpdate()
                     .set(WbsTreeSynchronousRecord::getNodeNumEnd, nodeNumEnd)
                     .set(WbsTreeSynchronousRecord::getUpdateTime, DateTime.now())
@@ -932,28 +921,58 @@ public class WbsSynchronousServiceImpl {
             List<List<Long>> partition = Lists.partition(pIds, 100);
 
             for (List<Long> data : partition) {
-                for (Long datum : data) {
-                    List<WbsTreePrivate> list = collect.get(datum);
-                    //修改排序
+                for (Long pId : data) {
+                    List<WbsTreePrivate> list = collect.get(pId);
+                    //排序调整
                     if (wbsTreeSynchronousRecord.getType().contains("7")) {
                         list.sort(Comparator.comparingInt(WbsTreePrivate::getSort));
-                        for (WbsTreePrivate wbsTreePrivate : list) {
-                            Integer sort = wbsTreePrivate.getSort();
-                            if (sort != null) {
-                                wbsTreePrivateMapper.updateSortByPId(datum, wbsTreePrivate.getSort());
+                        //获取节点下的当前表单
+                        List<WbsTreePrivate> resourceData = wbsTreePrivateMapper.selectList(Wrappers.<WbsTreePrivate>lambdaQuery()
+                                .select(WbsTreePrivate::getPKeyId, WbsTreePrivate::getSort)
+                                .eq(WbsTreePrivate::getPId, pId)
+                                .eq(WbsTreePrivate::getIsDeleted, 0)
+                                .orderByAsc(WbsTreePrivate::getSort));
+                        if (CollectionUtil.isNotEmpty(resourceData)) {
+                            for (int i = 0; i < resourceData.size(); i++) {
+                                resourceData.get(i).setSort(i + 1);
                             }
+                            //修改排序为连续排序
+                            wbsTreePrivateMapper.updateSortBatchByPKeyId(resourceData);
+                        }
+
+
+                        for (WbsTreePrivate wbsTreePrivate : list) {
+                            wbsTreePrivateMapper.updateSortByPId(pId, wbsTreePrivate.getSort());
                         }
                     }
+
                     boolean b = saveData.addAll(list);
-                }
 
-                //单个批次一个事务,只会回滚当前批次数据
-                Integer i = wbsTreePrivateMapper.insertBatchSomeColumn(saveData);
-                //如果失败  -- - - - - 继续执行   或者把当前节点的p_key_id 记录到某个地方 方便后续处理
-                if (i == 0) {
-                    List<Long> collect1 = addData.stream().map(WbsTreePrivate::getPKeyId).collect(Collectors.toList());
-                    //这里可以保存到数据库指定错误日志表
-                    throw new ServiceException("添加失败:" + StringUtil.join(collect1, ","));
+                    //单个批次一个事务,只会回滚当前批次数据
+                    Integer i = wbsTreePrivateMapper.insertBatchSomeColumn(saveData);
+                    //如果失败  -- - - - - 继续执行   或者把当前节点的p_key_id 记录到某个地方 方便后续处理
+                    if (i == 0) {
+                        List<Long> collect1 = addData.stream().map(WbsTreePrivate::getPKeyId).collect(Collectors.toList());
+                        //这里可以保存到数据库指定错误日志表
+                        throw new ServiceException("添加失败:" + StringUtil.join(collect1, ","));
+                    }else{
+                        //排序调整-连续排序
+                        if (wbsTreeSynchronousRecord.getType().contains("7")) {
+                            //获取节点下的当前表单
+                            List<WbsTreePrivate> resourceData = wbsTreePrivateMapper.selectList(Wrappers.<WbsTreePrivate>lambdaQuery()
+                                    .select(WbsTreePrivate::getPKeyId, WbsTreePrivate::getSort)
+                                    .eq(WbsTreePrivate::getPId, pId)
+                                    .eq(WbsTreePrivate::getIsDeleted, 0)
+                                    .orderByAsc(WbsTreePrivate::getSort));
+                            if (CollectionUtil.isNotEmpty(resourceData)) {
+                                for (int j = 0; j < resourceData.size(); j++) {
+                                    resourceData.get(j).setSort(j + 1);
+                                }
+                                //修改排序为连续排序
+                                wbsTreePrivateMapper.updateSortBatchByPKeyId(resourceData);
+                            }
+                        }
+                    }
                 }
             }
         }
@@ -1047,29 +1066,60 @@ public class WbsSynchronousServiceImpl {
         //按最小节点批量新增
         List<List<Long>> partition = Lists.partition(pIds, 100);
         for (List<Long> data : partition) {
-            for (Long datum : data) {
-                List<WbsTreeContract> list = collect.get(datum);
-                //修改排序
+            for (Long pId : data) {
+                List<WbsTreeContract> list = collect.get(pId);
+                //排序调整
                 if (wbsTreeSynchronousRecord.getType().contains("7")) {
                     list.sort(Comparator.comparingInt(WbsTreeContract::getSort));
-                    for (WbsTreeContract wbsTreeContract : list) {
-                        Integer sort = wbsTreeContract.getSort();
-                        if (sort != null) {
-                            wbsTreeContractMapper.updateSortByPId(datum, wbsTreeContract.getSort());
+                    //获取节点下的当前表单
+                    List<WbsTreeContract> resourceData = wbsTreeContractMapper.selectList(Wrappers.<WbsTreeContract>lambdaQuery()
+                            .select(WbsTreeContract::getPKeyId, WbsTreeContract::getSort)
+                            .eq(WbsTreeContract::getPId, pId)
+                            .eq(WbsTreeContract::getIsDeleted, 0)
+                            .orderByAsc(WbsTreeContract::getSort));
+                    if (CollectionUtil.isNotEmpty(resourceData)) {
+                        for (int i = 0; i < resourceData.size(); i++) {
+                            resourceData.get(i).setSort(i + 1);
                         }
+                        //修改排序为连续排序
+                        wbsTreeContractMapper.updateSortBatchByPKeyId(resourceData);
+                    }
+
+
+                    for (WbsTreeContract wbsTreePrivate : list) {
+                        wbsTreeContractMapper.updateSortByPId(pId, wbsTreePrivate.getSort());
                     }
                 }
                 boolean b = saveData.addAll(list);
-            }
 
-            //单个批次一个事务,只会回滚当前批次数据
-            Integer i = wbsTreeContractMapper.insertBatchSomeColumn(saveData);
-            //如果失败  -- - - - - 继续执行   或者把当前节点的p_key_id 记录到某个地方 方便后续处理
-            if (i == 0) {
-                List<Long> collect1 = addData.stream().map(WbsTreeContract::getPKeyId).collect(Collectors.toList());
-                //这里可以保存到数据库指定错误日志表
-                //这里可以保存到数据库指定错误日志表
-                throw new ServiceException("添加失败:" + StringUtil.join(collect1, ","));
+
+                //单个批次一个事务,只会回滚当前批次数据
+                Integer i = wbsTreeContractMapper.insertBatchSomeColumn(saveData);
+                //如果失败  -- - - - - 继续执行   或者把当前节点的p_key_id 记录到某个地方 方便后续处理
+                if (i == 0) {
+                    List<Long> collect1 = addData.stream().map(WbsTreeContract::getPKeyId).collect(Collectors.toList());
+                    //这里可以保存到数据库指定错误日志表
+                    //这里可以保存到数据库指定错误日志表
+                    throw new ServiceException("添加失败:" + StringUtil.join(collect1, ","));
+                }else{
+                    //排序调整
+                    if (wbsTreeSynchronousRecord.getType().contains("7")) {
+                        //获取节点下的当前表单
+                        List<WbsTreeContract> resourceData = wbsTreeContractMapper.selectList(Wrappers.<WbsTreeContract>lambdaQuery()
+                                .select(WbsTreeContract::getPKeyId, WbsTreeContract::getSort)
+                                .eq(WbsTreeContract::getPId, pId)
+                                .eq(WbsTreeContract::getIsDeleted, 0)
+                                .orderByAsc(WbsTreeContract::getSort));
+                        if (CollectionUtil.isNotEmpty(resourceData)) {
+                            for (int j = 0; i < resourceData.size(); j++) {
+                                resourceData.get(j).setSort(j + 1);
+                            }
+                            //修改排序为连续排序
+                            wbsTreeContractMapper.updateSortBatchByPKeyId(resourceData);
+                        }
+
+                    }
+                }
             }
         }
     }

+ 260 - 9
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeContractServiceImpl.java

@@ -83,6 +83,8 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.math.MathContext;
+import java.math.RoundingMode;
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Function;
@@ -1656,22 +1658,24 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                     sgTabMaps.put(s + "---" + wbsTreeContract.getPKeyId(), wbsTreeContract.getInitTableName());
                 }
             }
-            //获取 CL08水准测量记录表(监理)的 实际标高、高程偏差 对应字段
+            //获取 CL08水准测量记录表(监理)的 实际标高、高程偏差 对应字段 m_20220928134702_1574999102784012288
             String leveling = "CL08水准测量记录表(监理)";
+            String levelingTableName = "m_20220928134702_1574999102784012288";
 
-            String designedElevation = "设标高";
+            String designedElevation = "设标高";
             //负值+0/1 正值-0/1
-            String heightDeviation = "高偏差";
+            String heightDeviation = "高偏差";
             //设置标高 + (高度偏差 / 100)
             String actualElevation = "实际标高";
 
-
+            //m_20220928134725_1574999197613031424
             String planePosition = "CL10平面位置检测记录表(监理)";
+            String planePositionTableName = "m_20220928134725_1574999197613031424";
 
             //负值+0/1 正值-0/1
             String difference = "差值";
             //差值X + 差值Y 的开平方
-            String deviation = "偏";
+            String deviation = "偏";
             //指定表单和指定字段
             Map<String, Map<String, String>> dataMaps = new HashMap<>();
 
@@ -1696,7 +1700,7 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                 HashMap<String, String> map = new HashMap<>();
 
                 //判断当前表单是否是CL08、CL10
-                if (wbsTreeContract.getNodeName().contains(leveling) || wbsTreeContract.getNodeName().contains(planePosition)) {
+                if (levelingTableName.equals(wbsTreeContract.getInitTableName()) || planePositionTableName.equals(wbsTreeContract.getInitTableName())) {
                     TableInfo tableInfo = tableInfoMapper.selectOne(Wrappers.<TableInfo>lambdaQuery()
                             .eq(TableInfo::getTabEnName, wbsTreeContract.getInitTableName()));
                     List<WbsFormElement> wbsFormElements = wbsFormElementMapper.selectList(Wrappers.<WbsFormElement>lambdaQuery()
@@ -1726,13 +1730,15 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                     }
 
                     //存储
-                    dataMaps.put(wbsTreeContract.getNodeName(),map);
+                    dataMaps.put(wbsTreeContract.getInitTableName(),map);
                 }
             }
 
             //构造表数据
             List<InsertDataVO> resultData = new LinkedList<>();
-            this.syncTabDataImpl(sgTabMaps, jlTabMaps, resultData);
+            //坐标
+            Map<String,Set<String>> coordinateMap = new HashMap<>();
+            this.syncTabDataImpl(sgTabMaps, jlTabMaps, resultData,coordinateMap);
 
             //入库处理
             if (resultData.size() > 0) {
@@ -1816,6 +1822,209 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                                 filedNames.add(vo.getName());
                             }
                         }
+
+                        Map<String, String> stringStringMap = dataMaps.get(initTabName);
+
+                        //CL08水准测量记录表(监理)
+                        if(levelingTableName.equals(initTabName)){
+                            //设计标高
+                            String designedElevationNew = stringStringMap.get(designedElevation);
+                            HashMap<Integer, BigDecimal> designedElevationNewMap = new HashMap<>();
+                            //偏差
+                            String heightDeviationNew = stringStringMap.get(heightDeviation);
+                            HashMap<Integer, BigDecimal> heightDeviationNewMap = new HashMap<>();
+                            //实际标高
+                            String actualElevationNew = stringStringMap.get(actualElevation);
+
+                            //记录数量
+                            Integer rowMin = null;
+                            Integer rowMax = null;
+
+                            for (int i = 0; i < keys.size(); i++) {
+                                if(!Objects.equals(keys.get(i),designedElevationNew) && !Objects.equals(keys.get(i),heightDeviationNew)){
+                                    continue;
+                                }
+
+
+                                String value = values.get(i);
+                                //拆分数据
+                                String[] split1 = value.split("☆");
+
+                                List<String> heightDeviationList = new ArrayList<>();
+                                for (String s : split1) {
+                                    String[] split2 = s.split("_\\^_");
+                                    int rowNum = Integer.parseInt(split2[1].split("_")[0]);
+                                    //获取最大行数
+                                    if(rowMax == null){
+                                        rowMax = rowNum;
+                                    }else if(rowMax < rowNum){
+                                        rowMax = rowNum;
+                                    }
+                                    //获取最小行数
+                                    if(rowMin == null){
+                                        rowMin = rowNum;
+                                    }else if(rowMin > rowNum){
+                                        rowMin = rowNum;
+                                    }
+
+                                    if (keys.get(i).equals(designedElevationNew)) {
+                                        //设计标高
+                                        designedElevationNewMap.put(rowNum, new BigDecimal(split2[0]));
+                                    } else if (keys.get(i).equals(heightDeviationNew)){
+                                        if(StringUtils.isNotEmpty(split2[0])){
+                                            double v = Double.parseDouble(split2[0]);
+                                            //随机+ - 0/1
+                                            Random random = new Random();
+                                            int adjustment = random.nextInt(2);
+                                            if(v > 0){
+                                                v = v - adjustment;
+                                            }else{
+                                                v = v + adjustment;
+                                            }
+
+                                            //高度偏差
+                                            heightDeviationNewMap.put(rowNum, BigDecimal.valueOf(v));
+
+                                            heightDeviationList.add(new BigDecimal(v).setScale(0,RoundingMode.HALF_UP).intValue() + "_^_"+ split2[1]);
+                                        }
+                                    }
+                                }
+                                //设置偏高的值
+                                if(CollectionUtil.isNotEmpty(heightDeviationList)){
+                                    values.set(i, String.join("☆",heightDeviationList));
+                                }
+                            }
+                            if(rowMin==null){
+                                continue;
+                            }
+                            List<String> list = new ArrayList<>();
+
+                            //获取当前key对应的坐标
+                            Set<String> strings = coordinateMap.get(initTabName);
+                            String index = null;
+                            for (String string : strings) {
+                                String[] split = string.split("__");
+                                if(Objects.equals(split[0],actualElevationNew)){
+                                    index = split[1];
+                                }
+                            }
+                            //按照最小行数来计算
+                            for (int i = rowMin; i <= rowMax; i++) {
+                                BigDecimal designed = designedElevationNewMap.get(i);
+                                BigDecimal height = heightDeviationNewMap.get(i);
+
+                                if(designed == null || height == null){
+                                    continue;
+                                }
+                                BigDecimal v = designed.add(height.divide(new BigDecimal(1000)));
+                                //第5列,索引为4
+                                list.add(v.doubleValue() + "_^_"+ i + "_" + index);
+                            }
+                            //未获取到当前key的坐标就不设置值
+                            if(index == null){
+                                continue;
+                            }
+                            //设置实际标高的值
+                            values.set(keys.indexOf(actualElevationNew), String.join("☆",list));
+                        }else if(planePositionTableName.equals(initTabName)){
+                            //CL10平面位置检测记录表(监理)
+                            //差值
+                            String differenceNewX = stringStringMap.get(difference + "X");
+                            HashMap<Integer, BigDecimal> differenceNewXMap = new HashMap<>();
+
+                            String differenceNewY = stringStringMap.get(difference + "Y");
+                            HashMap<Integer, BigDecimal> differenceNewYMap = new HashMap<>();
+
+
+                            String deviationNew = stringStringMap.get(deviation);
+                            //记录数量
+                            Integer rowMin = null;
+                            Integer rowMax = null;
+                            for (int i = 0; i < keys.size(); i++) {
+                                if(!Objects.equals(keys.get(i),differenceNewX) && !Objects.equals(keys.get(i),differenceNewY)){
+                                    continue;
+                                }
+
+                                String value = values.get(i);
+                                //拆分数据
+                                String[] split1 = value.split("☆");
+
+                                List<String> list = new ArrayList<>();
+
+                                for (String s : split1) {
+                                    String[] split2 = s.split("_\\^_");
+                                    int rowNum = Integer.parseInt(split2[1].split("_")[0]);
+                                    //获取最大行数
+                                    if(rowMax == null){
+                                        rowMax = rowNum;
+                                    }else if(rowMax < rowNum){
+                                        rowMax = rowNum;
+                                    }
+                                    //获取最小行数
+                                    if(rowMin == null){
+                                        rowMin = rowNum;
+                                    }else if(rowMin > rowNum){
+                                        rowMin = rowNum;
+                                    }
+                                    if(StringUtils.isNotEmpty(split2[0])){
+                                        Integer v = Integer.parseInt(split2[0]);
+                                        //随机+ - 0/1
+                                        Random random = new Random();
+                                        int adjustment = random.nextInt(2);
+                                        if(v > 0){
+                                            v = v - adjustment;
+                                        }else{
+                                            v = v + adjustment;
+                                        }
+                                        if (keys.get(i).equals(differenceNewX)) {
+                                            //偏差X
+                                            differenceNewXMap.put(rowNum, new BigDecimal(split2[0]));
+                                        } else if (keys.get(i).equals(differenceNewY)){
+                                            //偏差Y
+                                            differenceNewYMap.put(rowNum, BigDecimal.valueOf(v));
+                                        }
+                                        list.add(v + "_^_"+ split2[1]);
+                                    }
+                                }
+                                values.set(i, String.join("☆",list));
+                            }
+                            if(rowMin==null){
+                                continue;
+                            }
+                            List<String> list = new ArrayList<>();
+                            //获取当前key对应的坐标
+                            Set<String> strings = coordinateMap.get(initTabName);
+                            String index = null;
+                            for (String string : strings) {
+                                String[] split = string.split("__");
+                                if(Objects.equals(split[0],deviationNew)){
+                                    index = split[1];
+                                }
+                            }
+                            //按照最小行数来计算
+                            for (int i = rowMin; i <= rowMax; i++) {
+                                BigDecimal x = differenceNewXMap.get(i);
+                                BigDecimal y = differenceNewYMap.get(i);
+
+                                if(x == null || y == null){
+                                    continue;
+                                }
+                                BigDecimal sqrt = sqrt(x.multiply(x).add(y.multiply(y)), 0);
+
+                                //第9列,索引为8
+                                list.add(sqrt.intValue() + "_^_"+ i + "_" + index);
+                            }
+                            //未获取到当前key的坐标就不设置值
+                            if(index == null){
+                                continue;
+                            }
+                            //设置实际标高的值
+                            values.set(keys.indexOf(deviationNew), String.join("☆",list));
+                        }
+
+
+
+
                         if (keys.size() > 0 && values.size() > 0 && keys.size() == values.size()) {
                             //alter SQL(扩容字段长度)
                             StringBuilder exStrBuilder = new StringBuilder();
@@ -1920,6 +2129,32 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
         }
     }
 
+    // 牛顿迭代法实现开平方
+    public  BigDecimal sqrt(BigDecimal value, int precision) {
+        // 检查负数输入
+        if (value.compareTo(BigDecimal.ZERO) < 0) {
+            throw new ArithmeticException("不能对负数开平方");
+        }
+
+        // 精度设置(保留小数位 + 额外2位保证精度)
+        MathContext mc = new MathContext(precision + 2, RoundingMode.HALF_EVEN);
+
+        // 初始值 = value / 2
+        BigDecimal guess = value.divide(BigDecimal.valueOf(2), mc);
+        BigDecimal lastGuess;
+
+        // 牛顿迭代公式:xₙ₊₁ = (xₙ + value/xₙ)/2
+        do {
+            lastGuess = guess;
+            guess = value.divide(guess, mc).add(guess)
+                    .divide(BigDecimal.valueOf(2), mc);
+        } while (guess.subtract(lastGuess).abs().compareTo(
+                BigDecimal.valueOf(1, precision + 1)) > 0); // 精度控制
+
+        // 返回最终结果(精确到指定小数位)
+        return guess.setScale(precision, RoundingMode.HALF_UP);
+    }
+
     /**
      * 构造数据
      *
@@ -1929,7 +2164,7 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
      * @throws Exception
      */
     private void syncTabDataImpl
-    (Map<String, String> sgData, Map<String, String> jlData, List<InsertDataVO> resultData) throws
+    (Map<String, String> sgData, Map<String, String> jlData, List<InsertDataVO> resultData, Map<String,Set<String>> coordinateMap) throws
             Exception {
         for (Map.Entry<String, String> sgTab : sgData.entrySet()) { //质检表
             String[] split = sgTab.getKey().split("---");
@@ -1948,6 +2183,22 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                 //表的代码名称相同,就复制数据,例如:G10=G10
                 if (nodeNameRe.equals(nodeNameReJL)) {
                     String htmlStringJL = this.getHtmlString(pKeyIdJL);
+
+                    //解析html坐标,生成key与keyName的映射关系
+                    if (StringUtils.isNotEmpty(htmlStringJL)) {
+                        Document doc = Jsoup.parse(htmlStringJL);
+                        Elements select = doc.select("[id]");
+                        HashSet<String> strings = new HashSet<>();
+                        for (Element element : select) {
+                            String id = element.id();
+                            String[] split1 = id.split("__");
+                            String s = split1[1].split("_")[1];
+
+                            strings.add(split1[0] + "__" + s);
+                        }
+                        coordinateMap.put(initTabNameJL, strings);
+                    }
+
                     //获取质检实体表对应数据
                     List<Map<String, Object>> mapsList = jdbcTemplate.queryForList("select * from " + initTabName + " where p_key_id = " + pKeyId);
                     if (mapsList.size() > 0) {

+ 8 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeSynchronousRecordServiceImpl.java

@@ -16,6 +16,7 @@ import org.springblade.manager.mapper.*;
 import org.springblade.manager.service.WbsTreeSynchronousRecordService;
 import org.springblade.manager.vo.WbsTreeSynchronousRecordVo;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 
@@ -190,6 +191,7 @@ public class WbsTreeSynchronousRecordServiceImpl extends ServiceImpl<WbsTreeSync
         //获取当前项目的初始节点
         WbsTreePrivate start = wbsTreePrivateMapper.selectOne(Wrappers.<WbsTreePrivate>lambdaQuery()
                 .eq(WbsTreePrivate::getProjectId, wbsTreePrivate.getProjectId())
+                .eq(WbsTreePrivate::getWbsId, wbsTreePrivate.getWbsId())
                 .eq(WbsTreePrivate::getParentId, 0)
                 .last("limit 1")
         );
@@ -225,12 +227,18 @@ public class WbsTreeSynchronousRecordServiceImpl extends ServiceImpl<WbsTreeSync
         return returnData;
     }
 
+    // 读取配置并设置默认值
+    @Value("${scheduler.enabled:true}")
+    private boolean schedulerEnabled;
     /**
      * 同步节点表单
      * 定时检查同步任务,状态为1的数据如果最后更新时间与当前时间超过10分钟,则修改状态为1
      */
     //@Scheduled(fixedDelay = 10000)
     public void syncInit() {
+        // 本地环境跳过执行(可添加日志输出)
+        if (!schedulerEnabled) return;
+
         List<WbsTreeSynchronousRecord> wbsTreeSynchronousRecords = baseMapper.selectList(new QueryWrapper<WbsTreeSynchronousRecord>().lambda()
                 .in(WbsTreeSynchronousRecord::getStatus, 0, 1)
                 .eq(WbsTreeSynchronousRecord::getIsDeleted, 0)