Browse Source

Merge remote-tracking branch 'origin/master'

liuyc 2 years ago
parent
commit
fb8f5d30a4
33 changed files with 687 additions and 220 deletions
  1. 7 3
      blade-common/src/main/java/org/springblade/common/utils/CommonUtil.java
  2. 3 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/ArchiveFile.java
  3. 8 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/feign/ArchiveFileClient.java
  4. 2 1
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/dto/ElementData.java
  5. 21 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/dto/FormData.java
  6. 4 1
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/ProjectInfo.java
  7. 6 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/feign/ProjectClient.java
  8. 11 2
      blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchiveExaminingReportController.java
  9. 3 1
      blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchiveFileAutoController.java
  10. 60 3
      blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchivesAutoController.java
  11. 3 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/ArchivesAutoMapper.java
  12. 30 5
      blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/ArchivesAutoMapper.xml
  13. 2 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/IArchiveAutoPdfService.java
  14. 12 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/IArchivesAutoService.java
  15. 1 1
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveAutoPdfServiceImpl.java
  16. 111 6
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveExaminingReportImpl.java
  17. 8 4
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveOfflineVersionInfoServiceImpl.java
  18. 66 4
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchivesAutoServiceImpl.java
  19. 10 2
      blade-service/blade-archive/src/main/java/org/springblade/archive/utils/ArchiveTreeUtil.java
  20. 5 0
      blade-service/blade-business/src/main/java/org/springblade/business/feignClient/ArchiveFileClientImpl.java
  21. 3 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/ArchiveFileMapper.java
  22. 28 5
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/ArchiveFileMapper.xml
  23. 28 25
      blade-service/blade-manager/src/main/java/com/mixsmart/utils/CustomFunction.java
  24. 27 22
      blade-service/blade-manager/src/main/java/com/mixsmart/utils/FormulaUtils.java
  25. 7 7
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ArchiveTreeController.java
  26. 7 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/feign/ProjectClientImpl.java
  27. 3 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ArchiveTreeContractMapper.java
  28. 19 7
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ArchiveTreeContractMapper.xml
  29. 1 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IArchiveTreeContractService.java
  30. 3 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IArchiveTreeService.java
  31. 8 9
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ArchiveTreeContractServiceImpl.java
  32. 25 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ArchiveTreeServiceImpl.java
  33. 155 110
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/FormulaServiceImpl.java

+ 7 - 3
blade-common/src/main/java/org/springblade/common/utils/CommonUtil.java

@@ -94,9 +94,13 @@ public class CommonUtil {
     public static InputStream getOSSInputStream(String urlStr) throws Exception {
         //获取OSS文件流
         URL imageUrl = new URL(urlStr);
-        HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
-        conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
-        return conn.getInputStream();
+        try {
+            HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
+            conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
+            return conn.getInputStream();
+        }catch (Exception e){
+            return null;
+        }
     }
 
     /**

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

@@ -270,4 +270,7 @@ public class ArchiveFile extends BaseEntity {
 	 */
 	@ApiModelProperty("是否案卷四要素,0否,1是")
 	private Integer isElement;
+
+	@ApiModelProperty("卷内索引")
+	private Integer fid;
 }

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

@@ -88,4 +88,12 @@ public interface ArchiveFileClient {
      */
     @PostMapping(API_PREFIX + "/getListByNodeID")
     List<ArchiveFile> getListByNodeID(@RequestParam String nodeId);
+
+    /**
+     * 项目下所有工序资料PDF
+     * @param projectId
+     * @return
+     */
+    @PostMapping(API_PREFIX + "/getAllPdfFileUrlByProjectIdAndFileType")
+    List<ArchiveFile> getAllPdfFileUrlByProjectIdAndFileType(@RequestParam Long projectId);
 }

+ 2 - 1
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/dto/ElementData.java

@@ -4,6 +4,7 @@ package org.springblade.manager.dto;
 import org.springblade.core.tool.utils.Func;
 import org.springblade.core.tool.utils.StringPool;
 
+import java.io.Serializable;
 import java.util.Objects;
 
 
@@ -13,7 +14,7 @@ import java.util.Objects;
  * @description TODO
  */
 
-public class ElementData {
+public class ElementData implements Serializable {
     /**
      *  表的自然顺序,同一张表复制N次,index代表该数据在第几张
      */

+ 21 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/dto/FormData.java

@@ -3,6 +3,7 @@ package org.springblade.manager.dto;
 
 
 import lombok.Data;
+import lombok.Setter;
 import org.springblade.core.tool.utils.Func;
 import org.springblade.core.tool.utils.StringPool;
 import org.springblade.manager.entity.Formula;
@@ -25,6 +26,9 @@ public class FormData {
      * 步长;跟别的元素计算时候,用于一对多
      */
     private Integer step=1;
+    /**
+     * 偏移量,🔢批量计算的时候起始点位置*/
+    private Integer offset=0;
     /**
      * 元素名称
      */
@@ -51,6 +55,8 @@ public class FormData {
      * 用于输出
      */
     private List<ElementData> values;
+    /**当需要偏移处理的时候需要备份原数据,等计算完成还原回去*/
+    private List<ElementData> backup;
     private Map<String,ElementData> vMap=new HashMap<>();
 
     /**
@@ -101,6 +107,21 @@ public class FormData {
     }
 
 
+    public void restore(){
+        this.offset=0;
+        this.values=new ArrayList<>(this.getBackup());
+    }
+
+
+
+    public void setOffset(Integer offset) {
+        this.offset = offset;
+        this.backup=new ArrayList<>(values);
+        this.values=values.stream().skip(this.offset).collect(Collectors.toList());
+    }
+
+
+
     public FormData(String code, Integer step, List<ElementData> values, Formula formula,String coords) {
         this.code = code;
         this.step = step;

+ 4 - 1
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/ProjectInfo.java

@@ -150,5 +150,8 @@ public class ProjectInfo extends BaseEntity {
     @ApiModelProperty(value = "电签类型 '1'安签 '2'东方中讯")
     private Integer remarkType;
 
-
+    /**
+     * 是否正在自动组卷中  0否  1是
+     */
+    private Integer isArchivesAuto;
 }

+ 6 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/feign/ProjectClient.java

@@ -30,4 +30,10 @@ public interface ProjectClient {
     @GetMapping(API_PREFIX + "/getById")
     ProjectInfo getById(@RequestParam String key);
 
+    /**
+     * 根据项目ID更新自动归档状态
+     */
+    @GetMapping(API_PREFIX + "/updateIsArchivesAutoById")
+    void updateIsArchivesAutoById(@RequestParam Long id,@RequestParam Integer isArchivesAuto);
+
 }

+ 11 - 2
blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchiveExaminingReportController.java

@@ -14,6 +14,8 @@ import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.secure.BladeUser;
 import org.springblade.core.secure.utils.SecureUtil;
 import org.springblade.core.tool.api.R;
+import org.springblade.evisa.feign.EVisaClient;
+import org.springblade.evisa.vo.CertBeanVO;
 import org.springblade.resource.feign.NewIOSSClient;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -38,10 +40,17 @@ public class ArchiveExaminingReportController {
     private final IArchiveExaminingReportService archiveExaminingReportService;
 
     private final NewIOSSClient iossClient;
+    private final EVisaClient eVisaClient;
     @GetMapping("test")
     public String test() throws DocumentException, IOException {
-        BladeFile bladeFile = iossClient.uploadFile("124456sdf", "D:\\develop\\test\\test1.pdf");
-        return bladeFile.getLink();
+//        BladeFile bladeFile = iossClient.uploadFile("124456sdf", "D:\\develop\\test\\test1.pdf");
+        String pdfUrl =  "https://bladex-chongqing-info.oss-cn-hangzhou.aliyuncs.com//upload/20230414/f95850012b2a780deefe86bff71a36fa.pdf";
+        CertBeanVO vo = eVisaClient.onlineCheckSeal(pdfUrl);
+        if (vo == null){
+            return "签名无效";
+        }else {
+            return vo.getCertBeanVOList().get(0).getDn();
+        }
     }
 
     @GetMapping("/getList")

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

@@ -85,6 +85,8 @@ public class ArchiveFileAutoController extends BladeController {
                                 saveVo.setFileType((long) FileUtils.getFileType(name));
                             }
                             saveVo.setSourceType(2);
+                            saveVo.setProjectId(archive.getProjectId() == null?"":archive.getProjectId().toString());
+                            saveVo.setContractId(archive.getContractId()==null?"":archive.getContractId().toString());
                             list.add(saveVo);
                             if(saveVo.getFilePage() != null && !saveVo.getFilePage().equals("")){
                                 pageN = pageN + saveVo.getFilePage();
@@ -107,7 +109,7 @@ public class ArchiveFileAutoController extends BladeController {
                     archive.setAutoFileSort(l+archive.getAutoFileSort());
                     //待修改
                     archive.setIsDeleted(0);
-                    archive.setIsArchive(0);
+                    archive.setIsArchive(1);
                     archive.setIsAutoFile(1);
                     archivesAutoService.save(archive);
                 }else{

+ 60 - 3
blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchivesAutoController.java

@@ -32,7 +32,9 @@ import org.springblade.core.mp.support.Query;
 import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.utils.Func;
 import org.springblade.manager.entity.ArchiveTreeContract;
+import org.springblade.manager.entity.ProjectInfo;
 import org.springblade.manager.feign.ArchiveTreeContractClient;
+import org.springblade.manager.feign.ProjectClient;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.RequestParam;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -63,7 +65,7 @@ public class ArchivesAutoController extends BladeController {
 
 	private final IArchiveAutoPdfService archiveAutoPdfService;
 	private final ArchiveTreeContractClient archiveTreeContractClient;
-
+	private ProjectClient projectClient;
 	/**
 	 * 详情
 	 */
@@ -275,7 +277,10 @@ public class ArchivesAutoController extends BladeController {
 	@ApiOperation(value = "获取归档树同级节点", notes = "传入节点id")
 	public R test1() {
 
-		archiveAutoPdfService.test1();
+		//archiveAutoPdfService.test1();
+		Long projectId = 1645263362890129410L;
+		List<ArchiveTreeContract> list = archiveTreeContractClient.getListByProjectId(projectId);
+		archivesAutoService.refreshFileNumberNoSlipt(list);
 		return R.data("");
 	}
 
@@ -317,9 +322,25 @@ public class ArchivesAutoController extends BladeController {
 	 */
 	@PostMapping("/archiveAutoMethod")
 	public R archiveAutoMethod(Long projectId) {
+		//先验证当前项目是否在自动组卷中,组卷中直接返回
+		ProjectInfo projectInfo = projectClient.getById(String.valueOf(projectId));
+		Integer isArchivesAuto = projectInfo.getIsArchivesAuto();
+		if(isArchivesAuto!=null && isArchivesAuto==1){
+			return R.fail("当前项目已经在自动组卷中");
+		}
+		//设置自动组卷中
+		projectClient.updateIsArchivesAutoById(projectId,1);
+
+		//将项目未锁定案卷拆卷
 		archivesAutoService.splitArchvies(projectId);
+		//项目自动组卷入口
 		archivesAutoService.archiveAutoMethod(projectId);
-		return R.data("");
+		//刷新项目档号
+		archivesAutoService.refreshFileNumberNoSlipt(projectId);
+
+		//设置自动组卷结束
+		projectClient.updateIsArchivesAutoById(projectId,0);
+		return R.data("自动组卷结束");
 	}
 
 	/**
@@ -334,6 +355,42 @@ public class ArchivesAutoController extends BladeController {
 		return R.data(url);
 	}
 
+	/**
+	 * 拆卷
+	 */
+	@PostMapping("/split")
+	@ApiOperationSupport(order = 15)
+	@ApiOperation(value = "拆卷", notes = "传入ids")
+	public R split(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+		return R.status(archivesAutoService.slipt(ids));
+	}
+
+	/**
+	 * 案卷迁移
+	 */
+	@PostMapping("/move")
+	@ApiOperationSupport(order = 15)
+	@ApiOperation(value = "案卷迁移", notes = "传入ids,nodeId")
+	public R move(@ApiParam(value = "主键集合", required = true) @RequestParam String ids, @RequestParam Long nodeId) {
+
+		List<ArchivesAuto> archivesAutos = archivesAutoService.listByIds(Func.toLongList(ids));
+		for (ArchivesAuto ar  :archivesAutos) {
+			ar.setNodeId(nodeId);
+		}
+
+		return R.status(archivesAutoService.updateBatchById(archivesAutos));
+	}
+
+	/**
+	 * 删除卷内文件
+	 */
+	@PostMapping("/removeFiles")
+	@ApiOperationSupport(order = 15)
+	@ApiOperation(value = "删除案卷的卷内文件", notes = "传入ids")
+	public R removeFiles(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+
+		return R.status(archivesAutoService.removeFiles(ids));
+	}
 
 
 }

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

@@ -86,4 +86,7 @@ public interface ArchivesAutoMapper extends BaseMapper<ArchivesAuto> {
 	List<Map<String,String>> getAllArchiveAgeByContractType(@Param("projectId") Long projectId);
 
 	List<String> getFilingUnitList(@Param("projectId") Long projectId);
+
+
+	Integer splitFiles(@Param("ids") List<Long> ids);
 }

+ 30 - 5
blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/ArchivesAutoMapper.xml

@@ -77,6 +77,17 @@
         <if test="vo.isAutoFile != null and vo.isAutoFile != ''">
             and is_auto_file = #{vo.isAutoFile}
         </if>
+        <choose>
+            <when test="vo.isArchive != null and vo.isArchive != ''">
+                and  is_auto_file = #{vo.isArchive}
+            </when>
+            <otherwise>
+                and (is_auto_file is null or is_auto_file != 1)
+            </otherwise>
+        </choose>
+        <if test="vo.isAutoFile != null and vo.isAutoFile != ''">
+            and is_auto_file = #{vo.isAutoFile}
+        </if>
         <if test="vo.nodeIds != null and vo.nodeIds != ''">
             and node_id in
             <foreach collection="vo.nodeIdArray" item="nodeId" open="(" separator="," close=")">
@@ -93,9 +104,14 @@
         <if test="vo.contractId != null and vo.contractId != ''">
             and contract_id = #{vo.contractId}
         </if>
-        <if test="vo.isArchive != null and vo.isArchive != ''">
-            and is_archive = #{vo.isArchive}
-        </if>
+        <choose>
+            <when test="vo.isArchive != null and vo.isArchive != ''">
+                and  is_auto_file = #{vo.isArchive}
+            </when>
+            <otherwise>
+                and (is_auto_file is null or is_auto_file != 1)
+            </otherwise>
+        </choose>
         <if test="vo.isAutoFile != null and vo.isAutoFile != ''">
             and is_auto_file = #{vo.isAutoFile}
         </if>
@@ -239,14 +255,14 @@
         WHERE uaa.project_id =#{projectId} and uaa.is_deleted = #{type}
     </select>
     <select id="getAllArchiveAgeByContractType" resultType="java.util.Map">
-        SELECT CASE uaa.storage_time WHEN '10' THEN '10年' WHEN '30' THEN '30年' ELSE '永久' END as name,COUNT(uaa.storage_time) as value
+        SELECT CASE uaa.storage_time WHEN '1' THEN '10年' WHEN '2' THEN '30年' ELSE '永久' END as name,COUNT(uaa.storage_time) as value
         FROM m_archive_tree_contract matc left join u_archives_auto uaa on uaa.node_id =matc.id
         WHERE matc.project_id =#{projectId} and uaa.is_deleted =0
         GROUP BY uaa.storage_time
     </select>
 <!--    档案鉴定,档案查询-->
     <select id="pageByAuthenticate" resultType="org.springblade.archive.vo.ArchivesAutoVO">
-        select uaa.*
+        select uaa.id,uaa.file_number,uaa.name,uaa.file_size,CASE uaa.storage_time WHEN '1' THEN '10年' WHEN '2' THEN '30年' ELSE '永久' END as storageTimeValue
         from(
                 select id from m_archive_tree_contract
                 where project_id = #{vo.projectId} and ancestors like concat('%', #{vo.nodeId}, '%') or id = #{vo.nodeId}
@@ -267,4 +283,13 @@
     </select>
 
 
+    <update id="splitFiles" >
+        update u_archive_file set is_archive = 0 ,archive_id = null where
+        id in
+        <foreach collection="ids" item="id" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </update>
+
+
 </mapper>

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

@@ -2,6 +2,7 @@ package org.springblade.archive.service;
 
 import org.springblade.archive.entity.ArchivesAuto;
 import org.springblade.business.entity.ArchiveFile;
+import org.springblade.manager.entity.ArchiveTreeContract;
 
 import java.util.List;
 import java.util.Map;
@@ -28,4 +29,5 @@ public interface IArchiveAutoPdfService {
 
     //合并pdf
     String MergePdfAndUpload(List<String> urlList,String fileName,String filePath,Long projectId) ;
+
 }

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

@@ -20,6 +20,7 @@ import org.springblade.archive.entity.ArchivesAuto;
 import org.springblade.archive.vo.ArchivesAutoVO;
 import org.springblade.core.mp.base.BaseService;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springblade.manager.entity.ArchiveTreeContract;
 
 import java.util.List;
 import java.util.Map;
@@ -62,4 +63,15 @@ public interface IArchivesAutoService extends BaseService<ArchivesAuto> {
 	void splitArchvies(Long project);
 
 	public String getMergeArchivesFile(Long archiveId);
+
+	//拆卷
+	boolean slipt(String ids);
+
+	//从案卷里删除文件
+	boolean removeFiles(String ids);
+
+
+	void refreshFileNumberNoSlipt(List<ArchiveTreeContract> archiveTreeContracts);
+
+	void refreshFileNumberNoSlipt(Long projectId);
 }

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

@@ -597,7 +597,7 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
         for (ArchiveFile file:  datas) {
             idx++;
             //设置序号
-            file.setId(idx.longValue());
+            file.setFid(idx);
             //设置文件编号
             if (StringUtil.isEmpty(file.getFileNumber())) {
                 file.setFileNumber("\\");

+ 111 - 6
blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveExaminingReportImpl.java

@@ -16,8 +16,11 @@ import org.springblade.archive.mapper.ArchiveExaminingReportMapper;
 import org.springblade.archive.service.IArchiveExaminingReportDetailService;
 import org.springblade.archive.service.IArchiveExaminingReportService;
 import org.springblade.archive.socket.WebSocketServer;
+import org.springblade.archive.utils.FileUtils;
 import org.springblade.archive.vo.ArchiveExaminingSocketVo;
 import org.springblade.archive.vo.ArchiveExaminingVo;
+import org.springblade.business.entity.ArchiveFile;
+import org.springblade.business.feign.ArchiveFileClient;
 import org.springblade.common.constant.ArchiveConstant;
 import org.springblade.core.mp.base.BaseServiceImpl;
 import org.springblade.core.oss.model.BladeFile;
@@ -25,15 +28,17 @@ import org.springblade.core.secure.BladeUser;
 import org.springblade.core.secure.utils.AuthUtil;
 import org.springblade.core.secure.utils.SecureUtil;
 import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.evisa.feign.EVisaClient;
+import org.springblade.evisa.vo.CertBeanVO;
 import org.springblade.resource.feign.NewIOSSClient;
 import org.springblade.resource.feign.NewISmsClient;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Date;
+import java.util.*;
 import java.util.List;
 
 /**
@@ -49,6 +54,10 @@ public class ArchiveExaminingReportImpl extends BaseServiceImpl<ArchiveExamining
     private final IArchiveExaminingReportDetailService detailService;
 
     private final NewIOSSClient iossClient;
+
+    private final ArchiveFileClient archiveFileClient;
+
+    private final EVisaClient eVisaClient;
     /**
      * 推送状态到前端
      * @param id
@@ -87,12 +96,29 @@ public class ArchiveExaminingReportImpl extends BaseServiceImpl<ArchiveExamining
         report.setId(id);
         report.setStatus(2);
         this.updateById(report);
+        //获取项目中所有档案文件的工序资料pdfUrl
+        List<ArchiveFile> files = archiveFileClient.getAllPdfFileUrlByProjectIdAndFileType(vo.getProjectId());
+        //不合格对象
+        List<Map<String,String>> mapList = new ArrayList<>();
+        int unqualifiedCount = 0;
         //检测中
             //真实性
         if (StringUtils.isNotBlank(vo.getAuthenticity()) && "1".equals(vo.getAuthenticity())) {
-            Thread.sleep(5000L);
+            //检测项目下所有工序资料PDF签章有效性
+            for (ArchiveFile file : files) {
+                if (StringUtils.isNotBlank(file.getPdfFileUrl())) {
+                    CertBeanVO cb = eVisaClient.onlineCheckSeal(file.getPdfFileUrl());
+                    if (cb == null) {
+                        Map<String, String> map = new HashMap<>();
+                        map.put("examiningItem", ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对固化信息有效性检测");
+                        map.put("unqualifiedObject", file.getFileName());
+                        mapList.add(map);
+                        unqualifiedCount++;
+                    }
+                }
+            }
             detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_AUTHENTICITY,
-                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对固化信息有效性检测", 0, "无", 0));
+                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对固化信息有效性检测", unqualifiedCount, unqualifiedCount == 0 ?"无":"详见附件", unqualifiedCount == 0?0:1));
             detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_AUTHENTICITY,
                     ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对元数据项数据长度检测", 0, "无", 0));
             detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_AUTHENTICITY,
@@ -170,7 +196,6 @@ public class ArchiveExaminingReportImpl extends BaseServiceImpl<ArchiveExamining
         }
             //安全性
         if (StringUtils.isNotBlank(vo.getSecurity()) && "1".equals(vo.getSecurity())) {
-            Thread.sleep(5000L);
             detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_SECURITY,
                     ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对系统环境中是否安装杀毒软件检测", 0, "无", 0));
             detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_SECURITY,
@@ -178,13 +203,28 @@ public class ArchiveExaminingReportImpl extends BaseServiceImpl<ArchiveExamining
             report.setReportDetailStatus(4);
             this.updateById(report);
         }
+        Thread.sleep(3000L);
         //生成报告,生成PDF
         report.setStatus(3);
         this.updateById(report);
         String url = this.generateReportPdf(id);
+        //生成附件PDF
+        if (mapList.size() > 0){
+            String detailPdf = this.generateReportDetailPdf(mapList);
+            List<String> PdfUrls = new ArrayList<>();
+            PdfUrls.add(url);
+            PdfUrls.add(detailPdf);
+            String localUrl = "/www/wwwroot/Users/hongchuangyanfa/Desktop/archiveExaminingPdf/123.pdf";
+//            String localUrl = "D:\\develop\\test\\123.pdf";
+            //合并pdf
+            FileUtils.mergePdfPublicMethods(PdfUrls,localUrl);
+            BladeFile bladeFile = iossClient.uploadFile("123.pdf",localUrl);
+            report.setReportPdfUrl(bladeFile.getLink());
+        }else {
+            report.setReportPdfUrl(url);
+        }
         Thread.sleep(5000L);
         //完成
-        report.setReportPdfUrl(url);
         report.setStatus(4);
         this.updateById(report);
     }
@@ -278,7 +318,72 @@ public class ArchiveExaminingReportImpl extends BaseServiceImpl<ArchiveExamining
             dataTable.addCell(pdfTableStyle(detail.getUnqualifiedCount()+"", size10font, high, true, true));
             dataTable.addCell(pdfTableStyle(detail.getUnqualifiedObject(), size10font, high, true, true));
             document.add(dataTable);
+        }
+        document.close();
+        writer.close();
+        BladeFile bladeFile = iossClient.uploadFile(uuid+".pdf", localUrl+uuid+".pdf");
+        if (bladeFile != null && StringUtils.isNotBlank(bladeFile.getLink())){
+            return bladeFile.getLink();
+        }else {
+            return null;
+        }
+    }
 
+    /**
+     * 生成检测报告PDF
+     */
+    private String generateReportDetailPdf(List<Map<String,String>> mapList) throws IOException, DocumentException {
+        int high = 20;
+        int widthPercentage = 100;
+        String uuid = StringUtil.randomUUID();
+        String localUrl = "/www/wwwroot/Users/hongchuangyanfa/Desktop/archiveExaminingPdf/";
+//        String localUrl = "D:\\develop\\test\\";
+        //新建一个pdf文档对象,前一个参数是纸张大小,后四个为边距
+        Document document = new Document(PageSize.A4, 5, 5, 30, 30);
+        //建立一个书写器
+        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(localUrl+uuid+".pdf"));
+        document.open();
+        //创建字体
+        BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
+        //字体对象,这里可以创建一个方法
+        Font size10font = new Font(baseFont, 10, Font.NORMAL); //大小为10的正常字体
+        Font size10font2 = new Font(baseFont, 10, Font.BOLD);  //大小为14的正常字体
+        //添加标题
+        //创建第一行表格
+        PdfPTable tableName = new PdfPTable(1);
+        tableName.setWidthPercentage(widthPercentage);  //设置标题长度占纸张比例
+        //给表格赋值
+        tableName.addCell(pdfTableStyle("检测报告附件表", size10font, high, true, true));
+        //将表格添加到文档对象中
+        document.add(tableName);
+        //表头文字
+        String[] name = new String[]{ "检测项目", "不合格对象"};
+        //创建第二行,并设置第二行中的表格数
+        PdfPTable twoTable = new PdfPTable(name.length);
+        twoTable.setWidthPercentage(widthPercentage);
+        //该数组是每个表格的宽度
+        float[] floats = new float[name.length];
+        floats[0] = 0.6f;
+        floats[1] = 0.5f;
+        //循环将表头数据添加到第二行表格中
+        for (int i = 0; i < name.length; i++) {
+            PdfPCell pdfPCell = pdfTableStyle(name[i], size10font2, high, true, true);
+            pdfPCell.setBackgroundColor(new BaseColor(231,230,230));
+            twoTable.addCell(pdfPCell);
+        }
+        //设置表格的宽度
+        twoTable.setTotalWidth(floats);
+        document.add(twoTable);
+        //将数据放入表格中
+        for (int i = 0; i < mapList.size(); i++) {
+            Map<String, String> map = mapList.get(i);
+            PdfPTable dataTable = new PdfPTable(name.length);
+            dataTable.setWidthPercentage(widthPercentage);
+            dataTable.setTotalWidth(floats);
+            dataTable.addCell(pdfTableStyle(map.get("examiningItem"), size10font, high, false, true));
+            dataTable.addCell(pdfTableStyle(map.get("unqualifiedObject"), size10font, high, true, true));
+            //如果出现不相同,则合并之前的
+            document.add(dataTable);
         }
         document.close();
         writer.close();

+ 8 - 4
blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveOfflineVersionInfoServiceImpl.java

@@ -88,15 +88,19 @@ public class ArchiveOfflineVersionInfoServiceImpl extends BaseServiceImpl<Archiv
                     String fileUrl = file.getFileUrl();
                     String fileName = fileUrl.substring(fileUrl.lastIndexOf('/') + 1);
                     InputStream file_out = CommonUtil.getOSSInputStream(fileUrl);
-                    CommonUtil.inputStreamToFile(file_out, new File(localUrl + fileName));
-                    file.setFileUrl(fileName);
+                    if (file_out != null) {
+                        CommonUtil.inputStreamToFile(file_out, new File(localUrl + fileName));
+                        file.setFileUrl(fileName);
+                    }
                 }
                 if (StringUtil.isNotBlank(file.getPdfFileUrl())) {
                     String pdfFileUrl = file.getPdfFileUrl();
                     String fileName = pdfFileUrl.substring(pdfFileUrl.lastIndexOf('/') + 1);
                     InputStream file_out = CommonUtil.getOSSInputStream(pdfFileUrl);
-                    CommonUtil.inputStreamToFile(file_out, new File(localUrl + fileName));
-                    file.setPdfFileUrl(fileName);
+                    if (file_out != null) {
+                        CommonUtil.inputStreamToFile(file_out, new File(localUrl + fileName));
+                        file.setPdfFileUrl(fileName);
+                    }
                 }
             }
             try {

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

@@ -20,6 +20,7 @@ import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 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.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.AllArgsConstructor;
@@ -115,7 +116,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		if (archivesAutos != null && archivesAutos.size() >0) {
 			archivesAutos.stream().forEach(aa -> {
 				if (StringUtils.isNotBlank(aa.getStorageTime())) {
-					aa.setStorageTimeValue("9999".equals(aa.getStorageTime()) ? "永久" : ("30".equals(aa.getStorageTime()) ? "30年" : "10年"));
+					aa.setStorageTimeValue("3".equals(aa.getStorageTime()) ? "永久" : ("2".equals(aa.getStorageTime()) ? "30年" : "10年"));
 				}
 				if (StringUtils.isNotBlank(aa.getSecretLevel())) {
 					aa.setSecretLevelValue("1".equals(aa.getSecretLevel()) ? "机密" : ("2".equals(aa.getSecretLevel()) ? "绝密" : "秘密"));
@@ -962,6 +963,16 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		return this.list(queryWrapper);
 	}
 
+
+	/**
+	 * 刷新项目档号
+	 * @param projectId
+	 */
+	public void refreshFileNumberNoSlipt(Long projectId) {
+		List<ArchiveTreeContract> list = archiveTreeContractClient.getListByProjectId(projectId);
+		this.refreshFileNumberNoSlipt(list);
+	}
+
 	/**
 	 * 不重组的情况下刷新档号
 	 * @param archiveTreeContracts
@@ -984,7 +995,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 			index =1;
 			List<ArchivesAuto> archivesAutos = findArchivesAutosByIds(ids);
 			if (archivesAutos == null || archivesAutos.size() == 0) {
-				return;
+				continue;
 			}
 			String fileNumberPrefix=subList.get(0).getFileNumberPrefix();
 			String archiveNameSuffix=subList.get(0).getArchiveNameSuffix();
@@ -1055,11 +1066,62 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 				urlList.add(frontUrls[2]);
 				urlList.add(frontUrls[3]);
 			}
-
-			url = archiveAutoPdfService.MergePdfAndUpload(urlList,archivesAuto.getName(),null,archivesAuto.getProjectId());
+			String fileName = SnowFlakeUtil.getId().toString();
+			url = archiveAutoPdfService.MergePdfAndUpload(urlList,fileName,null,archivesAuto.getProjectId());
 		}
 		return  url;
 	}
 
+	/**
+	 * 拆卷
+	 * @param ids
+	 * @return
+	 */
+	public  boolean slipt(String ids) {
+
+		List orgIds = Func.toLongList(ids);
+
+		List<String> strIds = new ArrayList<>();
+		List<Long> lIds = new ArrayList<>();
+
+		//排除锁定的和单文件案卷这种
+		List<ArchivesAuto> archivesAutos = this.listByIds(orgIds);
+		for (ArchivesAuto ar: archivesAutos) {
+			if (ar.getIsLock()!= null && ar.getIsLock() == 1) {
+				continue;
+			}
+			if (ar.getIsAutoFile()!= null &&  ar.getIsAutoFile() == 1) {
+				continue;
+			}
+			lIds.add(ar.getId());
+			strIds.add(ar.getId().toString());
+		}
+
+		//更新
+		List<ArchiveFile> files = archiveFileClient.getAllArchiveFileByArchiveIds(strIds);
+		if (files != null && files.size() > 0) {
+
+			List<Long> fids = files.stream()
+					.map(ArchiveFile::getId)
+					.collect(Collectors.toList());
+			baseMapper.splitFiles(fids);
+		}
+
+		//删除案卷
+		return this.deleteLogic(lIds);
+	}
+
+	/**
+	 * 从案卷删除文件
+	 * @param ids
+	 * @return
+	 */
+	public  boolean removeFiles(String ids) {
+		List<Long> fids = Func.toLongList(ids);
+		baseMapper.splitFiles(fids);
+		return true;
+	}
+
+
 
 }

+ 10 - 2
blade-service/blade-archive/src/main/java/org/springblade/archive/utils/ArchiveTreeUtil.java

@@ -45,9 +45,17 @@ public class ArchiveTreeUtil {
                 subTreeList.add(subTree);
 
             }else {
-                for (ArchiveTreeContractVO2 contractNode : subTree.getChildren()){
-                    subTreeList.add(contractNode);
+                if (subTree.getChildren() == null || subTree.getChildren().size() == 0) {
+                    continue;
                 }
+                if (subTree.getChildren().get(0).getExtType() == 2) {
+                    for (ArchiveTreeContractVO2 contractNode : subTree.getChildren()){
+                        subTreeList.add(contractNode);
+                    }
+                }else {
+                    subTreeList.add(subTree);
+                }
+
             }
         }
 

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

@@ -208,5 +208,10 @@ public class ArchiveFileClientImpl implements ArchiveFileClient {
         return files;
     }
 
+    @Override
+    public List<ArchiveFile> getAllPdfFileUrlByProjectIdAndFileType(Long projectId) {
+        return fileMapper.getAllPdfFileUrlByProjectIdAndFileType(projectId);
+    }
+
 
 }

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

@@ -76,4 +76,7 @@ public interface ArchiveFileMapper extends BaseMapper<ArchiveFile> {
     List<ArchiveFile> getAllArchiveFileByArchiveIds(@Param("ids") List<String> ids);
 
 	public List<ArchiveFile> getListByNodeID(@Param("nodeId") String nodeId);
+
+	//后续应该加入文件类型
+    List<ArchiveFile> getAllPdfFileUrlByProjectIdAndFileType(@Param("projectId")Long projectId);
 }

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

@@ -56,6 +56,7 @@
         <result column="source_type" property="sourceType"/>
         <result column="is_element" property="isElement"/>
         <result column="pdf_page_url" property="pdfPageUrl"/>
+        <result column="fid" property="fid"/>
     </resultMap>
     <update id="recoveryByIds">
         update u_archive_file set is_deleted = 0 where
@@ -66,7 +67,7 @@
     </update>
 
     <select id="selectArchiveFileCount" resultType="java.lang.Integer">
-        select count(id) from u_archive_file where is_deleted = 0  and (is_auto_file is null or is_auto_file != 1)
+        select count(id) from u_archive_file where is_deleted = 0
         <if test="vo.isApprovalValue != null and vo.isApprovalValue != ''">
             and status = #{vo.isApprovalValue}
         </if>
@@ -79,7 +80,17 @@
         <if test="vo.contractId != null and vo.contractId != ''">
             and contract_id = #{vo.contractId}
         </if>
-
+        <if test="vo.archiveId != null and vo.archiveId != ''">
+            and archive_id = #{vo.archiveId}
+        </if>
+        <choose>
+            <when test="vo.isArchive != null and vo.isArchive != ''">
+                and  is_auto_file = #{vo.isArchive}
+            </when>
+            <otherwise>
+                and (is_auto_file is null or is_auto_file != 1)
+            </otherwise>
+        </choose>
         <if test="vo.nodeIds != null and vo.nodeIds != ''">
             and node_id in
             <foreach collection="vo.nodeIdArray" item="nodeId" open="(" separator="," close=")">
@@ -99,7 +110,7 @@
     </select>
 
     <select id="selectArchiveFilePage" resultMap="archiveFileResultMap">
-        select * from u_archive_file where is_deleted = 0 and (is_auto_file is null or is_auto_file != 1)
+        select * from u_archive_file where is_deleted = 0
         <if test="vo.isApprovalValue != null and vo.isApprovalValue != ''">
             and status = #{vo.isApprovalValue}
         </if>
@@ -112,9 +123,17 @@
         <if test="vo.contractId != null and vo.contractId != ''">
             and contract_id = #{vo.contractId}
         </if>
-        <if test="vo.archive_id != null and vo.archive_id != ''">
-            and archive_id = #{vo.archive_id}
+        <if test="vo.archiveId != null and vo.archiveId != ''">
+            and archive_id = #{vo.archiveId}
         </if>
+        <choose>
+            <when test="vo.isArchive != null and vo.isArchive != ''">
+                and  is_auto_file = #{vo.isArchive}
+            </when>
+            <otherwise>
+                and (is_auto_file is null or is_auto_file != 1)
+            </otherwise>
+        </choose>
         <if test="vo.nodeIds != null and vo.nodeIds != ''">
             and node_id in
             <foreach collection="vo.nodeIdArray" item="nodeId" open="(" separator="," close=")">
@@ -309,5 +328,9 @@
           is_deleted = 0
           order by sort
     </select>
+    <select id="getAllPdfFileUrlByProjectIdAndFileType" resultType="org.springblade.business.entity.ArchiveFile">
+        SELECT file_name,pdf_file_url
+        FROM u_archive_file WHERE project_id = #{projectId}
+    </select>
 
 </mapper>

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

@@ -5,6 +5,7 @@ import cn.hutool.core.date.*;
 import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.NumberUtil;
 import com.alibaba.fastjson.JSON;
+import com.jfireel.expression.Expression;
 import com.jfireel.expression.node.CalculateNode;
 import com.jfireel.expression.node.impl.OperatorResultNode;
 import com.jfireel.expression.node.impl.StaticObjectMethodNode;
@@ -15,6 +16,7 @@ import org.jsoup.Jsoup;
 import org.springblade.core.tool.utils.*;
 import org.springblade.manager.formula.ElementBlock;
 import org.springblade.manager.formula.ItemBlock;
+import org.springblade.manager.formula.KeyMapper;
 
 import java.io.FileInputStream;
 import java.math.BigDecimal;
@@ -25,6 +27,8 @@ import java.util.concurrent.atomic.AtomicInteger;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
 import static java.math.BigDecimal.ROUND_CEILING;
 import static java.math.BigDecimal.ROUND_HALF_UP;
 
@@ -289,6 +293,29 @@ public class CustomFunction {
 		return "";
 	}
 
+	/**
+	 * @Description 分段求平均值
+	 * @Param [data 原数据, n 分段数]
+	 * @return java.util.List<java.lang.Object>
+	 * @Author yangyj
+	 * @Date 2023.04.28 10:13
+	 **/
+	public static List<Object> avg4segment(List<Object> data, int n) {
+		if (data.isEmpty()) {
+			return null;
+		}
+		if (n <= 1) {
+			return Collections.singletonList(avg(data));
+		}
+		Map<Integer, List<Object>> group = IntStream.range(0, data.size())
+				.boxed()
+				.collect(Collectors.groupingBy(i -> i / n, LinkedHashMap::new, Collectors.mapping(data::get, Collectors.toList())));
+		return group.values().stream().map(CustomFunction::avg).collect(Collectors.toList());
+	}
+
+
+
+
 	public static Object max(List<Object> list) {
 		if(ListUtils.isNotEmpty(list)){
 			OptionalDouble op =list.stream().filter(StringUtils::isNumber).map(StringUtils::handleNull).mapToDouble(Double::parseDouble).max();
@@ -2576,31 +2603,7 @@ public class CustomFunction {
 		return "";
 	}
 
-//	public static void main(String[] args) {
-//		ElementBlock eb =new ElementBlock();
-//		eb.setCode("m_xxxx_:key_x");
-//		eb.setPass(5);
-//		eb.setTotal(5);
-//		eb.setSort(16);
-//		List<ItemBlock> list = new ArrayList<>();
-//		eb.setList(list);
-//		ItemBlock ib = new ItemBlock();
-//		ib.setDev("±5");
-//		ib.setPkeyId(123456789L);
-//		ib.setS("12/25/36");
-//		ib.setD("12,12/25,23/36,35");
-//		list.add(ib);
-//		ItemBlock ib2 = new ItemBlock();
-//		ib2.setDev("±5");
-//		ib2.setPkeyId(123456789L);
-//		ib2.setS("12");
-//		ib2.setD("12,12");
-//		list.add(ib2);
-//		String json=JSON.toJSONString(eb);
-//		System.out.println(json);
-//		ElementBlock ebj= JSON.parseObject(json,ElementBlock.class);
-//		System.out.println();
-//	}
+
 
 
 }

+ 27 - 22
blade-service/blade-manager/src/main/java/com/mixsmart/utils/FormulaUtils.java

@@ -12,9 +12,7 @@ import org.springblade.manager.dto.ElementData;
 import org.springblade.manager.dto.FormData;
 import org.springblade.manager.entity.Formula;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
+import java.io.*;
 import java.math.BigDecimal;
 import java.nio.charset.StandardCharsets;
 import java.util.*;
@@ -351,33 +349,40 @@ public class FormulaUtils {
 
 
     private static boolean isContainKeywords(String s) {
-        List<String> keywords = Arrays.asList("或", "每", "个");
+        List<String> keywords = Arrays.asList("或", "每", "个","附录","抽查","测","量");
         return keywords.stream().anyMatch(s::contains);
     }
 
-    public static byte[] compress(String data) throws IOException {
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        DeflaterOutputStream dos = new DeflaterOutputStream(bos, new Deflater(Deflater.BEST_COMPRESSION));
-        dos.write(data.getBytes(StandardCharsets.UTF_8));
-        dos.close();
-        return bos.toByteArray();
-    }
 
-    public static String decompress(byte[] data) throws IOException {
-        ByteArrayInputStream bis = new ByteArrayInputStream(data);
-        InflaterInputStream iis = new InflaterInputStream(bis, new Inflater());
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        byte[] buffer = new byte[1024];
-        int len;
-        while ((len = iis.read(buffer)) > 0) {
-            bos.write(buffer, 0, len);
+
+    /**
+     * @Description 深度拷贝
+     * @Param [originalList]
+     * @return java.util.List<T>
+     * @Author yangyj
+     * @Date 2023.04.28 14:18
+     **/
+    public static <T extends Serializable> List<T> copyList(List<T> originalList) {
+        try {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            ObjectOutputStream oos = new ObjectOutputStream(baos);
+            oos.writeObject(originalList);
+            oos.close();
+            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+            ObjectInputStream ois = new ObjectInputStream(bais);
+            @SuppressWarnings("unchecked")
+            List<T> copiedList = (List<T>) ois.readObject();
+            ois.close();
+            return copiedList;
+        } catch (Exception e) {
+            e.printStackTrace();
         }
-        iis.close();
-        bos.close();
-        return new String(bos.toByteArray(), StandardCharsets.UTF_8);
+        return null;
     }
 
 
+
+
 //    public static void main(String[] args) {
 //        List<String> list =Arrays.asList(
 //                ""

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

@@ -106,16 +106,16 @@ public class ArchiveTreeController extends BladeController {
     @ApiOperationSupport(order = 5)
     @ApiOperation(value = "逻辑删除", notes = "传入id")
     public R remove(@ApiParam(value = "id", required = true) @RequestParam String id) {
-        List<ArchiveTree> archiveTrees = archiveTreeService.selectByParentIdOrId(id);
-        archiveTrees.forEach(archiveTree -> {
-            if (archiveTree.getParentId() == Long.parseLong(id)) {
-                throw new ServiceException("当前节点下存在子节点,删除失败");
-            }
+//        List<ArchiveTree> archiveTrees = archiveTreeService.selectByParentIdOrId(id);
+//        archiveTrees.forEach(archiveTree -> {
+//            if (archiveTree.getParentId() == Long.parseLong(id)) {
+//                throw new ServiceException("当前节点下存在子节点,删除失败");
+//            }
 //            if (archiveTree.getIsUploadFileDisplayConfigurationTree() == 1) {
 //                throw new ServiceException("当前节点被引用中,删除失败");
 //            }
-        });
-        return R.status(archiveTreeService.deleteLogic(Func.toLongList(id)));
+//        });
+        return R.status(archiveTreeService.deleteTree(Long.parseLong(id)));
     }
 
     /**

+ 7 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/feign/ProjectClientImpl.java

@@ -26,4 +26,11 @@ public class ProjectClientImpl implements ProjectClient {
     public ProjectInfo getById(String key) {
         return projectInfoService.getById(key);
     }
+
+    @Override
+    public void updateIsArchivesAutoById(Long id,Integer isArchivesAuto) {
+        ProjectInfo projectInfo = projectInfoService.getById(id);
+        projectInfo.setIsArchivesAuto(isArchivesAuto);
+        projectInfoService.updateById(projectInfo);
+    }
 }

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

@@ -79,7 +79,9 @@ public interface ArchiveTreeContractMapper extends BaseMapper<ArchiveTreeContrac
 	@MapKey("id")
 	List<Map<String, Object>> getArchiveTreeAndArchiveCount(@Param("projectId") Long projectId,@Param("nodeId") Long nodeId);
 
-    List<ArchiveTreeContract> getArchiveTreeByNodeType(@Param("projectId")Long projectId,@Param("nodeType") Long nodeType);
+    List<ArchiveTreeContractVO3> getArchiveTreeByNodeType(@Param("projectId")Long projectId,@Param("nodeType") String nodeType);
+
+    List<ArchiveTreeContractVO3> getArchiveTreeByNodeType2(@Param("projectId")Long projectId);
 
 	List<ArchiveTreeContractVO3> getChildrenNodeByNodeId(@Param("nodeId") Long nodeId);
 }

+ 19 - 7
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ArchiveTreeContractMapper.xml

@@ -331,9 +331,9 @@
         order by tree_sort asc
     </select>
     <select id="getListByProjectId" resultType="org.springblade.manager.entity.ArchiveTreeContract">
-        select id,project_id as projectId,parent_id as parentId,ancestors,node_name as nodeName,status,is_deleted as isDeleted,create_time as createTime
+        select id,project_id as projectId,parent_id as parentId,ancestors,node_name as nodeName,status,tree_code as treeCode, ext_type as extType, is_deleted as isDeleted,create_time as createTime
         from m_archive_tree_contract
-        where project_id=#{projectId};
+        where project_id=#{projectId} and is_deleted = 0 order by tree_sort asc;
     </select>
 
 
@@ -368,14 +368,26 @@
             if((SELECT COUNT(*) from m_archive_tree_contract matc WHERE parent_id = matc1.id)=0,false,true) as hasChildren
         FROM m_archive_tree_contract matc1 WHERE matc1.project_id =#{projectId} and matc1.parent_id = #{nodeId}
     </select>
-    <select id="getArchiveTreeByNodeType" resultType="org.springblade.manager.entity.ArchiveTreeContract">
-        SELECT * FROM m_archive_tree_contract
-        WHERE  parent_id = (select id from m_archive_tree_contract
+    <select id="getArchiveTreeByNodeType" resultType="org.springblade.manager.vo.ArchiveTreeContractVO3">
+        SELECT matc1.*,if((SELECT COUNT(*) from m_archive_tree_contract matc WHERE matc.parent_id = matc1.id)=0,true,false)
+            as notExsitChild
+        FROM m_archive_tree_contract matc1
+        WHERE  matc1.parent_id = (select id from m_archive_tree_contract
                             WHERE parent_id = (select id from m_archive_tree_contract WHERE parent_id = 0 and project_id = #{projectId})
-                            and post_type = #{nodeType})
-          and is_deleted = 0
+                            and tree_code = #{nodeType})
+          and matc1.is_deleted = 0
+    </select>
 
+    <select id="getArchiveTreeByNodeType2" resultType="org.springblade.manager.vo.ArchiveTreeContractVO3">
+        SELECT matc1.*,if((SELECT COUNT(*) from m_archive_tree_contract matc WHERE matc.parent_id = matc1.id)=0,true,false)
+            as notExsitChild
+        FROM m_archive_tree_contract matc1
+        WHERE  matc1.parent_id in (select id from m_archive_tree_contract
+                            WHERE parent_id = (select id from m_archive_tree_contract WHERE parent_id = 0 and project_id = #{projectId})
+                              and tree_code is NULL)
+          and matc1.is_deleted = 0
     </select>
+
     <select id="getChildrenNodeByNodeId" resultType="org.springblade.manager.vo.ArchiveTreeContractVO3">
         select matc1.*,if((SELECT COUNT(*) from m_archive_tree_contract matc WHERE matc.parent_id = matc1.id)=0,true,false)
             as notExsitChild

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

@@ -96,7 +96,7 @@ public interface IArchiveTreeContractService extends BaseService<ArchiveTreeCont
 
 	List<Map<String,Object>> getArchiveTreeAndArchiveCount(Long projectId,Long nodeId);
 
-    List<ArchiveTreeContract> getArchiveTreeByNodeType(Long projectId, Long nodeType);
+    List<ArchiveTreeContractVO3> getArchiveTreeByNodeType(Long projectId, Long nodeType);
 
 	List<ArchiveTreeContractVO3> getChildrenNodeByNodeId(Long nodeId);
 }

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

@@ -64,4 +64,7 @@ public interface IArchiveTreeService extends BaseService<ArchiveTree> {
 	 * @return
 	 */
 	Map<String,String> removeArchiveAutoRule(Long nodeId,boolean iswbsNode,Long projectId);
+
+	//删除子树
+	boolean deleteTree(Long id);
 }

+ 8 - 9
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ArchiveTreeContractServiceImpl.java

@@ -135,9 +135,9 @@ public class ArchiveTreeContractServiceImpl extends BaseServiceImpl<ArchiveTreeC
 
 		ArchiveTreeContractVO2 newTree = arTreeContractInitService.getTree(archiveTreeContracts);
 
-
-		List<ArchiveTreeContract> addNodes = arTreeContractInitService.getContractProcExtNodes(tenantId,projectId,wbsId,newTree);
-		archiveTreeContracts.addAll(addNodes);
+        //todo 等测试OK再打开,wbs contract树有很多数据错乱节点。
+//		List<ArchiveTreeContract> addNodes = arTreeContractInitService.getContractProcExtNodes(tenantId,projectId,wbsId,newTree);
+//		archiveTreeContracts.addAll(addNodes);
 
 		//初始化祖先节点和排序
 		arTreeContractInitService.InitTreeSort(archiveTreeContracts,tree);
@@ -855,17 +855,16 @@ public class ArchiveTreeContractServiceImpl extends BaseServiceImpl<ArchiveTreeC
 	}
 
 	@Override
-	public List<ArchiveTreeContract> getArchiveTreeByNodeType(Long projectId, Long nodeType) {
+	public List<ArchiveTreeContractVO3> getArchiveTreeByNodeType(Long projectId, Long nodeType) {
 		if (nodeType == 1){
-			nodeType = 1537246243393589249L;
+			return baseMapper.getArchiveTreeByNodeType2(projectId);
 		}else if (nodeType == 2){
-			nodeType = 1537247986361782274L;
+			return baseMapper.getArchiveTreeByNodeType(projectId,"C");
 		}else if (nodeType == 3){
-			nodeType = 1537246384519335938L;
+			return baseMapper.getArchiveTreeByNodeType(projectId,"S");
 		}else {
-			nodeType = 1607574141119365122L;
+			return null;
 		}
-		return baseMapper.getArchiveTreeByNodeType(projectId,nodeType);
 	}
 
 	@Override

+ 25 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ArchiveTreeServiceImpl.java

@@ -1199,4 +1199,29 @@ public class ArchiveTreeServiceImpl extends BaseServiceImpl<ArchiveTreeMapper, A
         }
         return true;
     }
+
+    /**
+     * 删除子树
+     * @param id
+     * @return
+     */
+    public  boolean deleteTree(Long id) {
+        ArchiveTree dstNode = this.getById(id);
+        if (dstNode == null ) {
+            return false;
+        }
+
+        List<ArchiveTreeVO2> dstTrees = this.tree2(AuthUtil.getTenantId(), dstNode.getProjectId(),null, null,null,false);
+        if (dstTrees == null || dstTrees.size() == 0) {
+            return false;
+        }
+
+        ArchiveTreeVO2 subTree = ForestNodeMergerEx.getSubTree(dstTrees.get(0),id);
+
+        List<Long> ids = ForestNodeMergerEx.getChildrenIds(subTree);
+
+        ids.add(id);
+
+        return this.deleteLogic(ids);
+    }
 }

+ 155 - 110
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/FormulaServiceImpl.java

@@ -41,6 +41,7 @@ import javax.validation.constraints.NotNull;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.math.BigDecimal;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -74,7 +75,6 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
     private final ITextdictInfoService textDictInfoService;
     private final IFormulaDataBlockService formulaDataBlockService;
 
-    /**  private final Container env;*/
     private   TableElementConverter tec;
 //    private   Map<String,Object> constantMap;
 //    private   List<FormData> formDataList;
@@ -183,7 +183,6 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
         /*公式参数*/
         FormulaOption formulaOption = this.formulaOptionService.getOne(Wrappers.<FormulaOption>lambdaQuery().eq(FormulaOption::getParentId,one.getRelateId()).eq(FormulaOption::getContractId,contractId));
         if(formulaOption!=null){
-           /*数据格式 {tablename:{keyxxx:{option:[1|0]}}}*/
            tec.constantMap.put(FMOT,JSON.parseObject(formulaOption.getVal(),LinkedHashMap.class));
         }
         /*评定表*/
@@ -206,6 +205,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
     }
 
     public Long findFirstParentId(){
+        /*分项实测项目锚定点*/
         int max=10;
         int loop=0;
         Long parentId= tec.getCurrentNode().getParentId();
@@ -222,77 +222,73 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
         }
         return parentId;
     }
-
+    /*评定表处理*/
     public void assessmentForm(){
-        if(tec.getTableAll().stream().anyMatch(e->StringUtils.isEquals(e.getTableType(),5))){
-            /*评定节点*/
-            FormulaDataBlock fdb = findFdb();
-            if(!StringUtils.isEquals("[]",fdb.getVal())){
-                List<ElementBlock> elementBlockList =JSON.parseArray(fdb.getVal(),ElementBlock.class);
-                Map<String, Measurement> itemsMap = new HashMap<>();
-                this.formDataMap.values().forEach(e->{
-                    String eName=e.getEName();
-                    if(eName.contains("实测")&&!eName.contains("平均")&&!eName.contains("率")&&!eName.contains("判")){
-                        String point  =FormulaUtils.parseItemName(eName);
-                        /*评定匹配检验单的元素用相似匹配*/
-                        Measurement measurement = itemsMap.computeIfAbsent(point,k->new Measurement(point));
-                        measurement.setValue(e);
-                    }
-                });
-                if(itemsMap.size()>0){
-                    /*表内用同行匹配*/
-                    tec.getFormDataMap().values().stream()
-                            .filter(v -> v.getEName().contains("率") || v.getEName().contains("判"))
-                            .forEach(v -> {
-                                itemsMap.values().stream()
-                                        .filter(i -> i.getPass() == null || i.getJudge() == null)
-                                        .filter(i -> {
-                                            FormData vf = i.getValue();
-                                            return vf != null && vf.getTableName().equals(v.getTableName()) && !vf.getCode().equals(v.getCode())&&FormulaUtils.similarity(v.getEName(),vf.getEName())>0.75;
-                                        }).max(Comparator.comparingDouble((Measurement i)->FormulaUtils.similarity(v.getEName(),i.getValue().getEName())))
-                                        .ifPresent(i->{
-                                               if (v.getEName().contains("率") && i.getPass() == null) {
-                                                   i.setPass(v);
-                                               } else if (v.getEName().contains("判") && i.getJudge() == null) {
-                                                   i.setJudge(v);
-                                               }
-                                         });
-                            });
-
-                    AtomicBoolean update= new AtomicBoolean(false);
-                    itemsMap.values().stream().filter(Measurement::isMatching).forEach(t->{
-                        ElementBlock g=null;
-                        FormData vfd=t.getValue();
-                        if(vfd.executable()&&vfd.getFormula().getRelyList()!=null){
-                            List<String> relyList = vfd.getFormula().getRelyList();
-                           Optional<ElementBlock> op= elementBlockList.stream().filter(e->relyList.contains(e.getCode())).findAny();
-                           if(op.isPresent()){
-                               g=op.get();
-                           }
+        try {
+            if (tec.getTableAll().stream().anyMatch(e -> StringUtils.isEquals(e.getTableType(), 5))) {
+                /*评定节点*/
+                FormulaDataBlock fdb = findFdb();
+                if (!StringUtils.isEquals("[]", fdb.getVal())) {
+                    List<ElementBlock> elementBlockList = JSON.parseArray(fdb.getVal(), ElementBlock.class);
+                    Map<String, Measurement> itemsMap = new HashMap<>();
+                    this.formDataMap.values().forEach(e -> {
+                        String eName = e.getEName();
+                        if (eName.contains("实测") && !eName.contains("平均") && !eName.contains("率") && !eName.contains("判")) {
+                            String point = FormulaUtils.parseItemName(eName);
+                            /*评定匹配检验单的元素用相似匹配*/
+                            Measurement measurement = itemsMap.computeIfAbsent(point, k -> new Measurement(point));
+                            measurement.setValue(e);
                         }
-                        if(g==null){
-                            Optional<ElementBlock> op= elementBlockList.stream().filter(w->FormulaUtils.similarity(w.getEName(),t.getPoint())>0.6).reduce((a, b) -> Comparator.<Double>reverseOrder().compare(FormulaUtils.similarity(a.getEName(),t.getPoint()), FormulaUtils.similarity(b.getEName(),t.getPoint())) <= 0 ? a : b);
-                            if(op.isPresent()){
-                                g=op.get();
+                    });
+                    if (itemsMap.size() > 0) {
+                        /*表内用同行匹配*/
+                        List<FormData> primary = tec.getFormDataMap().values().stream().filter(v -> v.getEName().contains("率") || v.getEName().contains("判")).collect(Collectors.toList());
+                        itemsMap.values().forEach(i -> {
+                            FormData vf = i.getValue();
+                            primary.stream().filter(p -> vf.getMaxRow().equals(p.getMaxRow()) && vf.getTableName().equals(p.getTableName())).forEach(t -> {
+                                if (t.getEName().contains("率")) {
+                                    i.setPass(t);
+                                } else if (t.getEName().contains("判")) {
+                                    i.setJudge(t);
+                                }
+                            });
+                        });
+                        AtomicBoolean update = new AtomicBoolean(false);
+                        itemsMap.values().stream().filter(Measurement::isMatching).forEach(t -> {
+                            ElementBlock g = null;
+                            FormData vfd = t.getValue();
+                            if (vfd.executable() && vfd.getFormula().getRelyList() != null) {
+                                List<String> relyList = vfd.getFormula().getRelyList();
+                                /*先从公式去匹配*/
+                                Optional<ElementBlock> op = elementBlockList.stream().filter(e -> relyList.contains(e.getCode())).findAny();
+                                if (op.isPresent()) {
+                                    g = op.get();
+                                }
                             }
-                        }
-                        if(g!=null){
-                            List<ItemBlock> itemBlockList =g.getList();
-                            int originSize=itemBlockList.size();
-                            List<Long> ids = this.jdbcTemplate.queryForList("select b.p_key_id from m_wbs_tree_contract a join m_wbs_tree_contract b on (a.parent_id=b.parent_id and a.contract_id=b.contract_id) where a.p_key_id="+tec.getCurrentNode().getPkId()+" and b.is_deleted=0 and b.node_type=6",Long.class);
-                            itemBlockList.removeIf(ik->!ids.contains(ik.getPkeyId()));
-                            if(itemBlockList.size()>0){
-                                int total=itemBlockList.stream().mapToInt(ItemBlock::getSubTotal).sum();
-                                int passNum=itemBlockList.stream().mapToInt(ItemBlock::getSubPass).sum();
-                                double passRate=100*(double)passNum/(double) total;
-                                FormulaUtils.write(t.getPass(),StringUtils.number2String(passRate,1),null);
-                                if(passRate>=60){
-                                    FormulaUtils.write(t.getJudge(),"合格",null);
+                            if (g == null) {
+                                Optional<ElementBlock> op = elementBlockList.stream().filter(w -> FormulaUtils.similarity(w.getEName(), t.getPoint()) > 0.6).max(Comparator.comparingDouble((ElementBlock b) -> FormulaUtils.similarity(b.getEName(), t.getPoint())));
+                                /*相似匹配*/
+                                if (op.isPresent()) {
+                                    g = op.get();
                                 }
-                                itemBlockList.sort(Comparator.comparingInt(a->ids.indexOf(a.getPkeyId())));
-                                List<String> values=itemBlockList.stream().map(ItemBlock::getData).flatMap(v->v.stream().flatMap(Collection::stream)).map(Object::toString).collect(Collectors.toList());
-                                int scale = StringUtils.getScale(values);
-                                FormulaUtils.write(t.getValue(),values.stream().map(u->StringUtils.number2String(u,scale)).collect(Collectors.toList()), true);
+                            }
+                            if (g != null) {
+                                List<ItemBlock> itemBlockList = g.getList();
+                                int originSize = itemBlockList.size();
+                                List<Long> ids = this.jdbcTemplate.queryForList("select b.p_key_id from m_wbs_tree_contract a join m_wbs_tree_contract b on (a.parent_id=b.parent_id and a.contract_id=b.contract_id) where a.p_key_id=" + tec.getCurrentNode().getPkId() + " and b.is_deleted=0 and b.node_type=6", Long.class);
+                                itemBlockList.removeIf(ik -> !ids.contains(ik.getPkeyId()));
+                                if (itemBlockList.size() > 0) {
+                                    int total = itemBlockList.stream().mapToInt(ItemBlock::getSubTotal).sum();
+                                    int passNum = itemBlockList.stream().mapToInt(ItemBlock::getSubPass).sum();
+                                    double passRate = 100 * (double) passNum / (double) total;
+                                    FormulaUtils.write(t.getPass(), StringUtils.number2String(passRate, 1), false);
+                                    if (passRate >= 60) {
+                                        FormulaUtils.write(t.getJudge(), "合格", false);
+                                    }
+                                    itemBlockList.sort(Comparator.comparingInt(a -> ids.indexOf(a.getPkeyId())));
+                                    List<String> values = itemBlockList.stream().map(ItemBlock::getData).flatMap(v -> v.stream().flatMap(Collection::stream)).map(Object::toString).collect(Collectors.toList());
+                                    int scale = StringUtils.getScale(values);
+                                    FormulaUtils.write(t.getValue(), values.stream().map(u -> StringUtils.number2String(u, scale)).collect(Collectors.toList()), true);
 
 //                                   if(t.getValue().getEName().contains("±")){
 //                                       /*存在偏差范围则获取的是偏差值:实测-设计*/
@@ -310,19 +306,22 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
 //                                   }else{
 //                                      FormulaUtils.write(t.getValue(),itemBlockList.stream().map(ItemBlock::getData).flatMap(v->v.stream().flatMap(Collection::stream)).collect(Collectors.toList()),true);
 //                                   }
+                                }
+                                t.flush();
+                                if (originSize > 0 && originSize != itemBlockList.size()) {
+                                    g.setList(itemBlockList);
+                                    update.set(true);
+                                }
                             }
-                            t.flush();
-                            if(originSize>0&&originSize!=itemBlockList.size()){
-                                g.setList(itemBlockList);
-                                update.set(true);
-                            }
+                        });
+                        if (update.get()) {
+                            this.formulaDataBlockService.saveOrUpdate(fdb);
                         }
-                    });
-                    if(update.get()){
-                        this.formulaDataBlockService.saveOrUpdate(fdb);
                     }
                 }
             }
+        }catch (Exception e){
+            e.printStackTrace();
         }
     }
 
@@ -566,24 +565,28 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
 
     @Override
     public IFormulaService sort() {
-        Map<Boolean,List<FormData>> map = tec.formDataList.stream().collect(Collectors.partitioningBy(e->Func.isNotEmpty(e.getFormula())&&e.getFormula().getFormula().contains("E[")));
-        tec.formDataList.clear();
-        /*没有依赖的*/
-        List<FormData> simple=map.get(false);
-        if(CollectionUtil.isNotEmpty(simple)){
-            tec.formDataList.addAll(simple);
-        }
-        /*有依赖的*/
-        List<FormData> rely= map.get(true);
-        if(CollectionUtil.isNotEmpty(rely)){
-            sort(rely,((rely.size()+1)/2)*rely.size());
-            tec.formDataList.addAll(rely);
+        try {
+            Map<Boolean, List<FormData>> map = tec.formDataList.stream().collect(Collectors.partitioningBy(e -> Func.isNotEmpty(e.getFormula()) && e.getFormula().getFormula().contains("E[")));
+            tec.formDataList.clear();
+            /*没有依赖的*/
+            List<FormData> simple = map.get(false);
+            if (CollectionUtil.isNotEmpty(simple)) {
+                tec.formDataList.addAll(simple);
+            }
+            /*有依赖的*/
+            List<FormData> rely = map.get(true);
+            if (CollectionUtil.isNotEmpty(rely)) {
+                sort(rely, ((rely.size() + 1) / 2) * rely.size());
+                tec.formDataList.addAll(rely);
+            }
+            /*初始化排序值,每个点间隔1000,方便插入*/
+            AtomicInteger sort = new AtomicInteger();
+            tec.formDataList.forEach(e -> e.setSort(sort.getAndAdd(1000)));
+            /*汇总阶段执行的公式*/
+            summaryPre();
+        }catch (Exception e){
+            e.printStackTrace();
         }
-        /*初始化排序值,每个点间隔1000,方便插入*/
-        AtomicInteger sort= new AtomicInteger();
-        tec.formDataList.forEach(e->e.setSort(sort.getAndAdd(1000)));
-        /*汇总阶段执行的公式*/
-        summaryPre();
         return this;
     }
 
@@ -729,14 +732,22 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                             }
                             if(fd.getCoordsList().size()>1&&f.split("[/+\\-*]").length>1){
                                 LinkedHashMap<String,FormData> fdMap =new LinkedHashMap<>();
-                                Optional<FormData> tto= ele.stream().max(Comparator.comparingInt(fe->fe.getValues().size()));
-                                Optional<FormData> tts= ele.stream().min(Comparator.comparingInt(fe->fe.getValues().size()));
-                                if(tto.isPresent()&&tts.isPresent()){
-                                    if(tto.get().getValues().size()!=tts.get().getValues().size()){
-                                        int baseLength=tto.get().getValues().size();
-                                        ele.forEach(e->{
-                                            e.setStep(baseLength/e.getValues().size());
-                                        });
+//                                Optional<FormData> tto= ele.stream().max(Comparator.comparingInt(fe->fe.getValues().size()));
+//                                Optional<FormData> tts= ele.stream().min(Comparator.comparingInt(fe->fe.getValues().size()));
+//                                if(tto.isPresent()&&tts.isPresent()){
+//                                    if(tto.get().getValues().size()!=tts.get().getValues().size()){
+//                                        int baseLength=tto.get().getValues().size();
+//                                        ele.forEach(e->{
+//                                            e.setStep(baseLength/e.getValues().size());
+//                                        });
+//                                    }
+//                                }
+                                FormData maxFormData = Collections.max(ele, Comparator.comparingInt((FormData ef)->ef.getValues().size()));
+                                FormData minFormData = Collections.min(ele, Comparator.comparingInt((FormData ef)->ef.getValues().size()));
+                                if (maxFormData.getValues().size() != minFormData.getValues().size()) {
+                                    int baseLength = maxFormData.getValues().size();
+                                    for (FormData formData : ele) {
+                                        formData.setStep(baseLength / formData.getValues().size());
                                     }
                                 }
                                 ele.forEach(e->{
@@ -747,12 +758,17 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                                 while (cda.hasNext()){
                                     LinkedHashMap<String,ElementData> tip= cda.next();
                                     Map<String, Object> variable = new HashMap<>(tec.constantMap);
+                                    @SuppressWarnings("unchecked")
                                     Map<String,Object> em= (Map<String, Object>) variable.computeIfAbsent(E, k->new HashMap<>());
                                     int index= new ArrayList<>(tip.values()).get(0).getIndex();
                                     for(Map.Entry<String,ElementData> se:tip.entrySet()){
                                         Object value=se.getValue().getValue();
                                         if(CustomFunction.isNumber(value)){
-                                            em.put(se.getKey(),StringUtils.obj2Double(value));
+                                            if(StringUtils.isDouble(value)){
+                                                em.put(se.getKey(), new BigDecimal(value.toString()));
+                                            }else{
+                                                em.put(se.getKey(),StringUtils.handleObj2Integer(value));
+                                            }
                                         }else{
                                             em.put(se.getKey(),value);
                                         }
@@ -762,13 +778,10 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                                 }
                                 if(local.size()>0){
                                     List<Object> values = slice(local,tec.constantMap,f);
-                                    if(fd.getTableName().equals(checkTable)){
-                                        FormulaUtils.write(fd,values,false);
-                                    }else{
-                                        FormulaUtils.write(fd,values,true);
-                                    }
+                                    FormulaUtils.write(fd,values, !fd.getTableName().equals(checkTable));
                                 }
                             }else{
+                                @SuppressWarnings("unchecked")
                                 Map<String,Object> em = (Map<String, Object>) currentMap.computeIfAbsent(E,(k)-> new HashMap<>());
                                 ele.forEach(e->{
                                     em.put(e.getCode(),e.getValues().stream().map(ElementData::getValue).collect(Collectors.toList()));
@@ -776,6 +789,8 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                                 Object data =Expression.parse(formula.getFormula()).calculate(currentMap);
                                 write(fd,data);
                             }
+                            /*重置*/
+                            ele.stream().filter(s->s.getOffset()>0).forEach(FormData::restore);
                         }else{
                             Object data =Expression.parse(formula.getFormula()).calculate(currentMap);
                             write(fd,data);
@@ -789,6 +804,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                 fd.setUpdate(1);
             }
         }
+
     }
     /**附表处理*/
     public void forSubTb(){
@@ -839,6 +855,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                     for (WbsTreeContract data : subTabList) {
                         /*自动挂载附表情况下,装配TableInfo数据*/
                         R bussDataInfo = this.getBussDataInfo(data.getPKeyId(), 1);
+                        @SuppressWarnings("unchecked")
                         Map<String, Object>  data1 = (Map<String, Object>) bussDataInfo.getData();
                         data1.put("pkeyId",data.getPKeyId());
                         dataArray.add(data1);
@@ -1020,7 +1037,9 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                          }
                          if(Func.isNotEmpty(list)){
                              targetItem.setSubTotal(list.size());
-                             targetItem.setDesigns(designList.getValues().stream().map(ElementData::getValue).flatMap(e->CustomFunction.obj2ListNe(e).stream()).filter(StringUtils::isNumber).map(StringUtils::obj2Double).collect(Collectors.toList()));
+                             if(Func.isNotEmpty(designList)) {
+                                 targetItem.setDesigns(designList.getValues().stream().map(ElementData::getValue).flatMap(e -> CustomFunction.obj2ListNe(e).stream()).filter(StringUtils::isNumber).map(StringUtils::obj2Double).collect(Collectors.toList()));
+                             }
                              AtomicInteger index= new AtomicInteger();
                              int len=targetItem.getDesigns().size();
                              if(len>0){
@@ -1404,7 +1423,7 @@ public  List<ElementData> setScale(Integer scale,List<ElementData> data){
                          while (m.find()){
                              String el=m.group();
                              String pstr=el.replaceAll("^"+FC_REG+"ifelse\\(","").replaceAll("\\)$","");
-                             String pa[]=pstr.split(",");
+                             String[] pa =pstr.split(",");
                              if(pa.length==3){
                                  Object data = Expression.parse(pa[0]+"?"+pa[1]+":"+pa[2]).calculate(createCurrentMap(el));
                                  f=f.replace(el,putDataWithKey(data));
@@ -1416,12 +1435,38 @@ public  List<ElementData> setScale(Integer scale,List<ElementData> data){
                        max++;
                      }while (f.contains("ifelse")&&max<20);
                  }
+                 if(f.contains("avg4segment")){
+                     Matcher m = RegexUtils.matcher(FC_REG+"(avg4segment)\\(([^)]+)\\)",f);
+                     while (m.find()){
+                         String[] args=m.group(2).split(",");
+                         List<FormData> target = getFormDataByCode(args[0]);
+                         if(!target.isEmpty()){
+                             FormData a=target.get(0);
+                             int n=Math.max(1,a.coordsList.size()/fd.getCoordsList().size());
+                             List<Object> data=CustomFunction.avg4segment(a.getValues().stream().map(ElementData::getValue).collect(Collectors.toList()),n);
+                             f=f.replace(m.group(),putDataWithKey(data));
+                         }
+                     }
+                 }
+                 if(f.contains("skip")){
+                     Matcher m = RegexUtils.matcher(FC_REG+"(skip)\\(([^)]+)\\)",f);
+                     while (m.find()){
+                         String[] args=m.group(2).split(",");
+                         List<FormData> target = getFormDataByCode(args[0]);
+                         if(!target.isEmpty()){
+                             FormData a=target.get(0);
+                             a.setOffset(StringUtils.handleObj2Integer(args[1]));
+                             f=f.replace(m.group(),args[0]);
+                         }
+                     }
+                 }
                  if(f.contains("quantity")){
                      /*聚合*/
                      Matcher m = RegexUtils.matcher(FC_REG+"(quantity)\\(([^)]+)\\)",f);
                      while (m.find()) {
                          Object data=null;
                          List<String> codeList = getCodeList(m.group(2));
+                         @SuppressWarnings("unchecked")
                          Map<String,List<Map<String,Object>>> textInfoMap= (Map<String, List<Map<String, Object>>>) tec.constantMap.getOrDefault(TEXT_INFO_MAP,new HashMap<>());
                          List<Map<String,Object>> tableColKeyVal= textInfoMap.get(codeList.get(0));
                          if(Func.isNotEmpty(tableColKeyVal)){