瀏覽代碼

Merge branch 'refs/heads/dev' into feature-lihb-bug

# 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/IWbsTreeContractService.java
#	blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ExcelTabServiceImpl.java
#	blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/FormulaServiceImpl.java
#	blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeContractServiceImpl.java
LHB 1 月之前
父節點
當前提交
c591f6161e
共有 100 個文件被更改,包括 3822 次插入361 次删除
  1. 14 0
      blade-common/pom.xml
  2. 238 0
      blade-common/src/main/java/org/springblade/common/utils/DeepSeekClient.java
  3. 34 0
      blade-common/src/main/java/org/springblade/common/vo/DeepSeekResponse.java
  4. 7 1
      blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/entity/Oss.java
  5. 5 4
      blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/feign/CommonFileClient.java
  6. 24 0
      blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/feign/FeignConfig.java
  7. 5 5
      blade-ops/blade-admin/pom.xml
  8. 10 0
      blade-ops/blade-resource/pom.xml
  9. 1 0
      blade-ops/blade-resource/src/main/java/org/springblade/resource/builder/oss/OssBuilder.java
  10. 1 0
      blade-ops/blade-resource/src/main/java/org/springblade/resource/builder/ossre/MinioTemplateRe.java
  11. 1 1
      blade-ops/blade-resource/src/main/java/org/springblade/resource/endpoint/LargeFileEndpoint.java
  12. 5 4
      blade-ops/blade-resource/src/main/java/org/springblade/resource/feign/CommonFileClientImpl.java
  13. 1 0
      blade-ops/blade-resource/src/main/java/org/springblade/resource/mapper/OssMapper.xml
  14. 64 0
      blade-service-api/blade-archive-api/src/main/java/org/springblade/archive/entity/ArchiveAiName.java
  15. 2 0
      blade-service-api/blade-archive-api/src/main/java/org/springblade/archive/entity/ArchivesAuto.java
  16. 9 0
      blade-service-api/blade-archive-api/src/main/java/org/springblade/archive/trans/ArchiveFileVo.java
  17. 11 0
      blade-service-api/blade-archive-api/src/main/java/org/springblade/archive/vo/ArchiveAiNameVO.java
  18. 12 0
      blade-service-api/blade-archive-api/src/main/java/org/springblade/archive/vo/ArchiveAiNameVO1.java
  19. 34 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/TrialAutoNumberDTO.java
  20. 6 3
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/TrialMaterialMobilizationDTO.java
  21. 37 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/TrialNumberRuleDTO.java
  22. 6 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/TrialSampleInfoDTO.java
  23. 11 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/TrialSelfInspectionRecordDTO.java
  24. 7 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/ArchiveFile.java
  25. 58 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/TrialAutoNumber.java
  26. 77 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/TrialNumberRule.java
  27. 3 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/feign/ArchiveFileClient.java
  28. 1 1
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/feign/InformationQueryClient.java
  29. 5 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/ArchiveFileVO.java
  30. 34 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/TrialAutoNumberVO.java
  31. 36 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/TrialNumberRuleVO.java
  32. 17 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/TrialNumberRuleVO1.java
  33. 16 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/dto/AddBussFileSortDTO.java
  34. 2 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/TableFile.java
  35. 3 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/entity/WbsTreeContract.java
  36. 9 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/feign/ExcelTabClient.java
  37. 5 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/feign/ExcelTabClientFallBack.java
  38. 10 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/CurrentNode.java
  39. 11 4
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/EvaSummary.java
  40. 5 1
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/FB02.java
  41. 8 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/WbsTreeContractLazyVO.java
  42. 1 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/WtcEva.java
  43. 1 0
      blade-service-api/blade-user-api/src/main/java/org/springblade/system/user/vo/InformationQueryBIMVO.java
  44. 155 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchiveAiNameController.java
  45. 53 21
      blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchivesAutoController.java
  46. 33 13
      blade-service/blade-archive/src/main/java/org/springblade/archive/external/impl/ExternalDataArchiveFileService.java
  47. 44 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/ArchiveAiNameMapper.java
  48. 32 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/ArchiveAiNameMapper.xml
  49. 2 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/ArchivesAutoMapper.java
  50. 4 1
      blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/ArchivesAutoMapper.xml
  51. 2 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/TaskSplitMapper.java
  52. 9 1
      blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/TaskSplitMapper.xml
  53. 45 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/IArchiveAiNameService.java
  54. 1 1
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/IArchiveNameService.java
  55. 7 1
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/IArchivesAutoService.java
  56. 155 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveAiNameServiceImpl.java
  57. 51 6
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveAutoPdfServiceImpl.java
  58. 11 4
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveNameServiceImpl.java
  59. 286 85
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchivesAutoServiceImpl.java
  60. 13 7
      blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/TaskSplitServiceImpl.java
  61. 30 3
      blade-service/blade-business/src/main/java/org/springblade/business/controller/EVisaTaskCheckController.java
  62. 84 8
      blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java
  63. 129 0
      blade-service/blade-business/src/main/java/org/springblade/business/controller/TrialAutoNumberController.java
  64. 1 1
      blade-service/blade-business/src/main/java/org/springblade/business/controller/TrialMaterialController.java
  65. 347 0
      blade-service/blade-business/src/main/java/org/springblade/business/controller/TrialNumberRuleController.java
  66. 5 0
      blade-service/blade-business/src/main/java/org/springblade/business/feignClient/ArchiveFileClientImpl.java
  67. 3 2
      blade-service/blade-business/src/main/java/org/springblade/business/feignClient/InformationQueryClientImpl.java
  68. 24 4
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/ArchiveFileMapper.xml
  69. 44 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/TrialAutoNumberMapper.java
  70. 22 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/TrialAutoNumberMapper.xml
  71. 46 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/TrialNumberRuleMapper.java
  72. 34 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/TrialNumberRuleMapper.xml
  73. 41 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/ITrialAutoNumberService.java
  74. 1 1
      blade-service/blade-business/src/main/java/org/springblade/business/service/ITrialMaterialMobilizationService.java
  75. 59 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/ITrialNumberRuleService.java
  76. 7 2
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/ArchiveFileServiceImpl.java
  77. 67 43
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/EntrustInfoServiceImpl.java
  78. 8 1
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TaskServiceImpl.java
  79. 45 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialAutoNumberServiceImpl.java
  80. 19 2
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialMaterialMobilizationServiceImpl.java
  81. 455 0
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialNumberRuleServiceImpl.java
  82. 18 4
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialSampleInfoServiceImpl.java
  83. 44 2
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialSelfInspectionRecordServiceImpl.java
  84. 49 3
      blade-service/blade-business/src/main/java/org/springblade/business/utils/PDFUtil.java
  85. 19 14
      blade-service/blade-e-visa/src/main/java/org/springblade/evisa/controller/ArchiveController.java
  86. 0 4
      blade-service/blade-e-visa/src/main/java/org/springblade/evisa/controller/EVController.java
  87. 96 20
      blade-service/blade-e-visa/src/main/java/org/springblade/evisa/service/impl/EVDataServiceImpl.java
  88. 7 1
      blade-service/blade-e-visa/src/main/java/org/springblade/evisa/utils/FileUtils.java
  89. 100 10
      blade-service/blade-e-visa/src/main/java/org/springblade/evisa/utils/PDFUtils.java
  90. 3 2
      blade-service/blade-manager/src/main/java/com/mixsmart/utils/CustomFunction.java
  91. 1 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/bean/TableInfo.java
  92. 190 50
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java
  93. 17 2
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/TableFileController.java
  94. 8 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/feign/ExcelTabClientImpl.java
  95. 1 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/formula/impl/ExecutorMeter.java
  96. 32 13
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ArchiveTreeContractMapper.xml
  97. 4 3
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/TableFileMapper.xml
  98. 7 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreeContractMapper.xml
  99. 3 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IExcelTabService.java
  100. 2 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IWbsTreeContractService.java

+ 14 - 0
blade-common/pom.xml

@@ -82,6 +82,20 @@
             <version>0.1.6</version>
         </dependency>
 
+        <!-- 使用OkHttp -->
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp</artifactId>
+            <version>4.9.3</version>
+        </dependency>
+
+        <!-- 使用Gson进行JSON处理 -->
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+            <version>2.8.9</version>
+        </dependency>
+
     </dependencies>
 
     <build>

+ 238 - 0
blade-common/src/main/java/org/springblade/common/utils/DeepSeekClient.java

@@ -0,0 +1,238 @@
+package org.springblade.common.utils;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import okhttp3.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+@Component
+public class DeepSeekClient {
+    private static final Logger logger = LoggerFactory.getLogger(DeepSeekClient.class);
+
+    private static final String API_KEY = "sk-16ebce9ef2eb40a68f29d9c2a70fe6b6";
+
+    private static final String API_URL = "https://api.deepseek.com/v1/chat/completions";
+
+    private final OkHttpClient client;
+    private final Gson gson = new Gson();
+
+    public DeepSeekClient() {
+        this.client = new OkHttpClient.Builder()
+                .connectTimeout(30, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(30, TimeUnit.SECONDS)
+                .build();
+    }
+
+    /**
+     * 请求 DeepSeek API
+     */
+    public String callDeepSeek(String prompt) throws IOException {
+        DeepSeekRequest request = new DeepSeekRequest(prompt, "deepseek-chat");
+        String requestJson = gson.toJson(request);
+
+        logger.debug("Sending request to DeepSeek: {}", requestJson);
+
+        Request httpRequest = new Request.Builder()
+                .url(API_URL)
+                .post(RequestBody.create(requestJson, MediaType.parse("application/json")))
+                .addHeader("Authorization", "Bearer " + API_KEY)
+                .addHeader("Content-Type", "application/json")
+                .addHeader("Accept", "application/json")
+                .build();
+
+        try (Response response = client.newCall(httpRequest).execute()) {
+            if (!response.isSuccessful()) {
+                String errorBody = response.body() != null ? response.body().string() : "No error body";
+                logger.error("API request failed with code: {}, Body: {}", response.code(), errorBody);
+                throw new IOException("API request failed with code: " + response.code());
+            }
+            return response.body().string();
+        }
+    }
+
+    /**
+     * 解析响应获取结果
+     */
+    public String analysisResponse(String responseJson) {
+        try {
+            JsonObject jsonObject = JsonParser.parseString(responseJson).getAsJsonObject();
+
+            if (jsonObject.has("error")) {
+                JsonObject error = jsonObject.getAsJsonObject("error");
+                String errorMsg = error.get("message").getAsString();
+                logger.error("API returned error: {}", errorMsg);
+                return "Error: " + errorMsg;
+            }
+
+            DeepSeekResponse response = gson.fromJson(jsonObject, DeepSeekResponse.class);
+
+            if (response == null || response.getChoices() == null || response.getChoices().isEmpty()) {
+                logger.error("Invalid response structure");
+                return "Error: Invalid response structure";
+            }
+
+            return response.getChoices().get(0).getMessage().getContent();
+        } catch (Exception e) {
+            logger.error("Error parsing response: {}", e.getMessage());
+            return "Error: " + e.getMessage();
+        }
+    }
+
+    /**
+     * 直接获取精简后的内容
+     */
+    public String getSimplifiedContent(String prompt) {
+        try {
+            String response = callDeepSeek(prompt);
+            return analysisResponse(response);
+        } catch (IOException e) {
+            logger.error("API call failed: {}", e.getMessage());
+            return "Error: " + e.getMessage();
+        }
+    }
+
+    static class DeepSeekRequest {
+        private String model;
+        private Message[] messages;
+        private double temperature = 0.7;
+        private int max_tokens = 2000;
+        private boolean stream = false;
+
+        // 构造函数
+        public DeepSeekRequest(String prompt, String model) {
+            this.model = model;
+
+            // 构造专家级对话上下文
+            this.messages = new Message[]{
+                    // 系统角色设定
+                    new Message("system", "你是有20年经验的建筑施工资料专家,熟悉GB/T50328、GB50202等规范。请用专业术语回答。"),
+
+                    // 用户问题
+                    new Message("user", "作为资料管理专家,请处理以下案卷题名:" + prompt)
+            };
+
+            this.temperature = 0.3;  // 降低随机性,提高专业性
+            this.max_tokens = 1000;
+        }
+
+        // Getters and Setters
+        public String getModel() {
+            return model;
+        }
+
+        public void setModel(String model) {
+            this.model = model;
+        }
+
+        public Message[] getMessages() {
+            return messages;
+        }
+
+        public void setMessages(Message[] messages) {
+            this.messages = messages;
+        }
+
+        public double getTemperature() {
+            return temperature;
+        }
+
+        public void setTemperature(double temperature) {
+            this.temperature = temperature;
+        }
+
+        public int getMax_tokens() {
+            return max_tokens;
+        }
+
+        public void setMax_tokens(int max_tokens) {
+            this.max_tokens = max_tokens;
+        }
+
+        public boolean isStream() {
+            return stream;
+        }
+
+        public void setStream(boolean stream) {
+            this.stream = stream;
+        }
+    }
+
+    static class Message {
+        private String role;
+        private String content;
+
+        // 构造函数
+        public Message(String role, String content) {
+            this.role = role;
+            this.content = content;
+        }
+
+        // Getters and Setters
+        public String getRole() {
+            return role;
+        }
+
+        public void setRole(String role) {
+            this.role = role;
+        }
+
+        public String getContent() {
+            return content;
+        }
+
+        public void setContent(String content) {
+            this.content = content;
+        }
+    }
+
+    static class DeepSeekResponse {
+        private List<Choice> choices;
+
+        public List<Choice> getChoices() {
+            return choices;
+        }
+
+        public void setChoices(List<Choice> choices) {
+            this.choices = choices;
+        }
+
+        static class Choice {
+            private Message message;
+            private int index;
+            private String finish_reason;
+
+            public Message getMessage() {
+                return message;
+            }
+
+            public void setMessage(Message message) {
+                this.message = message;
+            }
+
+            public int getIndex() {
+                return index;
+            }
+
+            public void setIndex(int index) {
+                this.index = index;
+            }
+
+            public String getFinish_reason() {
+                return finish_reason;
+            }
+
+            public void setFinish_reason(String finish_reason) {
+                this.finish_reason = finish_reason;
+            }
+        }
+    }
+}

+ 34 - 0
blade-common/src/main/java/org/springblade/common/vo/DeepSeekResponse.java

@@ -0,0 +1,34 @@
+package org.springblade.common.vo;
+
+import lombok.Data;
+
+import java.util.List;
+@Data
+public class DeepSeekResponse {
+    private String id;
+    private String object;
+    private long created;
+    private String model;
+    private List<Choice> choices;
+    private Usage usage;
+
+    @Data
+    public static class Choice {
+        private int index;
+        private Message message;
+        private String finish_reason;
+    }
+
+    @Data
+    public static class Message {
+        private String role;
+        private String content;
+    }
+
+    @Data
+    public static class Usage {
+        private int prompt_tokens;
+        private int completion_tokens;
+        private int total_tokens;
+    }
+}

+ 7 - 1
blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/entity/Oss.java

@@ -52,6 +52,13 @@ public class Oss extends TenantEntity {
      */
     @ApiModelProperty(value = "资源地址")
     private String endpoint;
+
+    /**
+     * oss地址
+     */
+    @ApiModelProperty(value = "资源地址")
+    private String transformEndpoint;
+
     /**
      * accessKey
      */
@@ -83,5 +90,4 @@ public class Oss extends TenantEntity {
     @ApiModelProperty(value = "备注")
     private String remark;
 
-
 }

+ 5 - 4
blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/feign/CommonFileClient.java

@@ -6,23 +6,24 @@ import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.http.MediaType;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RequestPart;
 import org.springframework.web.multipart.MultipartFile;
 
 @FeignClient(
-        value = AppConstant.APPLICATION_RESOURCE_NAME
+        value = AppConstant.APPLICATION_RESOURCE_NAME,configuration = FeignConfig.class
 )
 public interface CommonFileClient {
 
     String API_PREFIX = "/CommonFileApi";
 
     @PostMapping(value = API_PREFIX + "/pngOrJpgToPdf", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
-    NewBladeFile pngOrJpgToPdf(MultipartFile file);
+    NewBladeFile pngOrJpgToPdf(@RequestPart("file")MultipartFile file);
 
     @PostMapping(value = API_PREFIX + "/wordToPdf", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
-    NewBladeFile wordToPdf(MultipartFile file);
+    NewBladeFile wordToPdf(@RequestPart("file")MultipartFile file);
 
     @PostMapping(value = API_PREFIX + "/excelToPdf", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
-    NewBladeFile excelToPdf(MultipartFile file);
+    NewBladeFile excelToPdf(@RequestPart("file")MultipartFile file);
 
     @PostMapping(value = API_PREFIX + "/getPdfNum")
     String getPdfNum(@RequestParam("url") String url);

+ 24 - 0
blade-ops-api/blade-resource-api/src/main/java/org/springblade/resource/feign/FeignConfig.java

@@ -0,0 +1,24 @@
+package org.springblade.resource.feign;
+
+import feign.codec.Encoder;
+import feign.form.spring.SpringFormEncoder;
+import org.springframework.beans.factory.ObjectFactory;
+import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
+import org.springframework.cloud.openfeign.support.SpringEncoder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class FeignConfig {
+    private final ObjectFactory<HttpMessageConverters> messageConverters;
+
+    public FeignConfig(ObjectFactory<HttpMessageConverters> messageConverters) {
+        this.messageConverters = messageConverters;
+    }
+
+    @Bean
+    public Encoder feignEncoder() {
+        // 默认使用 SpringEncoder(支持 JSON),但如果遇到 MultipartFile 则用 SpringFormEncoder
+        return new SpringFormEncoder(new SpringEncoder(messageConverters));
+    }
+}

+ 5 - 5
blade-ops/blade-admin/pom.xml

@@ -91,11 +91,11 @@
             <artifactId>spring-cloud-starter-security</artifactId>
         </dependency>
         <!--Taobao-Sdk-->
-        <dependency>
-            <groupId>com.taobao</groupId>
-            <artifactId>taobao-sdk</artifactId>
-            <version>20201116</version>
-        </dependency>
+<!--        <dependency>-->
+<!--            <groupId>com.taobao</groupId>-->
+<!--            <artifactId>taobao-sdk</artifactId>-->
+<!--            <version>20201116</version>-->
+<!--        </dependency>-->
     </dependencies>
 
     <build>

+ 10 - 0
blade-ops/blade-resource/pom.xml

@@ -149,6 +149,16 @@
             <groupId>org.springblade</groupId>
             <artifactId>blade-starter-oss</artifactId>
         </dependency>
+        <dependency>
+            <groupId>io.github.openfeign.form</groupId>
+            <artifactId>feign-form</artifactId>
+            <version>3.8.0</version>
+        </dependency>
+        <dependency>
+            <groupId>io.github.openfeign.form</groupId>
+            <artifactId>feign-form-spring</artifactId>
+            <version>3.8.0</version>
+        </dependency>
     </dependencies>
 
 

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

@@ -98,6 +98,7 @@ public class OssBuilder {
                 oss.setEndpoint("https://xinan1.zos.ctyun.cn");
             }
         }
+		oss.setEndpoint("https://xinan1.zos.ctyun.cn");
 		System.out.println("oss111="+oss.getEndpoint());
 		Oss ossCached = ossPool.get(tenantId);
 		OssTemplate template = templatePool.get(tenantId);

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

@@ -483,6 +483,7 @@ public class MinioTemplateRe implements OssTemplateRe {
 	//	ossProperties.setEndpoint("http://183.247.216.148:9000");
 		//return ossProperties.getEndpoint();
 		return "http://183.247.216.148:9000";
+		//return "http://8.130.108.204:9000";
 	}
 
 

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

@@ -286,7 +286,7 @@ public class LargeFileEndpoint {
 
             if (param.getFilename().contains("pdf") || param.getFilename().contains("PDF")) {
                 try {
-                    PdfReader pdfReader = new PdfReader(inputStream);
+                    PdfReader pdfReader = new PdfReader(new FileInputStream(file1));
                     int pages = pdfReader.getNumberOfPages();
                     //获取文件页数
                     newBladeFile.setPage(pages);

+ 5 - 4
blade-ops/blade-resource/src/main/java/org/springblade/resource/feign/CommonFileClientImpl.java

@@ -4,7 +4,6 @@ import com.aspose.cells.SaveFormat;
 import com.aspose.words.DocumentBuilder;
 import com.itextpdf.text.Image;
 import com.itextpdf.text.Rectangle;
-import com.itextpdf.text.Utilities;
 import com.itextpdf.text.pdf.PdfWriter;
 import lombok.AllArgsConstructor;
 import org.apache.pdfbox.pdmodel.PDDocument;
@@ -16,6 +15,7 @@ import org.springblade.core.tool.utils.FileUtil;
 import org.springblade.core.tool.utils.IoUtil;
 import org.springblade.resource.builder.oss.OssBuilder;
 import org.springblade.resource.vo.NewBladeFile;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.multipart.MultipartFile;
 
@@ -33,11 +33,12 @@ public class CommonFileClientImpl implements CommonFileClient {
      */
     private final OssBuilder ossBuilder;
 
+
     /**
      * png 和 jpg 转 pdf
      */
     @Override
-    public NewBladeFile pngOrJpgToPdf(MultipartFile file) {
+    public NewBladeFile pngOrJpgToPdf(@RequestParam("file")MultipartFile file) {
         String pdfFileUrl = "";
         InputStream pdfInput = null;
         try {
@@ -103,7 +104,7 @@ public class CommonFileClientImpl implements CommonFileClient {
      * word 转 pdf
      */
     @Override
-    public NewBladeFile wordToPdf(MultipartFile file) {
+    public NewBladeFile wordToPdf(@RequestParam("file")MultipartFile file) {
         String pdfFileUrl = "";
         int page = 0;
         InputStream pdfInput = null;
@@ -149,7 +150,7 @@ public class CommonFileClientImpl implements CommonFileClient {
      * excel 转 pdf
      */
     @Override
-    public NewBladeFile excelToPdf(MultipartFile file) {
+    public NewBladeFile excelToPdf(@RequestParam("file") MultipartFile file) {
         String pdfFileUrl = "";
         int page = 0;
         org.apache.poi.ss.usermodel.Workbook ss = null;

+ 1 - 0
blade-ops/blade-resource/src/main/java/org/springblade/resource/mapper/OssMapper.xml

@@ -14,6 +14,7 @@
         <result column="oss_code" property="ossCode"/>
         <result column="category" property="category"/>
         <result column="endpoint" property="endpoint"/>
+        <result column="transform_endpoint" property="transformEndpoint"/>
         <result column="access_key" property="accessKey"/>
         <result column="secret_key" property="secretKey"/>
         <result column="bucket_name" property="bucketName"/>

+ 64 - 0
blade-service-api/blade-archive-api/src/main/java/org/springblade/archive/entity/ArchiveAiName.java

@@ -0,0 +1,64 @@
+/*
+ *      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.archive.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import org.springblade.core.mp.base.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 实体类
+ *
+ * @author BladeX
+ * @since 2025-07-03
+ */
+@Data
+@TableName("u_archive_ai_name")
+@EqualsAndHashCode(callSuper = true)
+public class ArchiveAiName extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	* 项目ID
+	*/
+		private Long projectId;
+	/**
+	* 合同段ID
+	*/
+		private Long contractId;
+	/**
+	* 任务ID
+	*/
+		private Long taskId;
+	/**
+	* 档案案卷ID
+	*/
+		private Long archiveAutoId;
+	/**
+	* 档案案卷题目
+	*/
+		private String archiveName;
+	/**
+	* 档案案卷题目AI
+	*/
+		private String archiveNameAi;
+
+
+}

+ 2 - 0
blade-service-api/blade-archive-api/src/main/java/org/springblade/archive/entity/ArchivesAuto.java

@@ -186,6 +186,8 @@ public class ArchivesAuto extends BaseEntity {
     @ApiModelProperty("是否解析,其他=未解析 1=已解析")
     private Integer splitStatus;
 
+    @ApiModelProperty("颜色状态")
+    private Integer colourStatus;
     //是否是影音
     public boolean isMedia() {
         return (this.getCarrierType() != null &&

+ 9 - 0
blade-service-api/blade-archive-api/src/main/java/org/springblade/archive/trans/ArchiveFileVo.java

@@ -48,6 +48,7 @@ public class ArchiveFileVo {
     private Integer width;
     private Integer height;
     private String isArchive;
+    private Integer sort;
 
     public String getId() {
         return id;
@@ -400,4 +401,12 @@ public class ArchiveFileVo {
     public void setIsArchive(String isArchive) {
         this.isArchive = isArchive;
     }
+
+    public Integer getSort() {
+        return sort;
+    }
+
+    public void setSort(Integer sort) {
+        this.sort = sort;
+    }
 }

+ 11 - 0
blade-service-api/blade-archive-api/src/main/java/org/springblade/archive/vo/ArchiveAiNameVO.java

@@ -0,0 +1,11 @@
+package org.springblade.archive.vo;
+
+import lombok.Data;
+
+@Data
+public class ArchiveAiNameVO {
+    private Long taskId;
+    private String taskTime;
+    private Integer status;
+    private Integer num;
+}

+ 12 - 0
blade-service-api/blade-archive-api/src/main/java/org/springblade/archive/vo/ArchiveAiNameVO1.java

@@ -0,0 +1,12 @@
+package org.springblade.archive.vo;
+
+import lombok.Data;
+
+@Data
+public class ArchiveAiNameVO1 {
+    private Long id;
+    private Long archiveAutoId;
+    private String archiveNameAi;
+    private Integer status;
+    private Long taskId;
+}

+ 34 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/TrialAutoNumberDTO.java

@@ -0,0 +1,34 @@
+/*
+ *      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.business.dto;
+
+import org.springblade.business.entity.TrialAutoNumber;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 数据传输对象实体类
+ *
+ * @author BladeX
+ * @since 2025-06-10
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class TrialAutoNumberDTO extends TrialAutoNumber {
+	private static final long serialVersionUID = 1L;
+
+}

+ 6 - 3
blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/TrialMaterialMobilizationDTO.java

@@ -20,10 +20,13 @@ import java.util.Date;
 public class TrialMaterialMobilizationDTO extends TrialMaterialMobilization {
     private static final long serialVersionUID = 1L;
 
-    /**
-     * 数据序号
-     */
     @ApiModelProperty("数据序号")
     private Integer dataNumber;
 
+    @ApiModelProperty("旧编号")
+    private String trialNumber;
+
+    @ApiModelProperty("自增流水号")
+    private String autoIncrementNumber;
+
 }

+ 37 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/TrialNumberRuleDTO.java

@@ -0,0 +1,37 @@
+/*
+ *      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.business.dto;
+
+import org.springblade.business.entity.TrialNumberRule;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 数据传输对象实体类
+ *
+ * @author BladeX
+ * @since 2025-06-10
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class TrialNumberRuleDTO extends TrialNumberRule {
+	private static final long serialVersionUID = 1L;
+
+    private Long nodeId;
+
+
+}

+ 6 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/TrialSampleInfoDTO.java

@@ -21,5 +21,11 @@ public class TrialSampleInfoDTO extends TrialSampleInfo {
     @ApiModelProperty("数据序号")
     private Integer dataNumber;
 
+    @ApiModelProperty("旧编号")
+    private String trialNumber;
+
+    @ApiModelProperty("自增流水号")
+    private String autoIncrementNumber;
+
 
 }

+ 11 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/TrialSelfInspectionRecordDTO.java

@@ -29,4 +29,15 @@ public class TrialSelfInspectionRecordDTO extends TrialSelfInspectionRecord {
     @ApiModelProperty(value = "是否批量保存 0=单保存,1=批量保存")
     private Integer isBatchSave;
 
+    @ApiModelProperty(value = "记录表自增流水号")
+    private String recordAutoNumber;
+
+    @ApiModelProperty(value = "报告单自增流水号")
+    private String reportAutoNumber;
+
+    @ApiModelProperty(value = "旧记录编号")
+    private String oldRecordNumber;
+    @ApiModelProperty(value = "旧报告编号")
+    private String oldReportNumber;
+
 }

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

@@ -280,6 +280,9 @@ public class ArchiveFile extends BaseEntity {
     @ApiModelProperty("卷内索引")
     private Integer fid;
 
+    @ApiModelProperty("卷内排序")
+    private Integer archiveSort;
+
     //整改情况,0,无整改,1 待整改,2 已整改
     @ApiModelProperty("整改情况")
     private Integer rectification;
@@ -391,6 +394,10 @@ public class ArchiveFile extends BaseEntity {
         }
 
         this.setSort(vo.getOrderNum());
+        //设置了专门排序的就设置
+        if (vo.getSort()!= null) {
+            this.setSort(vo.getSort());
+        }
 
 
         String type = vo.getType();

+ 58 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/TrialAutoNumber.java

@@ -0,0 +1,58 @@
+/*
+ *      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.business.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import org.springblade.core.mp.base.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 实体类
+ *
+ * @author BladeX
+ * @since 2025-06-10
+ */
+@Data
+@TableName("u_trial_auto_number")
+@EqualsAndHashCode(callSuper = true)
+public class TrialAutoNumber extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	* 自增的流水号
+	*/
+		private String autoIncrementNumber;
+
+		private Long contractId;
+	/**
+	* 来源主表的主键ID
+	*/
+		private Long formDataId;
+	/**
+	* 1材料 2样品 3委托单 4记录表 5报告表
+	*/
+		private Integer type;
+    /**
+     * 试验编号规则ID
+      */
+        private Long numberRuleId;
+
+
+}

+ 77 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/TrialNumberRule.java

@@ -0,0 +1,77 @@
+/*
+ *      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.business.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+
+import io.swagger.annotations.ApiModelProperty;
+import org.springblade.core.mp.base.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 实体类
+ *
+ * @author BladeX
+ * @since 2025-06-10
+ */
+@Data
+@TableName("u_trial_number_rule")
+@EqualsAndHashCode(callSuper = true)
+public class TrialNumberRule extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	* 项目ID
+	*/
+    @ApiModelProperty("项目ID")
+		private Long projectId;
+	/**
+	* 合同段ID
+	*/
+    @ApiModelProperty("合同段ID")
+		private Long contractId;
+	/**
+	* 编号规则 1材料 2样品 3委托单 4记录表 5报告表
+	*/
+    @ApiModelProperty("编号规则 1材料 2样品 3委托单 4记录表 5报告表")
+		private Integer type;
+	/**
+	* 编号规则
+	*/
+    @ApiModelProperty("编号规则")
+		private Integer rule;
+	/**
+	* 数据填充
+	*/
+    @ApiModelProperty("数据填充")
+		private String data;
+	/**
+	* 是否自增
+	*/
+    @ApiModelProperty("是否自增0否1是")
+		private Integer isAutoIncrement;
+    /**
+     * 排序
+      */
+    @ApiModelProperty("排序")
+        private Integer sort;
+
+
+}

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

@@ -164,4 +164,7 @@ public interface ArchiveFileClient {
 
     @PostMapping(API_PREFIX + "/saveArchiveFileByBIM")
     void saveArchiveFileByBIM(@RequestBody ArchiveFile archiveFile);
+
+    @PostMapping(API_PREFIX + "/getArchiveFileByArchiveIds")
+    List<ArchiveFile> getArchiveFileByArchiveIds(@RequestParam String archiveIds);
 }

+ 1 - 1
blade-service-api/blade-business-api/src/main/java/org/springblade/business/feign/InformationQueryClient.java

@@ -97,7 +97,7 @@ public interface InformationQueryClient {
     void insert(@RequestBody InformationQuery iq);
 
     @PostMapping(API_PREFIX+"/getInfoByWbsId")
-    InformationQuery getInfoByWbsId(@RequestParam Long wbsId);
+    InformationQuery getInfoByWbsId(@RequestParam Long wbsId,@RequestParam Integer classify);
 
     @PostMapping(API_PREFIX+"/updateInformationQuery1")
     void update(@RequestBody  InformationQuery iq);

+ 5 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/ArchiveFileVO.java

@@ -97,4 +97,9 @@ public class ArchiveFileVO extends ArchiveFile {
     private String archiveName;
 
     private Integer extType;
+
+    /**
+     * 是否已组卷
+     */
+    private Integer isArchive;
 }

+ 34 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/TrialAutoNumberVO.java

@@ -0,0 +1,34 @@
+/*
+ *      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.business.vo;
+
+import org.springblade.business.entity.TrialAutoNumber;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 视图实体类
+ *
+ * @author BladeX
+ * @since 2025-06-10
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class TrialAutoNumberVO extends TrialAutoNumber {
+	private static final long serialVersionUID = 1L;
+
+}

+ 36 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/TrialNumberRuleVO.java

@@ -0,0 +1,36 @@
+/*
+ *      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.business.vo;
+
+import org.springblade.business.entity.TrialNumberRule;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 视图实体类
+ *
+ * @author BladeX
+ * @since 2025-06-10
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class TrialNumberRuleVO extends TrialNumberRule {
+	private static final long serialVersionUID = 1L;
+
+    private String trialNumber;
+
+}

+ 17 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/vo/TrialNumberRuleVO1.java

@@ -0,0 +1,17 @@
+package org.springblade.business.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springblade.business.entity.TrialNumberRule;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TrialNumberRuleVO1 {
+    private List<TrialNumberRule> list=new ArrayList<>();
+    private String trialNumber;
+}

+ 16 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/dto/AddBussFileSortDTO.java

@@ -0,0 +1,16 @@
+package org.springblade.manager.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class AddBussFileSortDTO {
+    private String[] list;
+    private Integer classify;
+    private Long contractId;
+    private String id;
+    private Integer type;
+}

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

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

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

@@ -325,6 +325,9 @@ public class WbsTreeContract extends BaseEntity {
     @JsonProperty(value = "treePId")
     private Long treePId;
 
+    @ApiModelProperty(value = "是否完成日期填写 1是 2否")
+    private Integer dateIsComplete;
+
 
 
 }

+ 9 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/feign/ExcelTabClient.java

@@ -58,6 +58,15 @@ public interface ExcelTabClient {
                  @RequestParam String projectId,
                  @RequestHeader("Blade-Auth") String header) throws Exception;
 
+
+
+    @PostMapping(API_PREFIX + "/synPdfKeyInfo")
+    R synPdfKeyInfo(@RequestParam String contractId,
+                 @RequestParam String nodeIds,
+                 @RequestParam String classify,
+                 @RequestParam String projectId,
+                 @RequestHeader("Blade-Auth") String header) throws Exception;
+
     @PostMapping(API_PREFIX + "/getArchiveTabList")
     List<ExcelTab> getArchiveTabList();
 

+ 5 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/feign/ExcelTabClientFallBack.java

@@ -51,6 +51,11 @@ public class ExcelTabClientFallBack implements ExcelTabClient {
         return null;
     }
 
+    @Override
+    public R synPdfKeyInfo(String contractId, String nodeIds, String classify, String projectId, String header) throws Exception {
+        return null;
+    }
+
     @Override
     public List<ExcelTab> getArchiveTabList(){
         return null;

+ 10 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/CurrentNode.java

@@ -1,7 +1,9 @@
 package org.springblade.manager.vo;
 
+import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
 import org.springblade.manager.entity.WbsTreePrivate;
+import org.springframework.format.annotation.DateTimeFormat;
 
 import java.time.LocalDate;
 import java.time.LocalDateTime;
@@ -37,6 +39,14 @@ public class CurrentNode {
     private Long wbsNodeId;
     /**节点类型*/
     private Integer nodeType;
+    /**节点排序*/
+    private Integer sort;
+    /**节点名称*/
+    private String title;
+    /**创建时间*/
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime  createTime;
     /**treeCode*/
     private List<String> treeCode =new ArrayList<>();
     /**

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

@@ -60,17 +60,24 @@ public abstract class EvaSummary<T> {
                     ));
 
             int index=1;
+            int pageSizex=0;
             for (Map.Entry<Integer, List<T>> entry : pages.entrySet()) {
                 /*每一页就是一条插入记录*/
                 int k = entry.getKey();
+
                 if (wtcList.size() <= k) {
                     break;
                 }
                 List<T> v = entry.getValue();
                 /*是否是最后一页,fb02最后一页汇总用到*/
                 boolean isLast=index==pages.size();
+                // 算出 每页大小
+                if(pageSizex<=0){
+                    pageSizex = v.size();
+                }
                 index++;
-                List<Object> l=this.fds.stream().map(fd->putEd(k,v,fd,datas,isLast)).collect(Collectors.toList());
+                int finalPageSizex = pageSizex;
+                List<Object> l=this.fds.stream().map(fd->putEd(finalPageSizex,k,v,fd,datas,isLast)).collect(Collectors.toList());
                 l.add(wtcList.get(k).getPKeyId());
                 params.add(l.toArray());
             }
@@ -79,8 +86,8 @@ public abstract class EvaSummary<T> {
         return false;
     }
 
-    /**把数据放到对应元素*/
-    private String putEd(int pn, List<T> items, FormData fd,List<T>datas,boolean isLastPage){
+    /**把数据放到对应元素(一页一行的添加)*/
+    private String putEd(int pageSize,int pn, List<T> items, FormData fd,List<T>datas,boolean isLastPage){
         BiFunction<List<T>,Integer,List<Object>> fc = this.fm.get(fd.getCode());
         if(fc!=null) {
             List<Object> data ;
@@ -93,7 +100,7 @@ public abstract class EvaSummary<T> {
                     data=Collections.singletonList("");
                 }
             }else {
-                data  = fc.apply(items,pn);
+                data  = fc.apply(items,pn*pageSize);
             }
             for (int i = 0; i < data.size(); i++) {
                 Coords c = fd.getCoordsList().get(i);

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

@@ -6,9 +6,13 @@ import lombok.EqualsAndHashCode;
 import org.apache.commons.lang.StringUtils;
 import org.springblade.common.utils.BaseUtils;
 import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.IoUtil;
 import org.springblade.manager.dto.FormData;
 import org.springblade.manager.entity.FormulaDataBlock;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.util.*;
@@ -56,7 +60,7 @@ public class FB02 extends EvaSummary<Item02>{
                   this.fm.put(fd.getCode(),(List<Item02> l,Integer pn)->l.stream().map(Item02::getSubItem).collect(Collectors.toList()));
               }else if(fd.getEName().contains("序号")){
                   this.sn=fd;
-                  this.fm.put(fd.getCode(),(List<Item02> l,Integer pn)->IntStream.range(0, l.size()).boxed().map(i->i+pn*l.size()+1).collect(Collectors.toList()));
+                  this.fm.put(fd.getCode(),(List<Item02> l,Integer pn)->IntStream.range(0, l.size()).boxed().map(i->i+pn+1).collect(Collectors.toList()));
               }else if(fd.getEName().contains("实测项目")){
                   this.name=fd;
                   this.fm.put(fd.getCode(),(List<Item02> l,Integer pn)->l.stream().map(Item02::getName).collect(Collectors.toList()));

+ 8 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/vo/WbsTreeContractLazyVO.java

@@ -19,6 +19,9 @@ public class WbsTreeContractLazyVO implements Serializable {
     @JsonProperty(value = "pKeyId")
     private Long pKeyId;
 
+    @ApiModelProperty("pkeyId的节点父级id")
+    private Long pId;
+
     @ApiModelProperty("节点主键pKeyId别名,其他接口要用")
     private Long primaryKeyId;
 
@@ -133,4 +136,9 @@ public class WbsTreeContractLazyVO implements Serializable {
     @ApiModelProperty(value = "关联后管节点ID")
     private Long isTypePrivatePid;
 
+    @ApiModelProperty(value = "是否完成日期填写1是2否")
+    private Integer dateIsComplete;
+
+
+
 }

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

@@ -19,6 +19,7 @@ public class WtcEva {
     private String treeCode;
     private Long parentId;
     private Long pKeyId;
+    private Long pId;//pkeyid 的父级 id
     public boolean isEva(){
       return Objects.requireNonNull(this.nodeName, "nodeName不能为空").contains("评定");
   }

+ 1 - 0
blade-service-api/blade-user-api/src/main/java/org/springblade/system/user/vo/InformationQueryBIMVO.java

@@ -11,6 +11,7 @@ public class InformationQueryBIMVO {
 
     @TableField("id")
     private String id;
+
     @TableField("父级id")
     private String parentId;
 

+ 155 - 0
blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchiveAiNameController.java

@@ -0,0 +1,155 @@
+/*
+ *      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.archive.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import lombok.AllArgsConstructor;
+import javax.validation.Valid;
+
+import org.springblade.archive.vo.ArchiveAiNameVO;
+import org.springblade.archive.vo.ArchiveAiNameVO1;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.Func;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.RequestParam;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springblade.archive.entity.ArchiveAiName;
+import org.springblade.archive.service.IArchiveAiNameService;
+import org.springblade.core.boot.ctrl.BladeController;
+
+import java.util.List;
+
+/**
+ *  控制器
+ *
+ * @author BladeX
+ * @since 2025-07-03
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/archiveainame")
+@Api(value = "", tags = "接口")
+public class ArchiveAiNameController extends BladeController {
+
+	private final IArchiveAiNameService archiveAiNameService;
+
+	/**
+	 * 详情
+	 */
+	@GetMapping("/detail")
+	@ApiOperationSupport(order = 1)
+	@ApiOperation(value = "详情", notes = "传入archiveAiName")
+	public R<ArchiveAiName> detail(ArchiveAiName archiveAiName) {
+		ArchiveAiName detail = archiveAiNameService.getOne(Condition.getQueryWrapper(archiveAiName));
+		return R.data(detail);
+	}
+
+	@GetMapping("/getArchiveAiTask")
+	@ApiOperationSupport(order = 2)
+	@ApiOperation(value = "获取AI任务", notes = "获取AI任务")
+	public R<List<ArchiveAiNameVO>>getArchiveAiTask(Long projectId, Long contractId){
+		return R.data(archiveAiNameService.getArchiveAiTask(projectId,contractId));
+	}
+
+	@GetMapping("/deletedArchiveAiTask")
+	@ApiOperationSupport(order = 3)
+	@ApiOperation(value = "删除AI任务", notes = "删除AI任务")
+	public R deletedArchiveAiTask(Long taskId){
+		return R.status(archiveAiNameService.deletedArchiveAiTask(taskId));
+	}
+	@GetMapping("/page")
+	@ApiOperationSupport(order = 2)
+	@ApiOperation(value = "分页")
+	public R<IPage<ArchiveAiName>>page(Long taskId,Long projectId,Long contractId,Query query){
+		if(taskId!=null){
+			IPage<ArchiveAiName> pages = archiveAiNameService.page(Condition.getPage(query), new LambdaQueryWrapper<>(ArchiveAiName.class).eq(ArchiveAiName::getTaskId,taskId).eq(ArchiveAiName::getStatus,2));
+			return R.data(pages);
+		}else {
+			IPage<ArchiveAiName> pages = archiveAiNameService.page(Condition.getPage(query), new LambdaQueryWrapper<>(ArchiveAiName.class).eq(ArchiveAiName::getProjectId,projectId).eq(ArchiveAiName::getContractId,contractId).eq(ArchiveAiName::getStatus,2));
+			return R.data(pages);
+		}
+	}
+
+	@PostMapping("/confirmAiName")
+	@ApiOperationSupport(order = 3)
+	@ApiOperation(value = "确认AI名称", notes = "确认AI名称")
+	public R confirmAiName(@RequestBody List<ArchiveAiNameVO1>list){
+		return R.status(archiveAiNameService.confirmAiName(list));
+	}
+
+//	/**
+//	 * 分页
+//	 */
+//	@GetMapping("/list")
+//	@ApiOperationSupport(order = 2)
+//	@ApiOperation(value = "分页", notes = "传入archiveAiName")
+//	public R<IPage<ArchiveAiName>> list(ArchiveAiName archiveAiName, Query query) {
+//		IPage<ArchiveAiName> pages = archiveAiNameService.page(Condition.getPage(query), Condition.getQueryWrapper(archiveAiName));
+//		return R.data(pages);
+//	}
+
+//
+//
+//	/**
+//	 * 新增
+//	 */
+//	@PostMapping("/save")
+//	@ApiOperationSupport(order = 4)
+//	@ApiOperation(value = "新增", notes = "传入archiveAiName")
+//	public R save(@Valid @RequestBody ArchiveAiName archiveAiName) {
+//		return R.status(archiveAiNameService.save(archiveAiName));
+//	}
+//
+//	/**
+//	 * 修改
+//	 */
+//	@PostMapping("/update")
+//	@ApiOperationSupport(order = 5)
+//	@ApiOperation(value = "修改", notes = "传入archiveAiName")
+//	public R update(@Valid @RequestBody ArchiveAiName archiveAiName) {
+//		return R.status(archiveAiNameService.updateById(archiveAiName));
+//	}
+//
+//	/**
+//	 * 新增或修改
+//	 */
+//	@PostMapping("/submit")
+//	@ApiOperationSupport(order = 6)
+//	@ApiOperation(value = "新增或修改", notes = "传入archiveAiName")
+//	public R submit(@Valid @RequestBody ArchiveAiName archiveAiName) {
+//		return R.status(archiveAiNameService.saveOrUpdate(archiveAiName));
+//	}
+//
+//
+//	/**
+//	 * 删除
+//	 */
+//	@PostMapping("/remove")
+//	@ApiOperationSupport(order = 7)
+//	@ApiOperation(value = "逻辑删除", notes = "传入ids")
+//	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+//		return R.status(archiveAiNameService.deleteLogic(Func.toLongList(ids)));
+//	}
+
+	
+}

+ 53 - 21
blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchivesAutoController.java

@@ -16,16 +16,13 @@
  */
 package org.springblade.archive.controller;
 
-import cn.hutool.core.text.split.SplitIter;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
-import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import io.swagger.annotations.*;
 import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
 import lombok.AllArgsConstructor;
 
 import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 
@@ -41,12 +38,10 @@ import org.springblade.archive.entity.ExpertInspection;
 import org.springblade.archive.service.IArchiveAutoPdfService;
 import org.springblade.archive.service.ITraceLogService;
 import org.springblade.archive.utils.CallBgrsjk;
-import org.springblade.archive.utils.FileUtils;
 import org.springblade.archive.vo.*;
 import org.springblade.business.entity.ArchiveFile;
-import org.springblade.business.entity.InformationQuery;
-import org.springblade.common.constant.CommonConstant;
-import org.springblade.common.utils.CommonUtil;
+import org.springblade.business.feign.ArchiveFileClient;
+import org.springblade.common.utils.DeepSeekClient;
 import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.core.mp.support.Condition;
 import org.springblade.core.mp.support.Query;
@@ -55,16 +50,12 @@ 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.ContractInfo;
-import org.springblade.manager.entity.ExcelEditCallback;
-import org.springblade.manager.entity.ProjectInfo;
 import org.springblade.manager.feign.ArchiveTreeContractClient;
 import org.springblade.manager.feign.ContractClient;
 import org.springblade.manager.feign.ProjectClient;
-import org.springblade.manager.vo.MyInspectTreeVO;
-import org.springblade.system.cache.ParamCache;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.MediaType;
 import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.RequestParam;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -74,12 +65,8 @@ import org.springblade.archive.service.IArchivesAutoService;
 import org.springblade.core.boot.ctrl.BladeController;
 import org.springframework.web.multipart.MultipartFile;
 
-import java.io.File;
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.concurrent.ExecutorService;
 import java.util.stream.Collectors;
 
@@ -108,8 +95,11 @@ public class ArchivesAutoController extends BladeController {
 	private ExecutorService executorService;
 	@Autowired
 	private ITraceLogService iTraceLogService;
-
     private final JdbcTemplate jdbcTemplate;
+    @Autowired
+    private ArchiveFileClient archiveFileClient;
+
+
 	/**
 	 * 详情
 	 */
@@ -159,15 +149,15 @@ public class ArchivesAutoController extends BladeController {
     @GetMapping("/fileNumberFlush")
     @ApiOperationSupport(order = 4)
     @ApiOperation(value = "档号整理——按档号排序")
-    public R fileNumberFlush(Long projectId,Long contractId,String nodeId,Integer isArchive){
+    public R fileNumberFlush(Long projectId,Long contractId,String nodeId,Integer isArchive,Integer startNumber){
         List<ArchiveTreeContract> archiveTreeContracts = this.archiveTreeContractClient.queryAllChildByAncestors(nodeId,contractId);
         List<String> ids = new ArrayList<>();
         if(archiveTreeContracts != null && archiveTreeContracts.size() > 0){
             ids=JSONArray.parseArray(JSONObject.toJSONString(archiveTreeContracts.stream().map(ArchiveTreeContract::getId).distinct().collect(Collectors.toList())), String.class);
         }
         ids.add(nodeId);
-        archivesAutoService.fileNumberFlush(projectId,contractId,ids,isArchive);
-        return R.success("正在重置题名中,请稍后刷新");
+        archivesAutoService.fileNumberFlush(projectId,contractId,ids,isArchive,startNumber);
+        return R.success("正在刷新档号中,请稍后刷新");
     }
 
 
@@ -513,6 +503,48 @@ public class ArchivesAutoController extends BladeController {
 		}
 
 	}
+	@PostMapping("/reCreateArchiveAuto")
+	@ApiOperationSupport(order = 13)
+	@ApiOperation(value = "重新生成案卷", notes = "传入ids")
+	@Transactional
+	public R reCreateArchiveAuto(@ApiParam(value = "主键集合", required = true) @RequestParam String ids,@ApiParam(value = "合并后的文件题目", required = true)String name){
+		//先查出勾选的案卷
+		List<ArchivesAuto> archivesAutoList=archivesAutoService.listByIds(Func.toLongList(ids));
+		if(archivesAutoList.size()<=1){
+			return R.fail("请选择多个案卷进行合并");
+		}
+		archivesAutoList.sort(Comparator.comparingInt(a -> {
+			String[] parts = a.getFileNumber().split("_");
+			return Integer.parseInt(parts[parts.length - 1]); // 取最后一个部分作为数字
+		}));
+		//根据档号后缀排序 拿到第一个
+		ArchivesAuto auto = archivesAutoList.get(0);
+		//查出所有案卷文件
+		List<ArchiveFile>archiveFileList=archiveFileClient.getArchiveFileByArchiveIds(ids);
+		//将除第一个以外的案卷文件archiveId 设置成第一个的id
+		List<ArchiveFile>updateArchiveFileList=new ArrayList<>();
+		for (ArchiveFile file : archiveFileList) {
+			if (!file.getArchiveId().equals(auto.getId())) {
+				file.setArchiveId(auto.getId());
+				updateArchiveFileList.add(file);
+			}
+		}
+		archiveFileClient.updateArchiveFile(updateArchiveFileList);
+		auto.setName(name);
+		//删除其他案卷
+		archivesAutoList.remove(auto);
+		archivesAutoService.deleteLogic(archivesAutoList.stream().map(o->o.getId()).collect(Collectors.toList()));
+		//设置案卷页码和四要素
+		archivesAutoService.reCreateArchiveAuto(auto, archiveFileList);
+		return R.status(true);
+	}
+
+	@PostMapping("/creatFileNameFormAI")
+	@ApiOperationSupport(order = 10)
+	@ApiOperation(value = "案卷ai题名", notes = "传入ids")
+	public R creatFileNameFormAI(String ids,Long projectId,Long contractId) throws IOException {
+		return R.status(archivesAutoService.creatFileNameFormAI(ids,projectId,contractId));
+	}
 
 	/**
 	 * 预览案卷文件

+ 33 - 13
blade-service/blade-archive/src/main/java/org/springblade/archive/external/impl/ExternalDataArchiveFileService.java

@@ -40,7 +40,7 @@ public class ExternalDataArchiveFileService {
         List<ArchiveFile> upFiles = new ArrayList<>();
 
         //外部文件
-        List<ArchiveFile> externalFiles = listConvert(req.getNodeId(), req.getFiles(), externalDataInfo);
+        List<ArchiveFile> externalFiles = listConvert(req.getNodeId(), req.getFiles(), externalDataInfo,req.getTransType());
 
         List<String> outIds = Optional.ofNullable(externalFiles)
                 .orElseGet(Collections::emptyList)
@@ -55,13 +55,13 @@ public class ExternalDataArchiveFileService {
         //把本地的也加进去,一般用不到作为冗余手段
         updateFileMapping(externalDataInfo,localFiles);
         //比较获取
-        getAddAndUpdateFiles(externalDataInfo,externalFiles, localFiles, addFiles, upFiles);
+        getAddAndUpdateFiles(externalDataInfo,externalFiles, localFiles, addFiles, upFiles,req);
 
         //保存
         addAndUpdateFiles(addFiles,upFiles);
     }
 
-    public List<ArchiveFile> listConvert(String nodeId, List<ArchiveFileVo> archiveFileVos, ExternalDataInfo externalDataInfo) {
+    public List<ArchiveFile> listConvert(String nodeId, List<ArchiveFileVo> archiveFileVos, ExternalDataInfo externalDataInfo,Integer transType) {
 
         List<ArchiveFile> archiveFiles = new ArrayList<>();
         Map<String, Long> archiveFileOutIdMapping = new LinkedHashMap<>();
@@ -84,9 +84,14 @@ public class ExternalDataArchiveFileService {
 
             ArchiveFile archiveFile = new ArchiveFile();
 
-            // 拷贝属性
+            //
             archiveFile.fromExternal(archiveFileVo);
 
+            //模式1,只传递未组卷得案卷
+            if (transType != null && transType == 1) {
+                archiveFile.setIsArchive(0);
+            }
+
             // 设置新ID(从映射表中获取)
             Long newNodeId = archiveFileOutIdMapping.get(archiveFileVo.getId());
             archiveFile.setId(newNodeId);
@@ -127,7 +132,7 @@ public class ExternalDataArchiveFileService {
             List<ArchiveFile> externalFiles,
             List<ArchiveFile> localFiles,
             List<ArchiveFile> addFiles,
-            List<ArchiveFile> upFiles) {
+            List<ArchiveFile> upFiles,ArchiveReq req) {
 
         // 1. 提取本地文件的 outId 集合(用于快速判断外部文件是否已存在)
         Set<String> localOutIdSet = localFiles.stream()
@@ -155,7 +160,7 @@ public class ExternalDataArchiveFileService {
             } else {
                 // 存在则查找本地对应文件,判断是否需要更新
                 ArchiveFile localFile = localFileMap.get(externalOutId);
-                if (localFile != null && needUpdate(externalFile, localFile)) {
+                if (localFile != null && needUpdate(externalFile, localFile,req)) {
                     updateLocalFile(localFile, externalFile); // 更新字段
                     upFiles.add(localFile);
                 }
@@ -164,15 +169,30 @@ public class ExternalDataArchiveFileService {
     }
 
     // 辅助方法:判断是否需要更新
-    private boolean needUpdate(ArchiveFile external, ArchiveFile local) {
-        String extUtimeStr = formatTime(external.getUtime());
-        String localUtimeStr = formatTime(local.getUtime());
+// 辅助方法:判断是否需要更新
+    private boolean needUpdate(ArchiveFile external, ArchiveFile local, ArchiveReq req) {
+        // 处理 transType == 1 的情况
+        if (req.getTransType() != null && req.getTransType() == 1) {
+            // 比较 fileTime(避免空指针)和 sort 字段
+            String extFileTime = external.getFileTime();
+            String localFileTime = local.getFileTime();
+            boolean fileTimeDifferent = !Objects.equals(extFileTime, localFileTime);
+
+            boolean sortDifferent = !Objects.equals(external.getSort(), local.getSort());
+
+            return fileTimeDifferent || sortDifferent;
+        }
+        // 处理 transType == 0 和其他情况(默认逻辑)
+        else {
+            String extUtimeStr = formatTime(external.getUtime());
+            String localUtimeStr = formatTime(local.getUtime());
 
-        // 字符串严格比较:格式或内容不同即视为不一致
-        return !Objects.equals(extUtimeStr, localUtimeStr)
-                || !Objects.equals(external.getPdfPageUrl(), local.getPdfPageUrl());
-                //|| !Objects.equals(external.getArchiveId(), local.getArchiveId());
+            // 确保 external.getPdfPageUrl() 非空才比较(external有值)
+            boolean pdfUrlDifferent = external.getPdfPageUrl() != null &&
+                    !Objects.equals(external.getPdfPageUrl(), local.getPdfPageUrl());
 
+            return !Objects.equals(extUtimeStr, localUtimeStr) || pdfUrlDifferent;
+        }
     }
 
     /**

+ 44 - 0
blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/ArchiveAiNameMapper.java

@@ -0,0 +1,44 @@
+/*
+ *      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.archive.mapper;
+
+import io.lettuce.core.dynamic.annotation.Param;
+import org.springblade.archive.entity.ArchiveAiName;
+import org.springblade.archive.vo.ArchiveAiNameVO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import java.util.List;
+
+/**
+ *  Mapper 接口
+ *
+ * @author BladeX
+ * @since 2025-07-03
+ */
+public interface ArchiveAiNameMapper extends BaseMapper<ArchiveAiName> {
+
+	/**
+	 * 自定义分页
+	 *
+	 * @param page
+	 * @param archiveAiName
+	 * @return
+	 */
+	List<ArchiveAiNameVO> selectArchiveAiNamePage(IPage page, ArchiveAiNameVO archiveAiName);
+
+    boolean deletedArchiveAiTask(@Param("taskId") Long taskId);
+}

+ 32 - 0
blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/ArchiveAiNameMapper.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.archive.mapper.ArchiveAiNameMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="archiveAiNameResultMap" type="org.springblade.archive.entity.ArchiveAiName">
+        <result column="id" property="id"/>
+        <result column="create_user" property="createUser"/>
+        <result column="create_dept" property="createDept"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_user" property="updateUser"/>
+        <result column="update_time" property="updateTime"/>
+        <result column="status" property="status"/>
+        <result column="is_deleted" property="isDeleted"/>
+        <result column="project_id" property="projectId"/>
+        <result column="contract_id" property="contractId"/>
+        <result column="task_id" property="taskId"/>
+        <result column="archive_auto_id" property="archiveAutoId"/>
+        <result column="archive_name" property="archiveName"/>
+        <result column="archive_name_ai" property="archiveNameAi"/>
+    </resultMap>
+    <update id="deletedArchiveAiTask">
+        update  u_archive_ai_name set is_deleted=1 where task_id=#{taskId}
+
+    </update>
+
+
+    <select id="selectArchiveAiNamePage" resultMap="archiveAiNameResultMap">
+        select * from u_archive_ai_name where is_deleted = 0
+    </select>
+
+</mapper>

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

@@ -229,4 +229,6 @@ public interface ArchivesAutoMapper extends BaseMapper<ArchivesAuto> {
 
     List<ArchivesAutoVO4> selectAllArchiveAuto(@Param("projectId")Long projectId, @Param("contractId") Long contractId, @Param("nodeIds") List<String> nodeIds,@Param("isArchive")Integer isArchive);
 
+
+
 }

+ 4 - 1
blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/ArchivesAutoMapper.xml

@@ -49,6 +49,7 @@
         <result column="filing_unit" property="filingUnit"/>
         <result column="file_size" property="fileSize"/>
         <result column="is_reviewed" property="isReviewed"/>
+        <result column="colour_status" property="colourStatus"/>
     </resultMap>
 <!-- 带文件子查询的-->
     <resultMap id="archivesAutoResultMap2" type="org.springblade.archive.vo.ArchivesAutoVO">
@@ -216,6 +217,7 @@
         <result column="sort_num" property="sortNum"/>
     </resultMap>
 
+
     <select id="approvalFile" resultType="org.springblade.archive.vo.ArchivesAutoVO$ApprovalFile">
         <if test="archiveId!=null">
             select * from u_archive_file where archive_id = #{archiveId} order by sort
@@ -1432,6 +1434,7 @@
         <foreach collection="nodeIds" item="nodeId" open="(" separator="," close=")">
             #{nodeId}
         </foreach>
-        ORDER BY uaa.auto_file_sort Asc
+        order by uatc.tree_sort,uaa.auto_file_sort is null ,uaa.auto_file_sort,uaa.file_number is null,
+        SUBSTRING_INDEX(uaa.file_number, '_', 1), SUBSTRING_INDEX(uaa.file_number, '_', -1) + 0 ,uaa.create_time asc
     </select>
 </mapper>

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

@@ -45,4 +45,6 @@ public interface TaskSplitMapper extends BaseMapper<TaskSplit> {
 
 	// 获取分解任务是否存在
 	Integer getSpliteTaskCount(String contractId);
+
+	//Integer updateArchiveByIds(String contractId,);
 }

+ 9 - 1
blade-service/blade-archive/src/main/java/org/springblade/archive/mapper/TaskSplitMapper.xml

@@ -27,11 +27,19 @@
     </select>
 
     <select id="getArchiveCount" resultType="java.lang.Integer">
-        select count(1) from u_archives_auto where contract_id = #{contractId}
+        select count(1) from u_archives_auto where contract_id = #{contractId} and is_deleted = 0
     </select>
 
     <select id="getSpliteTaskCount" resultType="java.lang.Integer">
         select count(1) from u_task_split where contract_id = #{contractId} and type=2
     </select>
 
+<!--    <update id="updateArchiveByIds">
+        update u_archives_auto set status = 1 where contract_id = #{contractId} and id in
+        <foreach item="item" collection="ids" separator="," close=")" open="(" index="index">
+            #{item}
+        </foreach>
+    </update>-->
+
+
 </mapper>

+ 45 - 0
blade-service/blade-archive/src/main/java/org/springblade/archive/service/IArchiveAiNameService.java

@@ -0,0 +1,45 @@
+/*
+ *      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.archive.service;
+
+import org.springblade.archive.entity.ArchiveAiName;
+import org.springblade.archive.vo.ArchiveAiNameVO;
+import org.springblade.archive.vo.ArchiveAiNameVO1;
+import org.springblade.core.mp.base.BaseService;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ *  服务类
+ *
+ * @author BladeX
+ * @since 2025-07-03
+ */
+public interface IArchiveAiNameService extends BaseService<ArchiveAiName> {
+
+
+
+    void syncCreatAiName(List<ArchiveAiName> aiNames) throws IOException;
+
+    List<ArchiveAiNameVO> getArchiveAiTask(Long projectId, Long contractId);
+
+    boolean confirmAiName(List<ArchiveAiNameVO1>vos);
+
+    Boolean deletedArchiveAiTask(Long taskId);
+}

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

@@ -60,6 +60,6 @@ public interface IArchiveNameService {
      */
     String generateFullLevelName(
             List<Long> nodeList,
-            NodeHierarchy hierarchy
+            NodeHierarchy hierarchy,boolean useCovering
     );
 }

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

@@ -26,6 +26,7 @@ import org.springblade.archive.entity.ArchivesAuto;
 import org.springblade.archive.entity.ExpertInspection;
 import org.springblade.archive.entity.JiLinArchiveAutoDto;
 import org.springblade.archive.vo.*;
+import org.springblade.business.entity.ArchiveFile;
 import org.springblade.core.mp.base.BaseService;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import org.springblade.core.mp.support.Query;
@@ -158,9 +159,14 @@ public interface IArchivesAutoService extends BaseService<ArchivesAuto> {
 
 	R sendFileToEArchives(ArchiveDataVo dataInfo);
 
-    void fileNumberFlush(Long projectId, Long contractId, List<String> nodeIds,Integer isArchive);
+    void fileNumberFlush(Long projectId, Long contractId, List<String> nodeIds,Integer isArchive,Integer startNumber);
 
     boolean reBuildArchiveFrontPdfs(String archiveIds, Long projectId);
 
     boolean findAndReplace(List<ArchivesAuto> archivesAutos, FindAndReplaceDto dto);
+
+	void reCreateArchiveAuto(ArchivesAuto archivesAuto, List<ArchiveFile> waitArchiveFiles);
+
+
+	boolean creatFileNameFormAI(String ids, Long projectId, Long contractId) throws IOException;
 }

+ 155 - 0
blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveAiNameServiceImpl.java

@@ -0,0 +1,155 @@
+/*
+ *      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.archive.service.impl;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.apache.commons.lang.StringUtils;
+import org.springblade.archive.entity.ArchiveAiName;
+import org.springblade.archive.mapper.ArchiveAiNameMapper;
+import org.springblade.archive.service.IArchiveAiNameService;
+import org.springblade.archive.vo.ArchiveAiNameVO;
+import org.springblade.archive.vo.ArchiveAiNameVO1;
+import org.springblade.common.utils.DeepSeekClient;
+import org.springblade.core.mp.base.BaseServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.stream.Collectors;
+
+import static java.util.stream.Collectors.groupingBy;
+
+/**
+ *  服务实现类
+ *
+ * @author BladeX
+ * @since 2025-07-03
+ */
+@Service
+public class ArchiveAiNameServiceImpl extends BaseServiceImpl<ArchiveAiNameMapper, ArchiveAiName> implements IArchiveAiNameService {
+
+	 private static String DEEPSEEK_ARCHIVE_NAME = ".这是一段案卷题名,精简案卷题名重复啰嗦的内容,不要加以上内容没有的词语 返回值不要有任何多余得废话,只要结果";
+	 private static final int MAX_CONCURRENT_REQUESTS = 5;
+
+	@Autowired
+	private JdbcTemplate jdbcTemplate;
+
+	@Autowired
+	private DeepSeekClient deepSeekClient;
+
+	@Resource(name = "taskExecutor1")
+	private ThreadPoolExecutor executor;
+
+	private final Semaphore apiSemaphore = new Semaphore(MAX_CONCURRENT_REQUESTS);
+
+	@Override
+	@Async("taskExecutor1")
+	@Transactional
+	public void syncCreatAiName(List<ArchiveAiName> aiNames) {
+		aiNames.parallelStream().forEach(name -> {
+			try {
+				apiSemaphore.acquire();
+				try {
+					String content = deepSeekClient.getSimplifiedContent(name.getArchiveName() + DEEPSEEK_ARCHIVE_NAME);
+					if (content.startsWith("API_ERROR:") ||
+							content.startsWith("PARSE_ERROR:") ||
+							content.startsWith("IO_ERROR:")||content.startsWith("Error:")) {
+						name.setStatus(4);
+						name.setArchiveNameAi("获取失败");
+					} else {
+						name.setArchiveNameAi(content);
+						name.setStatus(2); // 标记为成功
+					}
+				} finally {
+					apiSemaphore.release();
+				}
+			} catch (InterruptedException e) {
+				Thread.currentThread().interrupt();
+				name.setStatus(4); // 设置失败状态
+				name.setArchiveNameAi("获取失败");
+			} catch (Exception e) {
+				name.setStatus(4); // 设置失败状态
+				name.setArchiveNameAi("获取失败");
+			}
+		});
+
+		// 分批更新数据库
+		int batchSize = 100;
+		for (int i = 0; i < aiNames.size(); i += batchSize) {
+			int end = Math.min(i + batchSize, aiNames.size());
+			List<ArchiveAiName> batch = aiNames.subList(i, end);
+			this.updateBatchById(batch);
+		}
+	}
+
+	@Override
+	public List<ArchiveAiNameVO> getArchiveAiTask(Long projectId, Long contractId) {
+		List<ArchiveAiNameVO>list=new ArrayList<>();
+		List<ArchiveAiName> archiveAiNameList = this.baseMapper.selectList(new LambdaQueryWrapper<>(ArchiveAiName.class).eq(ArchiveAiName::getProjectId, projectId).eq(ArchiveAiName::getContractId, contractId));
+		if(!archiveAiNameList.isEmpty()){
+			Map<Long, List<ArchiveAiName>> map = archiveAiNameList.stream().collect(groupingBy(ArchiveAiName::getTaskId));
+			for (Map.Entry<Long, List<ArchiveAiName>> entry : map.entrySet()) {
+				ArchiveAiNameVO archiveAiNameVO = new ArchiveAiNameVO();
+				List<ArchiveAiName> archiveAiNames = entry.getValue();
+				archiveAiNameVO.setTaskId(entry.getKey());
+				Date createTime = archiveAiNames.get(0).getCreateTime();
+				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+				String formattedDate = sdf.format(createTime);
+				archiveAiNameVO.setTaskTime(formattedDate);
+				archiveAiNameVO.setNum(archiveAiNames.size());
+				archiveAiNameVO.setStatus(archiveAiNames.stream().allMatch(ai -> ai.getStatus() >1) ? 2:1);
+				list.add(archiveAiNameVO);
+			}
+		}
+		return list;
+	}
+
+
+	@Transactional
+	public boolean confirmAiName(List<ArchiveAiNameVO1>vos) {
+		for (ArchiveAiNameVO1 archiveAiName : vos) {
+			if(archiveAiName.getStatus()==2&& StringUtils.isNotEmpty(archiveAiName.getArchiveNameAi())){
+				archiveAiName.setStatus(3);
+				String sql=" update u_archives_auto set name='"+archiveAiName.getArchiveNameAi()+"', colour_status=2  where id="+archiveAiName.getArchiveAutoId();
+				jdbcTemplate.update(sql);
+				String sql2="update u_archive_ai_name set status=3 where id="+archiveAiName.getId();
+				jdbcTemplate.update(sql2);
+			}
+		}
+		Long taskId = vos.get(0).getTaskId();
+		String sql3="select * from u_archive_ai_name where task_id="+taskId+" and is_deleted=0";
+		List<ArchiveAiName> list = jdbcTemplate.query(sql3, new BeanPropertyRowMapper<>(ArchiveAiName.class));
+		if(list.stream().allMatch(item -> item.getStatus() >= 3)){
+			deletedArchiveAiTask(taskId);
+		};
+		return true;
+	}
+
+	@Override
+	public Boolean deletedArchiveAiTask(Long taskId) {
+		return baseMapper.deletedArchiveAiTask(taskId);
+	}
+}

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

@@ -41,10 +41,7 @@ import java.io.OutputStream;
 import java.io.*;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.stream.Collectors;
 
 @Slf4j
@@ -321,7 +318,7 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
                 urls.add(url);
             }
         }
-        String localPath = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
+        String localPath = FileUtils.getSysLocalFileUrl();
         List<String> pageUrls = FileUtils.doForPageNumberUseItextpdf(urls, localPath, newIOSSClient, archivesAuto.getProjectId());
         for (int i = 0; i < waitArchiveFiles.size(); i++) {
             waitArchiveFiles.get(i).setPdfPageUrl(pageUrls.get(i));
@@ -671,7 +668,46 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
 //                                    newStyle.setWrapText(true);
 //                                    cell.setCellStyle(newStyle);
 //                                }
-                                cell.setCellValue(myData);
+                                // ====================== 核心修改开始 ======================
+                                if (myData.startsWith("twospaces")) {
+                                    // 1. 去掉开头的"twospaces",并添加"占位"两个汉字
+                                    String actualText = myData.substring("twospaces".length()).trim();
+                                    String displayText = "占位" + actualText;
+
+                                    // 2. 创建富文本格式:白色"占位"+默认颜色实际文本
+                                    CreationHelper helper = workbook.getCreationHelper();
+                                    RichTextString richText = helper.createRichTextString(displayText);
+
+                                    // 创建白色字体(用于"占位"两字)
+                                    Font whiteFont = workbook.createFont();
+                                    whiteFont.setColor(IndexedColors.WHITE.getIndex());
+
+                                    // 创建默认黑色字体(用于实际文本)
+                                    Font defaultFont = workbook.createFont();
+                                    defaultFont.setColor(IndexedColors.BLACK.getIndex());
+
+                                    // 🔴 修复:正确设置索引范围
+                                    // "占位"是两个字符,索引0-1
+                                    richText.applyFont(0, 2, whiteFont);  // 第0-1个字符:白色
+
+                                    // 剩余字符:黑色(从索引2开始)
+                                    if (displayText.length() > 2) {
+                                        richText.applyFont(3, displayText.length() - 1, defaultFont);
+                                    }
+
+                                    // 3. 设置单元格值
+                                    cell.setCellValue(richText);
+
+                                    // 4. 设置单元格样式确保白色文字不可见
+                                    CellStyle style = workbook.createCellStyle();
+                                    style.cloneStyleFrom(cell.getCellStyle());
+                                    style.setWrapText(true);  // 保持自动换行
+                                    cell.setCellStyle(style);
+
+                                } else {
+                                    // 非"twospaces"开头的正常处理
+                                    cell.setCellValue(myData);
+                                }
                             }
                         }
                     }
@@ -741,6 +777,12 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
             file.setFileTime(FileUtils.cleanFileTime(file.getFileTime()));
 
             Map<String, Object> fileMap = new ObjectMapper().convertValue(file, Map.class);
+
+            if (fileMap.containsKey("fileName") && fileMap.get("fileName") != null) {
+                String fileName = fileMap.get("fileName").toString();
+                fileMap.put("fileName", "twospaces" + fileName); // 添加两个空格前缀
+            }
+
             fileMapList.add(fileMap);
         }
         //设置总页数
@@ -825,6 +867,9 @@ public class ArchiveAutoPdfServiceImpl implements IArchiveAutoPdfService {
         try {
             if (file != null) {
                 url = file.getPdfFileUrl();
+                if(StringUtils.isNotEmpty(file.getEVisaFile())&& !Objects.equals(file.getPdfFileUrl(),file.getEVisaFile())){
+                    url=file.getEVisaFile();
+                }
                 if (StringUtil.isEmpty(url)) {
                     String fileUrl = file.getFileUrl();
                     if (fileUrl != null && StringUtils.isNotEmpty(fileUrl) && fileUrl.endsWith(".pdf")) {

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

@@ -203,7 +203,7 @@ public class ArchiveNameServiceImpl implements IArchiveNameService {
     @Override
     public String generateFullLevelName(
             List<Long> nodeIds,
-            NodeHierarchy hierarchy
+            NodeHierarchy hierarchy,boolean useCovering
     ) {
         // 1. 获取输入节点
         Map<Long, ArchiveTreeContract> allNodeMap = hierarchy.getAllNodeMap();
@@ -283,7 +283,7 @@ public class ArchiveNameServiceImpl implements IArchiveNameService {
                                 }
                             }
 
-                            if (allGroupsFullyCovered) {
+                            if (allGroupsFullyCovered && useCovering) {
                                 nameParts.add(getLevelName(hierarchy, grandParentId));
                                 canUseGrandParentName = true;
                             }
@@ -317,7 +317,7 @@ public class ArchiveNameServiceImpl implements IArchiveNameService {
                 int childrenCount = (allChildren != null) ? allChildren.size() : 0;
 
                 // 检查是否全覆盖所有子节点
-                if (childrenCount > 0 && groupNodes.size() == childrenCount) {
+                if (childrenCount > 0 && groupNodes.size() == childrenCount ) {
                     // 只有组内第一个父节点使用完整层级名称
                     String parentName = firstParentInGroup ?
                             getLevelName(hierarchy, groupId) :
@@ -334,7 +334,14 @@ public class ArchiveNameServiceImpl implements IArchiveNameService {
                     String childNames = groupNodes.stream()
                             .map(ArchiveTreeContract::getNodeName)
                             .collect(Collectors.joining("、"));
-                    nameParts.add(parentName + childNames);
+                    // 修改点:根据条件决定添加的内容
+                    if (!useCovering ) {
+                        // 当 useCovering=false 且不是第一个父节点时,只添加子节点名称
+                        nameParts.add(childNames);
+                    } else {
+                        // 其他情况:添加父节点名称+子节点名称
+                        nameParts.add(parentName + childNames);
+                    }
                 }
 
                 // 后续节点不再是第一个

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

@@ -52,6 +52,7 @@ import org.springblade.business.feign.ArchiveFileClient;
 import org.springblade.business.feign.MetadataClassificationClient;
 import org.springblade.business.feign.TaskClient;
 import org.springblade.common.utils.CommonUtil;
+import org.springblade.common.utils.DeepSeekClient;
 import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.mp.base.BaseServiceImpl;
@@ -91,11 +92,13 @@ import java.net.URL;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.rmi.ServerException;
 import java.time.LocalDateTime;
 import java.util.*;
 import java.util.List;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
 /**
@@ -151,6 +154,8 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 
 	private final IArchiveNameService archiveNameService;
 
+	private final IArchiveAiNameService aiNameService;
+
 
 	@Override
 	public IPage<ArchivesAutoVO> selectArchivesAutoPage(IPage<ArchivesAutoVO> page, ArchivesAutoVO archivesAuto) {
@@ -383,43 +388,34 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 			vo.setSecretLevelValue("1".equals(vo.getSecretLevel()) ? "机密" : ("2".equals(vo.getSecretLevel()) ? "绝密" : "秘密"));
 		}
 		List<ArchivesAutoVO.ApprovalFile> approvalFiles = vo.getApprovalFileList();
-		ArchivesAutoVO.ApprovalFile front = null;
-		ArchivesAutoVO.ApprovalFile cataLog = null;
-		ArchivesAutoVO.ApprovalFile spare = null;
-		ArchivesAutoVO.ApprovalFile back = null;
+		ArchivesAutoVO.ApprovalFile[] elementFiles = new ArchivesAutoVO.ApprovalFile[4];
+		AtomicInteger pageSize = new AtomicInteger(0);
 		if (approvalFiles != null && !approvalFiles.isEmpty()) {
-			// todo 四要素 使用名称判断
-			Map<String, List<ArchivesAutoVO.ApprovalFile>> collect = approvalFiles.stream().collect(Collectors.groupingBy(approvalFile -> {
-				if (approvalFile != null &&
-						(approvalFile.getFileName().equals("封面") || approvalFile.getFileName().equals("卷内目录") || approvalFile.getFileName().equals("卷内备考表") || approvalFile.getFileName().equals("备考表") || approvalFile.getFileName().equals("背脊"))) {
-					if (approvalFile.getFileName().equals("卷内备考表")) {
-						return "备考表";
-					}
-					return approvalFile.getFileName();
+			// 四要素 使用名称判断
+			approvalFiles.removeIf(approvalFile -> {
+				if ("封面".equals(approvalFile.getFileName()) || "封面表".equals(approvalFile.getFileName())) {
+					elementFiles[0] = approvalFile;
+					return true;
+				} else if ("卷内目录".equals(approvalFile.getFileName()) || "卷内目录表".equals(approvalFile.getFileName()) || "目录表".equals(approvalFile.getFileName()) || "目录".equals(approvalFile.getFileName())) {
+					elementFiles[1] = approvalFile;
+					return true;
+				} else if ("备考表".equals(approvalFile.getFileName()) || "卷内备考表".equals(approvalFile.getFileName())) {
+					elementFiles[2] = approvalFile;
+					return true;
+				} else if ("背脊".equals(approvalFile.getFileName()) || "背脊表".equals(approvalFile.getFileName())) {
+					elementFiles[3] = approvalFile;
+					return true;
 				}
-				return "0";
-			}, Collectors.toList()));
-			List<ArchivesAutoVO.ApprovalFile> approvalFiles1 = collect.get("0");
-			if (approvalFiles1 == null) {
-				approvalFiles1 = new ArrayList<>();
-			}
-			vo.setPageNumber(approvalFiles1.size());
-			vo.setApprovalFileList(approvalFiles1);
-			if (collect.containsKey("封面")) {
-				front = collect.get("封面").stream().max(Comparator.comparing(ArchivesAutoVO.ApprovalFile::getId)).orElse(null);
-			}
-			if (collect.containsKey("卷内目录")) {
-				cataLog = collect.get("卷内目录").stream().max(Comparator.comparing(ArchivesAutoVO.ApprovalFile::getId)).orElse(null);
-			}
-			if (collect.containsKey("备考表")) {
-				spare = collect.get("备考表").stream().max(Comparator.comparing(ArchivesAutoVO.ApprovalFile::getId)).orElse(null);
-			}
-			if (collect.containsKey("背脊")) {
-				back = collect.get("背脊").stream().max(Comparator.comparing(ArchivesAutoVO.ApprovalFile::getId)).orElse(null);
-			}
+				pageSize.addAndGet(approvalFile.getFilePage() == null ? 1 : approvalFile.getFilePage());
+				return false;
+			});
 		} else {
 			vo.setPageNumber(0);
 		}
+		ArchivesAutoVO.ApprovalFile front = elementFiles[0];
+		ArchivesAutoVO.ApprovalFile cataLog = elementFiles[1];
+		ArchivesAutoVO.ApprovalFile spare = elementFiles[2];
+		ArchivesAutoVO.ApprovalFile back = elementFiles[3];
 		String outUrl = vo.getOutUrl();
 		if (StringUtils.isNotBlank(outUrl)) {
 			// 根据 factorType 字符串生成档案号码字符串链表
@@ -1107,7 +1103,9 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 			indexMap.put(treeCode, fileNumberSuffix + 1);
 		}
 
-		archivesAuto.setFileNumber(fileNumberSuffix.toString());//档号
+		// 将数值格式化为3位数字字符串(不足3位前面补0)
+		String formattedNumber = String.format("%03d", fileNumberSuffix);
+		archivesAuto.setFileNumber(formattedNumber); // 设置档号
 		//archivesAuto.setMicron();//微缩号
 		archivesAuto.setUnit(unit);//立卷单位
 		//archivesAuto.setQuantity();//数量/单位
@@ -1297,7 +1295,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 
 
 	private String builtArchiveName_new(List<ArchiveFile> waitArchiveFiles, ArchiveTreeContract node, boolean isCrossNode
-	,IArchiveNameService.NodeHierarchy nameInfo) {
+	,IArchiveNameService.NodeHierarchy nameInfo,Set<Long> multiVolumeNodes,Integer archiveAutoType) {
 
 		String archiveName = "";
 
@@ -1308,7 +1306,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		Long contractId = node.getContractId();
 		if (contractId != null && contractId != -1) {
 			ContractInfo contract = contractClient.getContractById(contractId);
-			contractName = contract.getContractName();
+			contractName = contract.getContractNumber();
 		}
 		//获取案卷题名
 		archiveName = projectName;
@@ -1323,16 +1321,62 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 				.filter(nodeId -> nodeId != null && !nodeId.isEmpty())
 				.collect(Collectors.toCollection(LinkedHashSet::new));
 
+		String timeRange = "";
+
+		boolean extFlag = false;
+		if (node.getExtType()!= null && node.getExtType()== 1) {
+			extFlag = true;
+		}
+
+
+		if (uniqueNodeIds.size() == 1 && extFlag == false) {
+			try {
+				Long nodeId = Long.parseLong(uniqueNodeIds.iterator().next());
+
+				// 检查该节点是否需要添加时间区间(生成多个案卷)
+				if (multiVolumeNodes != null && multiVolumeNodes.contains(nodeId)) {
+					// 获取所有有效的时间字符串
+					List<String> validTimes = waitArchiveFiles.stream()
+							.map(ArchiveFile::getFileTime)
+							.filter(time -> time != null && !time.trim().isEmpty())
+							.sorted() // 按字符串自然顺序排序
+							.collect(Collectors.toList());
+
+					if (!validTimes.isEmpty()) {
+						String minTime = validTimes.get(0);
+						String maxTime = validTimes.get(validTimes.size() - 1);
+
+						// 生成时间区间字符串
+						timeRange = minTime + "~" + maxTime;
+					} else {
+						log.warn("组卷文件缺少有效时间戳:nodeId={}", nodeId);
+					}
+				}
+			} catch (NumberFormatException e) {
+				log.warn("无效的节点ID格式", e);
+			}
+		}
+
 		// 2. 将节点ID从String转换为Long(保持原始顺序)
 		List<Long> nodeIds = uniqueNodeIds.stream()
 				.map(this::safeParseLong)
 				.filter(Objects::nonNull)
 				.collect(Collectors.toList());
 
+		String fullPath = "";
+		if (extFlag == true) {
+			fullPath =  archiveNameService.generateFullLevelName(nodeIds, nameInfo,true);
+		}else {
+			//独立组卷,且非工序节点,取节点名曾即可
+			if (archiveAutoType == 3) {
+				fullPath =  node.getNodeName();
+			}else {
+				fullPath =  archiveNameService.generateFullLevelName(nodeIds, nameInfo,false);
+			}
+		}
 
-		String fullPath =  archiveNameService.generateFullLevelName(nodeIds, nameInfo);
 
-		archiveName+=fullPath;
+		archiveName += timeRange + fullPath;
 
 //		if (archiveName.length() > 200) {
 //			// 从150位置开始查找第一个顿号
@@ -1440,7 +1484,6 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		//生成文件对应的页码,返回url
 		archiveAutoPdfService.builtFilePageNo(archivesAuto, waitArchiveFiles);
 		this.updateById(archivesAuto);
-
 		return "";
 	}
 
@@ -1467,7 +1510,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		//1.创建新案卷
 		ArchivesAuto archivesAuto = builtArchives(node, pageN, fileN, startDate, endDate, archiveName);
 		//2.设置文件所属案卷,组卷状态
-		Long archivesAutoId = archivesAuto.getId();
+		//Long archivesAutoId = archivesAuto.getId();
 
 		//封面和生成文件页码
 		archiveAutoPdfService.buildArchiveFrontPdfs(archivesAuto.getProjectId(), archivesAuto, waitArchiveFiles, false);
@@ -1475,11 +1518,9 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		builtFilePageNo(archivesAuto, waitArchiveFiles);//生成文件页码
 
 
-		for (ArchiveFile file : waitArchiveFiles) {
-			file.setArchiveId(archivesAutoId);//设置文件所属案卷
-			file.setIsArchive(1);
-
-		}
+		//设置文件所属案卷,组卷状态,排序
+		Long archivesAutoId = archivesAuto.getId();
+		setArchiveFiles(archivesAutoId,waitArchiveFiles);
 		archiveFileClient.updateArchiveFileForCreateArchive(waitArchiveFiles);
 		try {
 //			for (ArchiveFile saveVo : waitArchiveFiles) {
@@ -1491,6 +1532,50 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		}
 	}
 
+
+	public void reCreateArchiveAuto(ArchivesAuto archivesAuto, List<ArchiveFile> waitArchiveFiles){
+		archiveAutoPdfService.assignArchiveTableUrl();
+		//生成四要素
+		archiveAutoPdfService.buildArchiveFrontPdfs(archivesAuto.getProjectId(), archivesAuto, waitArchiveFiles, true);
+		//生成页码
+		builtFilePageNo(archivesAuto, waitArchiveFiles);
+		archiveFileClient.updateArchiveFile(waitArchiveFiles);
+	}
+
+	@Override
+	public boolean creatFileNameFormAI(String ids, Long projectId, Long contractId) throws IOException {
+		List<ArchivesAuto> archivesAutoList = this.listByIds(Func.toLongList(ids));
+		List<ArchiveAiName>aiNames=new ArrayList<>();
+		Long taskId=SnowFlakeUtil.getId();
+		List<ArchiveAiName> archiveAiNameList = aiNameService.getBaseMapper().selectList(new LambdaQueryWrapper<>(ArchiveAiName.class).eq(ArchiveAiName::getProjectId, projectId).eq(ArchiveAiName::getContractId, contractId).in(ArchiveAiName::getArchiveAutoId, Func.toLongList(ids)));
+		List<Long> existid=new ArrayList<>();
+		if(!archiveAiNameList.isEmpty()){
+			existid= archiveAiNameList.stream().filter(ai -> ai.getStatus() == 1).map(ai -> ai.getArchiveAutoId()).collect(Collectors.toList());
+		}
+		for (ArchivesAuto auto : archivesAutoList) {
+			if(!existid.isEmpty()){
+				if(existid.contains(auto.getId())){
+					continue;
+				}
+			}
+			ArchiveAiName aiName = new ArchiveAiName();
+			aiName.setProjectId(projectId);
+			aiName.setContractId(contractId);
+			aiName.setTaskId(taskId);
+			aiName.setArchiveAutoId(auto.getId());
+			aiName.setArchiveName(auto.getName());
+			aiName.setStatus(1);
+			aiNames.add(aiName);
+		}
+		if(aiNames.size()<=0){
+			throw new ServerException("所选节点正在生成中,请勿重复提交");
+		}
+		//异步调用AI接口
+		aiNameService.syncCreatAiName(aiNames);
+		return aiNameService.saveBatch(aiNames);
+	}
+
+
 	/**
 	 * 单独组卷规则组卷
 	 *
@@ -1498,7 +1583,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 	 * @param node             规格参数所在节点
 	 * @param pageN
 	 */
-	private void createArchive3_new(List<ArchiveFile> waitArchiveFiles, ArchiveTreeContract node, int pageN,IArchiveNameService.NodeHierarchy nameInfo) {
+	private void createArchive3_new(List<ArchiveFile> waitArchiveFiles, ArchiveTreeContract node, int pageN,IArchiveNameService.NodeHierarchy nameInfo, Set<Long> multiVolumeNodes) {
 
 		String archiveStartDateAndEndDate = getArchiveStartDateAndEndDate(waitArchiveFiles);
 		String[] split = archiveStartDateAndEndDate.split(",");
@@ -1509,11 +1594,11 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 			return;
 		}
 
-		String archiveName = builtArchiveName_new(waitArchiveFiles, node, false,nameInfo);//获取案卷题名
+		String archiveName = builtArchiveName_new(waitArchiveFiles, node, false,nameInfo,multiVolumeNodes,3);//获取案卷题名
 		//1.创建新案卷
 		ArchivesAuto archivesAuto = builtArchives(node, pageN, fileN, startDate, endDate, archiveName);
 		//2.设置文件所属案卷,组卷状态
-		Long archivesAutoId = archivesAuto.getId();
+		//Long archivesAutoId = archivesAuto.getId();
 
 		//封面和生成文件页码
 		archiveAutoPdfService.buildArchiveFrontPdfs(archivesAuto.getProjectId(), archivesAuto, waitArchiveFiles, false);
@@ -1521,11 +1606,9 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		builtFilePageNo(archivesAuto, waitArchiveFiles);//生成文件页码
 
 
-		for (ArchiveFile file : waitArchiveFiles) {
-			file.setArchiveId(archivesAutoId);//设置文件所属案卷
-			file.setIsArchive(1);
-
-		}
+		//设置文件所属案卷,组卷状态,排序
+		Long archivesAutoId = archivesAuto.getId();
+		setArchiveFiles(archivesAutoId,waitArchiveFiles);
 		archiveFileClient.updateArchiveFileForCreateArchive(waitArchiveFiles);
 		try {
 //			for (ArchiveFile saveVo : waitArchiveFiles) {
@@ -1545,7 +1628,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 	 * @param waitArchiveFiles
 	 * @param archiveAutoGroupId 分类并卷分组ID
 	 */
-	private void createArchive2(List<ArchiveFile> waitArchiveFiles, Long archiveAutoGroupId, Long projectId,IArchiveNameService.NodeHierarchy nameInfo) {
+	private void createArchive2(List<ArchiveFile> waitArchiveFiles, Long archiveAutoGroupId, Long projectId,IArchiveNameService.NodeHierarchy nameInfo,Set<Long> multiVolumeNodes) {
 
 		//获取同一分类archiveAutoGroupId下设置的(设置规则时选中的)节点,排好序
 //		List<ArchiveTreeContract> selectList = archiveTreeContractClient.getStorageNodeByGroupId(projectId, archiveAutoGroupId);
@@ -1587,7 +1670,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		}
 		//默认组卷存在跨节点组卷  注意案卷归属节点,案卷命名方式
 		//获取案卷题名
-		String archiveName = builtArchiveName_new(waitArchiveFiles, node, true,nameInfo);//获取案卷题名
+		String archiveName = builtArchiveName_new(waitArchiveFiles, node, true,nameInfo,multiVolumeNodes,2);//获取案卷题名
 
 		//1.创建新案卷
 		ArchivesAuto archivesAuto = builtArchives(node, pageN, fileN, startDate, endDate, archiveName);
@@ -1597,12 +1680,16 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 
 		builtFilePageNo(archivesAuto, waitArchiveFiles);
 
-		//3.设置文件所属案卷,组卷状态
+
+//		Long archivesAutoId = archivesAuto.getId();
+//		for (ArchiveFile file : waitArchiveFiles) {
+//			file.setArchiveId(archivesAutoId);//设置文件所属案卷
+//			file.setIsArchive(1);
+//		}
+		//设置文件所属案卷,组卷状态,排序
 		Long archivesAutoId = archivesAuto.getId();
-		for (ArchiveFile file : waitArchiveFiles) {
-			file.setArchiveId(archivesAutoId);//设置文件所属案卷
-			file.setIsArchive(1);
-		}
+		setArchiveFiles(archivesAutoId,waitArchiveFiles);
+
 		archiveFileClient.updateArchiveFileForCreateArchive(waitArchiveFiles);
 		try {
 			batchCreateMetadataFiles(waitArchiveFiles);
@@ -1645,11 +1732,9 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		builtFilePageNo(archivesAuto, waitArchiveFiles);
 
 		//3.设置文件所属案卷,组卷状态
+		//设置文件所属案卷,组卷状态,排序
 		Long archivesAutoId = archivesAuto.getId();
-		for (ArchiveFile file : waitArchiveFiles) {
-			file.setArchiveId(archivesAutoId);//设置文件所属案卷
-			file.setIsArchive(1);
-		}
+		setArchiveFiles(archivesAutoId,waitArchiveFiles);
 		archiveFileClient.updateArchiveFileForCreateArchive(waitArchiveFiles);
 		try {
 //			for (ArchiveFile saveVo : waitArchiveFiles) {
@@ -1701,11 +1786,9 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		builtFilePageNo(archivesAuto, waitArchiveFiles);
 
 		//3.设置文件所属案卷,组卷状态
+		//设置文件所属案卷,组卷状态,排序
 		Long archivesAutoId = archivesAuto.getId();
-		for (ArchiveFile file : waitArchiveFiles) {
-			file.setArchiveId(archivesAutoId);//设置文件所属案卷
-			file.setIsArchive(1);
-		}
+		setArchiveFiles(archivesAutoId,waitArchiveFiles);
 		archiveFileClient.updateArchiveFileForCreateArchive(waitArchiveFiles);
 		try {
 //			for (ArchiveFile saveVo : waitArchiveFiles) {
@@ -1840,6 +1923,8 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 			String completeMsg = "[自动组卷] 单独组卷:" + "-traceId:" + traceId + "节点:" + node.getNodeName() + " 文件数量:" + archiveFiles.size();
 			iTraceLogService.saveLog(traceId, completeMsg);
 
+			Set<Long> multiVolumeNodes = precalculateMultiVolumeNodes(archiveFiles, specificationSize);
+
 			// 步骤4:遍历未归档文件
 			List<ArchiveFile> waitArchiveFiles = new ArrayList<>();  // 待组卷文件集合
 			int archivesSize = 0;  // 待组卷文件总页数
@@ -1855,7 +1940,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 
 					// 如果是最后一个文件且有待组卷文件,则组卷
 					if (archiveFilesSize == archiveFiles.size() && !waitArchiveFiles.isEmpty()) {
-						createArchive3_new(waitArchiveFiles, node, archivesSize,nameInfo);
+						createArchive3_new(waitArchiveFiles, node, archivesSize,nameInfo,null);
 						waitArchiveFiles.clear();
 						archivesSize = 0;
 					}
@@ -1874,7 +1959,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 
 						// 最后一个文件直接组卷
 						if (archiveFilesSize == archiveFiles.size()) {
-							createArchive3_new(waitArchiveFiles, node, archivesSize,nameInfo);
+							createArchive3_new(waitArchiveFiles, node, archivesSize,nameInfo,multiVolumeNodes);
 							waitArchiveFiles.clear();
 							archivesSize = 0;
 						}
@@ -1883,7 +1968,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 					else if (checkStatus == 1) {
 						waitArchiveFiles.add(file);
 						archivesSize = tempTotalSize;
-						createArchive3_new(waitArchiveFiles, node, archivesSize,nameInfo);
+						createArchive3_new(waitArchiveFiles, node, archivesSize,nameInfo,multiVolumeNodes);
 
 						// 重置待组卷集合
 						waitArchiveFiles.clear();
@@ -1893,7 +1978,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 					else if (checkStatus == -1) {
 						if (!waitArchiveFiles.isEmpty()) {
 							// 先将现有集合组卷(不含当前文件)
-							createArchive3_new(waitArchiveFiles, node, archivesSize,nameInfo);
+							createArchive3_new(waitArchiveFiles, node, archivesSize,nameInfo,multiVolumeNodes);
 
 							// 新建集合存放当前文件
 							waitArchiveFiles.clear();
@@ -1902,7 +1987,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 
 							// 最后一个文件直接组卷
 							if (archiveFilesSize == archiveFiles.size()) {
-								createArchive3_new(waitArchiveFiles, node, archivesSize,nameInfo);
+								createArchive3_new(waitArchiveFiles, node, archivesSize,nameInfo,multiVolumeNodes);
 								waitArchiveFiles.clear();
 								archivesSize = 0;
 							}
@@ -1910,7 +1995,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 							// 当前文件单独成卷
 							waitArchiveFiles.add(file);
 							archivesSize = filePage;
-							createArchive3_new(waitArchiveFiles, node, archivesSize,nameInfo);
+							createArchive3_new(waitArchiveFiles, node, archivesSize,nameInfo,multiVolumeNodes);
 
 							// 重置集合
 							waitArchiveFiles.clear();
@@ -2258,6 +2343,8 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		int fileIndex = 0;
 		int totalFiles = archiveFiles.size();
 
+		Set<Long> multiVolumeNodes = precalculateMultiVolumeNodes(archiveFiles, specificationSize);
+
 		for (ArchiveFile file : archiveFiles) {
 			fileIndex++;
 			// 获取文件页数,处理null值
@@ -2275,13 +2362,13 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 					waitArchiveFiles.add(file);
 					archivesSize = tempTotalSize;
 					if (fileIndex == totalFiles) { // 是最后一个文件
-						createArchive2(waitArchiveFiles, archiveAutoGroupId, projectId,nameInfo);
+						createArchive2(waitArchiveFiles, archiveAutoGroupId, projectId,nameInfo,multiVolumeNodes);
 					}
 					break;
 
 				case 1: // 达到规格
 					waitArchiveFiles.add(file);
-					createArchive2(waitArchiveFiles, archiveAutoGroupId, projectId,nameInfo);
+					createArchive2(waitArchiveFiles, archiveAutoGroupId, projectId,nameInfo,multiVolumeNodes);
 					waitArchiveFiles = new ArrayList<>();
 					archivesSize = 0;
 					break;
@@ -2289,10 +2376,10 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 				case -1: // 超出规格
 					if (waitArchiveFiles.isEmpty()) {
 						// 当前文件单独成卷
-						createArchive2(Collections.singletonList(file), archiveAutoGroupId, projectId,nameInfo);
+						createArchive2(Collections.singletonList(file), archiveAutoGroupId, projectId,nameInfo,multiVolumeNodes);
 					} else {
 						// 先将现有文件组卷
-						createArchive2(waitArchiveFiles, archiveAutoGroupId, projectId,nameInfo);
+						createArchive2(waitArchiveFiles, archiveAutoGroupId, projectId,nameInfo,multiVolumeNodes);
 
 						// 创建新的待组卷集合
 						waitArchiveFiles = new ArrayList<>();
@@ -2300,7 +2387,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 						archivesSize = filePage;
 
 						if (fileIndex == totalFiles) { // 是最后一个文件
-							createArchive2(waitArchiveFiles, archiveAutoGroupId, projectId,nameInfo);
+							createArchive2(waitArchiveFiles, archiveAutoGroupId, projectId,nameInfo,multiVolumeNodes);
 						}
 					}
 					break;
@@ -2506,7 +2593,8 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 				.ne("is_auto_file", 1)
 				.orderByAsc("tree_sort")
 				.orderByAsc("auto_file_sort")
-				.orderByAsc("file_number");
+				.orderByAsc("file_number")
+		         .orderByAsc("create_time");
 
 		return this.list(queryWrapper);
 	}
@@ -4416,18 +4504,18 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 
     @Override
     @Async
-    public void fileNumberFlush(Long projectId, Long contractId, List<String> nodeIds,Integer isArchive) {
+    public void fileNumberFlush(Long projectId, Long contractId, List<String> nodeIds,Integer isArchive,Integer startNumber) {
         ArchiveProjectConfig config = archiveProjectConfigService.getByProjectIdOrNew(projectId);
         List<ArchivesAutoVO4>list=baseMapper.selectAllArchiveAuto(projectId,contractId,nodeIds,isArchive);
         if(list!=null && list.size()>0){
             if(config.getDirType()==null||config.getDirType()==0){
-                List<ArchivesAuto> archivesAutos = setFileNumberByConfig(config, list);
+                List<ArchivesAuto> archivesAutos = setFileNumberByConfig(config, list,startNumber);
                 this.updateBatchById(archivesAutos);
             }else {
                 Map<Long, List<ArchivesAutoVO4>> map = list.stream().collect(Collectors.groupingBy(ArchivesAutoVO4::getParentId));
                 for (Map.Entry<Long, List<ArchivesAutoVO4>> entry : map.entrySet()) {
                     List<ArchivesAutoVO4> value = entry.getValue();
-                    List<ArchivesAuto> archivesAutos = setFileNumberByConfig(config, value);
+                    List<ArchivesAuto> archivesAutos = setFileNumberByConfig(config, value,startNumber);
                    this.updateBatchById(archivesAutos);
                 }
             }
@@ -4448,6 +4536,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
             //List<ArchiveFile> archiveFiles = archiveFileClient.getArchiveFileByArchiveID(Long.valueOf(archiveId));
             List<ArchiveFile> archiveFiles= jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(ArchiveFile.class));
             archiveAutoPdfService.buildArchiveFrontPdfs(projectId,auto,archiveFiles,true);
+			auto.setColourStatus(1);
             baseMapper.updateById(auto);
         }
         return true;
@@ -4531,8 +4620,11 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
         return true;
     }
 
-    public List<ArchivesAuto> setFileNumberByConfig(ArchiveProjectConfig config,List<ArchivesAutoVO4> value){
-        int i=1;
+    public List<ArchivesAuto> setFileNumberByConfig(ArchiveProjectConfig config,List<ArchivesAutoVO4> value,Integer startNumber){
+        int i=startNumber;
+		if(config.getIndexType()==1&&startNumber.toString().length()>config.getIndexNum()+1){
+			throw new ServiceException("起始流水号位数不能超过设置的虚数位数");
+		}
         List<ArchivesAuto>list=new ArrayList<>();
         for (ArchivesAutoVO4 v:value) {
             ArchivesAuto auto = new ArchivesAuto();
@@ -4540,7 +4632,7 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
                v.setFileNumber(v.getFileNumberPrefix()+"_"+i);
            }else {
                String prefix = v.getFileNumberPrefix();
-               int index = i; // 编号从 1 开始
+               int index = i; // 编号从 startNumber 开始
                // 获取配置中的编号长度(最多多少位)
                int numLength = config.getIndexNum();
                // 默认最多4位,防止过长或无效值
@@ -4695,4 +4787,113 @@ public class ArchivesAutoServiceImpl extends BaseServiceImpl<ArchivesAutoMapper,
 		return R.success("保存成功");
 	}
 
+	// 归档文件设置函数
+	public  void setArchiveFiles(Long archivesAutoId, List<ArchiveFile> waitArchiveFiles) {
+		if (waitArchiveFiles == null || archivesAutoId == null) {
+			return; // 处理空指针情况
+		}
+
+		int archiveSortCounter = 1; // 从1开始递增的archiveSort计数器
+
+		for (ArchiveFile file : waitArchiveFiles) {
+			file.setArchiveId(archivesAutoId);   // 设置文件所属案卷ID
+			file.setIsArchive(1);                // 标记文件已归档
+			file.setArchiveSort(archiveSortCounter++); // 设置自增的archiveSort
+		}
+	}
+
+
+	private Set<Long> precalculateMultiVolumeNodes(List<ArchiveFile> files, int specificationSize) {
+		if (files == null || files.isEmpty()) {
+			return Collections.emptySet();
+		}
+
+		Map<Long, List<List<ArchiveFile>>> nodeGroupingMap = new HashMap<>();
+		Set<Long> multiVolumeNodes = new HashSet<>();
+
+		// 待组卷文件集合
+		List<ArchiveFile> waitArchiveFiles = new ArrayList<>();
+		// 待组卷文件总页数
+		int archivesSize = 0;
+		// 文件索引(用于处理最后文件)
+		int fileIndex = 0;
+		int totalFiles = files.size();
+
+		for (ArchiveFile file : files) {
+			fileIndex++;
+			int filePage = file.getFilePage() != null ? file.getFilePage() : 0;
+			int tempTotalSize = archivesSize + filePage;
+			int checkStatus = checkSpecificationSize(specificationSize, tempTotalSize);
+
+			switch (checkStatus) {
+				case 0: // 未到规格
+					waitArchiveFiles.add(file);
+					archivesSize = tempTotalSize;
+					if (fileIndex == totalFiles) { // 是最后一个文件
+						recordGroup(waitArchiveFiles, nodeGroupingMap);
+					}
+					break;
+
+				case 1: // 达到规格
+					waitArchiveFiles.add(file);
+					recordGroup(waitArchiveFiles, nodeGroupingMap);
+					waitArchiveFiles = new ArrayList<>();
+					archivesSize = 0;
+					break;
+
+				case -1: // 超出规格
+					if (!waitArchiveFiles.isEmpty()) {
+						recordGroup(waitArchiveFiles, nodeGroupingMap);
+						waitArchiveFiles = new ArrayList<>();
+						waitArchiveFiles.add(file);
+						archivesSize = filePage;
+						if (fileIndex == totalFiles) { // 是最后一个文件
+							recordGroup(waitArchiveFiles, nodeGroupingMap);
+						}
+					} else {
+						waitArchiveFiles.add(file);
+						archivesSize = filePage;
+						recordGroup(waitArchiveFiles, nodeGroupingMap);
+						waitArchiveFiles = new ArrayList<>();
+						archivesSize = 0;
+					}
+					break;
+			}
+		}
+
+		// 确定哪些节点有多个卷
+		nodeGroupingMap.forEach((nodeId, groups) -> {
+			if (groups.size() > 1) {
+				multiVolumeNodes.add(nodeId);
+			}
+		});
+
+		return multiVolumeNodes;
+	}
+
+
+	private void recordGroup(List<ArchiveFile> groupFiles, Map<Long, List<List<ArchiveFile>>> nodeGroupingMap) {
+		if (groupFiles == null || groupFiles.isEmpty()) {
+			return;
+		}
+
+		// 提取节点ID(确保单一节点)
+		Set<Long> groupNodeIds = new HashSet<>();
+		for (ArchiveFile file : groupFiles) {
+			try {
+				Long nodeId = Long.parseLong(file.getNodeId());
+				groupNodeIds.add(nodeId);
+			} catch (Exception e) {
+				// 忽略无效节点ID
+			}
+		}
+
+		// 仅记录单节点分组
+		if (groupNodeIds.size() == 1) {
+			Long nodeId = groupNodeIds.iterator().next();
+			nodeGroupingMap.computeIfAbsent(nodeId, k -> new ArrayList<>())
+					.add(new ArrayList<>(groupFiles));
+		}
+	}
+
 }

+ 13 - 7
blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/TaskSplitServiceImpl.java

@@ -33,6 +33,7 @@ import javax.annotation.Resource;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Random;
 
@@ -73,7 +74,7 @@ public class TaskSplitServiceImpl extends BaseServiceImpl<TaskSplitMapper, TaskS
 			}
 
 			Random random = new Random();
-			int randomNumber = random.nextInt(11) + 10; // 生成10到20之间的随机数
+			int randomNumber = random.nextInt(30) + 150; // 生成10到20之间的随机数
 			int i = (int) Math.ceil(randomNumber * spliteTaskCount/60.0 );
 
 			Integer archiveCount = baseMapper.getArchiveCount(contractId);
@@ -85,18 +86,23 @@ public class TaskSplitServiceImpl extends BaseServiceImpl<TaskSplitMapper, TaskS
 			data.put("taskTime",i);
 		}else{ // 指定文件解析
 			taskSplit.setType(3);
-			String[] split = splitIds.split(",");
-			taskSplit.setToolCount(split.length);
+			//String[] split = splitIds.split(",");
+			List<String> split = Func.toStrList(splitIds);
+			taskSplit.setToolCount(split.size());
 			taskSplit.setFinished(0);
 
+			// 修改当前文件的状体
+			// baseMapper.updateArchiveByIds(contractId,splitIds);
+
+
 			Random random = new Random();
-			int randomNumber = random.nextInt(11) + 10; // 生成10到20之间的随机数
-			int i = (int) Math.ceil(randomNumber * split.length/60.0 );
-			data.put("fileCount",split.length);
+			int randomNumber = random.nextInt(30) + 150;// 生成10到20之间的随机数
+			int i = (int) Math.ceil(randomNumber * split.size()/60.0 );
+			data.put("fileCount",split.size());
 			data.put("taskTime",i);
 			LocalDateTime now = LocalDateTime.now();
 			DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss");
-			String formattedDateTime = now.format(formatter)+"_"+split.length+"条分解任务";
+			String formattedDateTime = now.format(formatter)+"_"+split.size()+"条分解任务";
 			taskSplit.setTaskName(formattedDateTime);
 		}
 

+ 30 - 3
blade-service/blade-business/src/main/java/org/springblade/business/controller/EVisaTaskCheckController.java

@@ -844,9 +844,36 @@ public class EVisaTaskCheckController {
             if (ids == null || ids.size() == 0) {
                 return null;
             }
-            String sql = "select * from m_textdict_info where id in(" + StringUtils.join(ids, ",") + ") ";
-            List<TextdictInfo> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(TextdictInfo.class));
-            jsonList = JSONArray.parseArray(JSONObject.toJSONString(query), JSONObject.class);
+        Map<String, List<String>> groupMap = ids.stream().collect(Collectors.groupingBy(str -> {
+            if (str.contains("✹")) {
+                return "sign";
+            }
+            return "dqid";
+        }));
+        List<String> dqIds = groupMap.get("dqid");
+        List<TextdictInfo> query = null;
+        if (dqIds != null && !dqIds.isEmpty()) {
+            String sql = "select * from m_textdict_info where id in(" + StringUtils.join(dqIds, ",") + ") ";
+            query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(TextdictInfo.class));
+        }
+        List<String> signList = groupMap.get("sign");
+        if (signList != null && !signList.isEmpty()) {
+            String signIds = signList.stream().map(sign -> sign.replace("✹", "")).collect(Collectors.joining(","));
+            String sql = "SELECT distinct conf_id,relation_id from m_sign_config_relation WHERE conf_id in ( " + signIds + ") and type = 1 and is_deleted = 0";
+            List<SignConfigRelation> signConfigRelationList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(SignConfigRelation.class));
+            if (!signConfigRelationList.isEmpty()) {
+                if (query == null) {
+                    query = new ArrayList<>();
+                }
+                for (SignConfigRelation relation : signConfigRelationList) {
+                    TextdictInfo textdictInfo = new TextdictInfo();
+                    textdictInfo.setId(relation.getConfId());
+                    textdictInfo.setSigRoleId(relation.getRelationId() + "");
+                    query.add(textdictInfo);
+                }
+            }
+        }
+        jsonList = JSONArray.parseArray(JSONObject.toJSONString(query), JSONObject.class);
 //        }
         return jsonList;
     }

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

@@ -1498,7 +1498,7 @@ public R<String> batchDownloadFileToZip(String ids, HttpServletResponse response
                     String[] idss = query.stream()
                             .map(item -> String.valueOf(item.getId()))
                             .toArray(String[]::new);
-                    String update = "update u_entrust_info set status=3 where id in(" + String.join(",", idss) + ")";
+                    String update = "update u_entrust_info set status=4 where id in(" + String.join(",", idss) + ")";
                     jdbcTemplate.execute(update);
                 }
                 return R.success("操作成功");
@@ -1969,7 +1969,7 @@ public R<Boolean> copyContractTreeNode(@RequestBody CopyContractTreeNodeVO vo) {
                     List<String> keySet = new LinkedList<>();
                     for (Map.Entry<String, Object> entry : resultMap.entrySet()) {
                         keySet.add(entry.getKey());
-                        Object value = reviseValue(eMap, entry.getKey(), entry.getValue());
+                        Object value = reviseValue(eMap, entry.getKey(), entry.getValue(), nodeOld.getPKeyId());
                         if (value != null) {
                             if (value.toString().contains("\n")) {
                                 value = value.toString().replace("\n", "\\n");
@@ -2411,10 +2411,49 @@ private Object reviseValue(Map<String, String> p2, String key, Object value) {
     }
     return value;
 }
+    private Object reviseValue(Map<String, String> p2, String key, Object value, Long pKeyId) {
+        try {
+            if (p2.containsKey(key)) {
+                String setting = p2.get(key);
+                if (StringPool.NULL.equals(setting)) {
+                    /*擦除原来的内容*/
+                    return setting;
+                } else {
+                    /*重做随机值*/
+                    List<RangeJson> rjs = JSON.parseArray(setting, RangeJson.class);
+                    if (value != null && !value.toString().isEmpty() && Func.isNotEmpty(rjs)) {
+                        List<RangeJson> rangeJsons = rjs.stream().filter(rj -> rj.getPkeyId().equals(pKeyId)).collect(Collectors.toList());
+                        if (!rangeJsons.isEmpty()) {
+                            List<String[]> la = Arrays.stream(value.toString().split("☆")).map(s -> s.split("_\\^_")).collect(Collectors.toList());
+                            /*全部为一个数的时候不用修改*/
+                            if (la.stream().map(a -> a[0]).collect(Collectors.toSet()).size() > 1 || la.size() == 1) {
+                                List<String> result = new ArrayList<>();
+                                for (String[] a : la) {
+                                    String v = a[0];
+                                    String sv;
+                                    if (v.contains("、")) {
+                                        sv = Arrays.stream(v.split("[、]")).map(e -> imitate(e, rangeJsons)).collect(Collectors.joining("、"));
+                                    } else {
+                                        sv = imitate(v, rangeJsons);
+                                    }
+                                    result.add(sv + "_^_" + a[1]);
+                                }
+                                return String.join("☆", result);
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return value;
+    }
 
 public String imitate(String v, List<RangeJson> rjs) {
     try {
-        RangeJson best = rjs.stream().min(Comparator.comparingDouble(j -> Double.parseDouble(v) - Double.parseDouble(j.getDesign()))).orElse(rjs.get(0));
+        RangeJson best = rjs.stream().filter(j -> BaseUtils.isNotEmpty(j.getDesign()))
+                .peek(j -> j.setDesign(j.getDesign().split("/")[0])).min(Comparator.comparingDouble(j -> Double.parseDouble(v) - Double.parseDouble(j.getDesign()))).orElse(rjs.get(0));
         // int scale = Math.max(new StringBuilder(v).reverse().indexOf("."), 0);
         int scale = BaseUtils.getScaleZero(v, best.getDev(), best.getDesign());
         return BaseUtils.rangeList(1, best.getDesign(), best.getDev(), 1, scale, 1).get(0).toString();
@@ -2436,7 +2475,8 @@ private String reviseCols(Map<String, String> p2, String cols, Long pkeyId, Stri
                 List<String> colsList = target.stream().filter(k -> k.startsWith("key")).collect(Collectors.toList());
                 for (String k : colsList) {
                     if (p2.containsKey(k)) {
-                        Object value = reviseValue(p2, k, origin.get(k));
+//                        Object value = reviseValue(p2, k, origin.get(k));
+                        Object value = reviseValue(p2, k, origin.get(k), pkeyId);
                         if (value != null) {
                             if (value.toString().contains("_^_")) {
                                 value = "'" + value + "'";
@@ -2584,7 +2624,16 @@ private void addCopyTabData(WbsTreeContract needCopyNode, WbsTreeContract toCopy
                             String tableName = needTab.getInitTableName();
                             String col = nodeTabColsMap.get(tableName);
                             String colVal = nodeTabColsMap.get(tableName);
-                            colVal = colVal.replaceAll("id,p_key_id,", "'" + SnowFlakeUtil.getId() + "' as id,'" + toCopyNodeTab.getPKeyId() + "' as p_key_id,");
+                            String[] split = colVal.split(",");
+                            for (int i = 0; i < split.length; i++) {
+                                String key = split[i];
+                                if (key.equals("id")) {
+                                    split[i] = "'" + SnowFlakeUtil.getId() + "' as id";
+                                } else if (key.equals("p_key_id")) {
+                                    split[i] = "'" + toCopyNodeTab.getPKeyId() + "' as p_key_id";
+                                }
+                            }
+                            colVal = String.join(",", split);
                             //delete SQL (先删除旧数据,再新增)
                             String delSql = "delete from " + tableName + " where p_key_id = " + toCopyNodeTab.getPKeyId() + " ; ";
                             //insert into SQL
@@ -2633,7 +2682,16 @@ private void addCopyTabData(WbsTreeContract needCopyNode, WbsTreeContract toCopy
                                 String tableName = objTab.getInitTableName();
                                 String col = nodeTabColsMap.get(tableName);
                                 String colVal = nodeTabColsMap.get(tableName);
-                                colVal = colVal.replaceAll("id,p_key_id,", "'" + SnowFlakeUtil.getId() + "' as id,'" + objTab.getPKeyId() + "' as p_key_id,");
+                                String[] split = colVal.split(",");
+                                for (int i = 0; i < split.length; i++) {
+                                    String key = split[i];
+                                    if (key.equals("id")) {
+                                        split[i] = "'" + SnowFlakeUtil.getId() + "' as id";
+                                    } else if (key.equals("p_key_id")) {
+                                        split[i] = "'" + objTab.getPKeyId() + "' as p_key_id";
+                                    }
+                                }
+                                colVal = String.join(",", split);
                                 //delete SQL (先删除旧数据,再新增)
                                 String delSql = "delete from " + tableName + " where p_key_id = " + objTab.getPKeyId() + " ; ";
                                 //insert into SQL
@@ -2749,7 +2807,16 @@ private void addCopyNodesAndTabsBuildData(List<WbsTreeContract> addNodeList, Lis
                         String tableName = obj.getInitTableName();
                         String col = nodeTabColsMap.get(tableName);
                         String colVal = nodeTabColsMap.get(tableName);
-                        colVal = colVal.replaceAll("id,p_key_id,", "'" + SnowFlakeUtil.getId() + "' as id,'" + obj.getPKeyId() + "' as p_key_id,");
+                        String[] split = colVal.split(",");
+                        for (int i = 0; i < split.length; i++) {
+                            String key = split[i];
+                            if (key.equals("id")) {
+                                split[i] = "'" + SnowFlakeUtil.getId() + "' as id";
+                            } else if (key.equals("p_key_id")) {
+                                split[i] = "'" + obj.getPKeyId() + "' as p_key_id";
+                            }
+                        }
+                        colVal = String.join(",", split);
                         //delete SQL (先删除旧数据,再新增)
                         String delSql = "delete from " + tableName + " where p_key_id = " + obj.getPKeyId() + " ; ";
                         //insert into SQL
@@ -2882,7 +2949,16 @@ private void addCopyNodesAndTabsBuildData(List<WbsTreeContract> addNodeList, Lis
                                     StringBuilder copyDataSql = new StringBuilder();
                                     String col = queryProcessDataVO.getAncestors();
                                     String colVal = queryProcessDataVO.getAncestors();
-                                    colVal = colVal.replaceAll("id,p_key_id,", "'" + SnowFlakeUtil.getId() + "' as id,'" + objTab.getPKeyId() + "' as p_key_id,");
+                                    String[] split = colVal.split(",");
+                                    for (int i = 0; i < split.length; i++) {
+                                        String key = split[i];
+                                        if (key.equals("id")) {
+                                            split[i] = "'" + SnowFlakeUtil.getId() + "' as id";
+                                        } else if (key.equals("p_key_id")) {
+                                            split[i] = "'" + objTab.getPKeyId() + "' as p_key_id";
+                                        }
+                                    }
+                                    colVal = String.join(",", split);
                                     //delete SQL (先删除旧数据,再新增)
                                     String delSql = "delete from " + tableName + " where p_key_id = " + objTab.getPKeyId() + " ; ";
                                     //insert into SQL

+ 129 - 0
blade-service/blade-business/src/main/java/org/springblade/business/controller/TrialAutoNumberController.java

@@ -0,0 +1,129 @@
+/*
+ *      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.business.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import lombok.AllArgsConstructor;
+import javax.validation.Valid;
+
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.Func;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.RequestParam;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springblade.business.entity.TrialAutoNumber;
+import org.springblade.business.vo.TrialAutoNumberVO;
+import org.springblade.business.service.ITrialAutoNumberService;
+import org.springblade.core.boot.ctrl.BladeController;
+
+/**
+ *  控制器
+ *
+ * @author BladeX
+ * @since 2025-06-10
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/trialautonumber")
+@Api(value = "试验编号自增", tags = "试验编号自增")
+public class TrialAutoNumberController extends BladeController {
+
+	private final ITrialAutoNumberService trialAutoNumberService;
+
+	/**
+	 * 详情
+	 */
+	@GetMapping("/detail")
+	@ApiOperationSupport(order = 1)
+	@ApiOperation(value = "详情", notes = "传入trialAutoNumber")
+	public R<TrialAutoNumber> detail(TrialAutoNumber trialAutoNumber) {
+		TrialAutoNumber detail = trialAutoNumberService.getOne(Condition.getQueryWrapper(trialAutoNumber));
+		return R.data(detail);
+	}
+
+	/**
+	 * 分页
+	 */
+	@GetMapping("/list")
+	@ApiOperationSupport(order = 2)
+	@ApiOperation(value = "分页", notes = "传入trialAutoNumber")
+	public R<IPage<TrialAutoNumber>> list(TrialAutoNumber trialAutoNumber, Query query) {
+		IPage<TrialAutoNumber> pages = trialAutoNumberService.page(Condition.getPage(query), Condition.getQueryWrapper(trialAutoNumber));
+		return R.data(pages);
+	}
+
+	/**
+	 * 自定义分页
+	 */
+	@GetMapping("/page")
+	@ApiOperationSupport(order = 3)
+	@ApiOperation(value = "分页", notes = "传入trialAutoNumber")
+	public R<IPage<TrialAutoNumberVO>> page(TrialAutoNumberVO trialAutoNumber, Query query) {
+		IPage<TrialAutoNumberVO> pages = trialAutoNumberService.selectTrialAutoNumberPage(Condition.getPage(query), trialAutoNumber);
+		return R.data(pages);
+	}
+
+	/**
+	 * 新增
+	 */
+	@PostMapping("/save")
+	@ApiOperationSupport(order = 4)
+	@ApiOperation(value = "新增", notes = "传入trialAutoNumber")
+	public R save(@Valid @RequestBody TrialAutoNumber trialAutoNumber) {
+		return R.status(trialAutoNumberService.save(trialAutoNumber));
+	}
+
+	/**
+	 * 修改
+	 */
+	@PostMapping("/update")
+	@ApiOperationSupport(order = 5)
+	@ApiOperation(value = "修改", notes = "传入trialAutoNumber")
+	public R update(@Valid @RequestBody TrialAutoNumber trialAutoNumber) {
+		return R.status(trialAutoNumberService.updateById(trialAutoNumber));
+	}
+
+	/**
+	 * 新增或修改
+	 */
+	@PostMapping("/submit")
+	@ApiOperationSupport(order = 6)
+	@ApiOperation(value = "新增或修改", notes = "传入trialAutoNumber")
+	public R submit(@Valid @RequestBody TrialAutoNumber trialAutoNumber) {
+		return R.status(trialAutoNumberService.saveOrUpdate(trialAutoNumber));
+	}
+
+
+	/**
+	 * 删除
+	 */
+	@PostMapping("/remove")
+	@ApiOperationSupport(order = 7)
+	@ApiOperation(value = "逻辑删除", notes = "传入ids")
+	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+		return R.status(trialAutoNumberService.deleteLogic(Func.toLongList(ids)));
+	}
+
+
+
+
+}

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

@@ -90,7 +90,7 @@ public class TrialMaterialController extends BladeController {
     @PostMapping("/mobilization/submit")
     @ApiOperationSupport(order = 5)
     @ApiOperation(value = "进场材料新增或修改", notes = "传入TrialMaterialMobilization对象")
-    public R<Object> mobilizationSubmit(@Valid @RequestBody TrialMaterialMobilization obj) {
+    public R<Object> mobilizationSubmit(@Valid @RequestBody TrialMaterialMobilizationDTO obj) {
         return R.status(iTrialMaterialMobilizationService.mobilizationSubmit(obj));
     }
 

+ 347 - 0
blade-service/blade-business/src/main/java/org/springblade/business/controller/TrialNumberRuleController.java

@@ -0,0 +1,347 @@
+/*
+ *      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.business.controller;
+
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.models.auth.In;
+import lombok.AllArgsConstructor;
+import javax.validation.Valid;
+
+import org.springblade.business.dto.TrialNumberRuleDTO;
+import org.springblade.business.mapper.TrialNumberRuleMapper;
+import org.springblade.business.vo.TrialNumberRuleVO1;
+import org.springblade.common.utils.SnowFlakeUtil;
+import org.springblade.core.log.exception.ServiceException;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.secure.BladeUser;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.ObjectUtil;
+import org.springblade.manager.entity.WbsTreePrivate;
+import org.springframework.beans.BeanUtils;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.RequestParam;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springblade.business.entity.TrialNumberRule;
+import org.springblade.business.vo.TrialNumberRuleVO;
+import org.springblade.business.service.ITrialNumberRuleService;
+import org.springblade.core.boot.ctrl.BladeController;
+
+import java.io.FileNotFoundException;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ *  控制器
+ *
+ * @author BladeX
+ * @since 2025-06-10
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/trialnumberrule")
+@Api(value = "试验编号规则", tags = "试验编号规则")
+public class TrialNumberRuleController extends BladeController {
+
+	private final ITrialNumberRuleService trialNumberRuleService;
+    private final TrialNumberRuleMapper  trialNumberRuleMapper;
+    private final JdbcTemplate jdbcTemplate;
+
+	/**
+	 * 详情
+	 */
+//	@GetMapping("/detail")
+//	@ApiOperationSupport(order = 1)
+//	@ApiOperation(value = "详情", notes = "传入trialNumberRule")
+//	public R<TrialNumberRule> detail(TrialNumberRule trialNumberRule) {
+//		TrialNumberRule detail = trialNumberRuleService.getOne(Condition.getQueryWrapper(trialNumberRule));
+//		return R.data(detail);
+//	}
+//
+//	/**
+//	 * 分页
+//	 */
+//	@GetMapping("/list")
+//	@ApiOperationSupport(order = 2)
+//	@ApiOperation(value = "分页", notes = "传入trialNumberRule")
+//	public R<IPage<TrialNumberRule>> list(TrialNumberRule trialNumberRule, Query query) {
+//		IPage<TrialNumberRule> pages = trialNumberRuleService.page(Condition.getPage(query), Condition.getQueryWrapper(trialNumberRule));
+//		return R.data(pages);
+//	}
+
+	/**
+	 * 自定义分页
+	 */
+//	@GetMapping("/page")
+//	@ApiOperationSupport(order = 3)
+//	@ApiOperation(value = "分页", notes = "传入trialNumberRule")
+//	public R<IPage<TrialNumberRuleVO>> page(TrialNumberRuleVO trialNumberRule, Query query) {
+//		IPage<TrialNumberRuleVO> pages = trialNumberRuleService.selectTrialNumberRulePage(Condition.getPage(query), trialNumberRule);
+//		return R.data(pages);
+//	}
+
+	/**
+	 * 新增
+	 */
+	@PostMapping("/save")
+	@ApiOperationSupport(order = 4)
+	@ApiOperation(value = "新增", notes = "传入trialNumberRule")
+	public R<String> save(@Valid @RequestBody TrialNumberRule trialNumberRule) {
+        if(trialNumberRule.getRule()==6){
+            if(StringUtils.isEmpty(trialNumberRule.getData())){
+                throw new ServiceException("数据填充不能为空");
+            }
+            String data = trialNumberRule.getData();
+            if (!data.matches("\\d+")) {
+                throw new ServiceException("数据填充只能为数字且不能有其他字符");
+            }
+        }
+        Integer maxSort=trialNumberRuleMapper.selectMaxSort(trialNumberRule.getProjectId(),trialNumberRule.getContractId(),trialNumberRule.getType());
+        List<TrialNumberRule> rules = trialNumberRuleMapper.selectList(Wrappers.<TrialNumberRule>query().lambda().eq(TrialNumberRule::getProjectId, trialNumberRule.getProjectId()).eq(TrialNumberRule::getContractId, trialNumberRule.getContractId()).eq(TrialNumberRule::getType, trialNumberRule.getType()));
+        if(!rules.isEmpty()){
+            for (TrialNumberRule rule : rules) {
+                if(Objects.equals(rule.getRule(), trialNumberRule.getRule())&&trialNumberRule.getRule()==6){
+                    throw new ServiceException("已存在流水号规则");
+                }
+            }
+        }
+        trialNumberRule.setSort(maxSort+1);
+        if(trialNumberRule.getContractId()==null||trialNumberRule.getContractId()==0L){
+            trialNumberRule.setStatus(1);
+        }else {
+            trialNumberRule.setStatus(2);
+        }
+        trialNumberRuleService.save(trialNumberRule);
+        if(trialNumberRule.getContractId()!=0L){
+            trialNumberRuleService.clearTrialNumber(trialNumberRule.getProjectId(),trialNumberRule.getContractId(),trialNumberRule.getType());
+        }
+        Map<String, String> map = trialNumberRuleService.getTrialNumber(trialNumberRule.getProjectId(),trialNumberRule.getContractId(), trialNumberRule.getType(), null, false);
+		return R.data(map.get("trialNumber"));
+	}
+
+    @PostMapping("/submitList")
+    public R<String> saveList(@RequestBody List<TrialNumberRule>list){
+        List<TrialNumberRule> collect = list.stream().filter(rule -> rule.getRule() == 6).collect(Collectors.toList());
+        if(collect.size()>1){
+            throw new ServiceException("流水只保存一个,不可保存多个");
+        }
+        List<TrialNumberRule> rules = trialNumberRuleMapper.selectList(Wrappers.<TrialNumberRule>query().lambda().eq(TrialNumberRule::getProjectId, list.get(0).getProjectId()).eq(TrialNumberRule::getContractId, list.get(0).getContractId()).eq(TrialNumberRule::getType, list.get(0).getType()));
+        List<TrialNumberRule> collect1 = rules.stream().filter(rule -> rule.getRule() == 6).collect(Collectors.toList());
+        TrialNumberRule rule6 = null;
+        if(collect1.size()>0){
+            rule6=collect1.get(0);
+        }
+        int i=1;
+        for (TrialNumberRule rule : list) {
+            if(rule.getContractId()==null||rule.getContractId()==0L){
+                rule.setStatus(1);
+            }else {
+                rule.setStatus(2);
+            }
+            rule.setSort(i++);
+            if(rule.getRule()==6){
+                if(StringUtils.isEmpty(rule.getData())){
+                    throw new ServiceException("数据填充不能为空");
+                }
+                String data = rule.getData();
+                if (!data.matches("\\d+")) {
+                    throw new ServiceException("数据填充只能为数字且不能有其他字符");
+                }
+                if(rule6!=null){
+                    if(rule.getId()!=null&&rule.getId().equals(rule6.getId())){
+                        if(rule.getContractId()!=null&&rule.getContractId()!=0L){
+                            if(!StringUtils.equals(rule.getData(),rule6.getData())){
+                                trialNumberRuleMapper.updateAutoIncrement(rule.getId());
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        trialNumberRuleService.saveOrUpdateBatch(list);
+        Map<String, String> map = trialNumberRuleService.getTrialNumber(list.get(0).getProjectId(),list.get(0).getContractId(), list.get(0).getType(), null, false);
+        return R.data(map.get("trialNumber"));
+    }
+
+	/**
+	 * 修改
+	 */
+	@PostMapping("/update")
+	@ApiOperationSupport(order = 5)
+	@ApiOperation(value = "修改", notes = "传入trialNumberRule")
+	public R<String> update(@Valid @RequestBody TrialNumberRule trialNumberRule) {
+        if(trialNumberRule.getRule()==6){
+            if(StringUtils.isEmpty(trialNumberRule.getData())){
+                throw new ServiceException("数据填充不能为空");
+            }
+            String data = trialNumberRule.getData();
+            if (!data.matches("\\d+")) {
+                throw new ServiceException("数据填充只能为数字且不能有其他字符");
+            }
+        }
+        List<TrialNumberRule> rules = trialNumberRuleMapper.selectList(Wrappers.<TrialNumberRule>query().lambda().eq(TrialNumberRule::getProjectId, trialNumberRule.getProjectId()).eq(TrialNumberRule::getContractId, trialNumberRule.getContractId()).eq(TrialNumberRule::getType, trialNumberRule.getType()));
+        if(!rules.isEmpty()){
+            for (TrialNumberRule rule : rules) {
+                if(!Objects.equals(rule.getId(), trialNumberRule.getId())&&trialNumberRule.getRule()==6&&rule.getRule()==6){
+                    throw new ServiceException("已存在流水号规则");
+                }
+            }
+        }
+        if(trialNumberRule.getRule()==6){
+            //查出流水号规则
+            TrialNumberRule trialNumberRule1 = trialNumberRuleService.getById(trialNumberRule.getId());
+            //如果是合同段的规则
+            if(trialNumberRule.getContractId()!=null&&trialNumberRule.getContractId()!=0L){
+                //并且数据填充发生改变
+                if(!StringUtils.equals(trialNumberRule1.getData(),trialNumberRule.getData())){
+                    //将自增表的数据删除
+                    trialNumberRuleMapper.updateAutoIncrement(trialNumberRule.getId());
+                }
+            }
+        }
+        trialNumberRuleService.updateById(trialNumberRule);
+        Map<String, String> map = trialNumberRuleService.getTrialNumber(trialNumberRule.getProjectId(),trialNumberRule.getContractId(), trialNumberRule.getType(), null, false);
+		return R.data(map.get("trialNumber"));
+	}
+
+	/**
+	 * 调整排序
+	 */
+	@PostMapping("/sort")
+	@ApiOperationSupport(order = 6)
+	@ApiOperation(value = "调整排序", notes = "传入List<TrialNumberRule>")
+	public R<String> sort(@Valid @RequestBody List<TrialNumberRule> trialNumberRules) {
+        for (int i = 0; i < trialNumberRules.size(); i++) {
+            trialNumberRules.get(i).setSort(i+1);
+        }
+        trialNumberRuleService.saveOrUpdateBatch(trialNumberRules);
+        if(ObjectUtil.isNotEmpty(trialNumberRules.get(0).getContractId())&&trialNumberRules.get(0).getContractId()!=0L){
+            trialNumberRuleService.clearTrialNumber(trialNumberRules.get(0).getProjectId(),trialNumberRules.get(0).getContractId(),trialNumberRules.get(0).getType());
+        }
+        Map<String, String> map = trialNumberRuleService.getTrialNumber(trialNumberRules.get(0).getProjectId(),trialNumberRules.get(0).getContractId(), trialNumberRules.get(0).getType(), null, false);
+        return R.data(map.get("trialNumber"));
+	}
+
+
+    /**
+     * 新增或修改
+     */
+//    @PostMapping("/submit")
+//    @ApiOperationSupport(order = 6)
+//    @ApiOperation(value = "新增或修改", notes = "传入trialNumberRule")
+//    public R<String> submit(@Valid @RequestBody TrialNumberRule trialNumberRule,BladeUser bladeUser) {
+//
+//
+//
+//
+//        return null;
+//    }
+
+
+	/**
+	 * 删除
+	 */
+	@PostMapping("/remove")
+	@ApiOperationSupport(order = 7)
+	@ApiOperation(value = "逻辑删除", notes = "传入ids")
+	public R<String> remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+        String[] idss = ids.split(",");
+        TrialNumberRule trialNumberRule = trialNumberRuleService.getById(idss[0]);
+        trialNumberRuleService.clearTrialNumber(trialNumberRule.getProjectId(),trialNumberRule.getContractId(),trialNumberRule.getType());
+        trialNumberRuleService.deleteLogic(Func.toLongList(ids));
+        Map<String, String> map = trialNumberRuleService.getTrialNumber(trialNumberRule.getProjectId(),trialNumberRule.getContractId(), trialNumberRule.getType(), null, false);
+		return R.data(map.get("trialNumber"));
+	}
+
+
+
+
+    /**
+     * type 1材料 2样品  4记录表 5报告表
+     * 委托单另外一个方法单独获取
+     */
+    @GetMapping("/getTrialNumber")
+    @ApiOperationSupport(order = 8)
+    @ApiOperation(value = "获取试验编号", notes = "传入projectId,contractId,type,nodeId")
+    public R<Map<String, String>> getTrialNumber(Long projectId,Long contractId, Integer type, Long nodeId){
+        Map<String, String> map = trialNumberRuleService.getTrialNumber(projectId,contractId, type, nodeId, true);
+        return  R.data(map);
+    }
+    @GetMapping("/getEntrustNumber")
+    @ApiOperationSupport(order = 11)
+    @ApiOperation(value = "获取委托单编号")
+    public R<Map<String, String>>getEntrustNumber(Long pkeyId,Long contractId) throws FileNotFoundException {
+        return R.data(trialNumberRuleService.getEntrustNumber(pkeyId,contractId));
+    }
+
+    /**
+     * 获取试验编号规则
+     * @param
+     * @param contractId
+     * @param type
+     * @return
+     */
+    @GetMapping("/getTrialNumberRule")
+    @ApiOperationSupport(order = 9)
+    @ApiOperation(value = "获取试验编号规则", notes = "传入projectId,contractId(后管查询传0),type")
+    public R<TrialNumberRuleVO1> getTrialNumberRule(Long projectId,Long contractId, Integer type){
+        return R.data(trialNumberRuleService.getTrialNumberRule(projectId,contractId,type));
+    }
+
+    @GetMapping("/reTrialNumberRule")
+    @ApiOperationSupport(order = 10)
+    @ApiOperation(value = "重置试验编号规则")
+    public R<String> reTrialNumberRule(Long projectId, Long contractId, Integer type){
+        List<TrialNumberRule> trialNumberRules = trialNumberRuleService.getBaseMapper().selectList(Wrappers.<TrialNumberRule>query().lambda().eq(TrialNumberRule::getProjectId, projectId).eq(TrialNumberRule::getContractId, contractId).eq(TrialNumberRule::getType, type).eq(TrialNumberRule::getStatus,2).orderByAsc(TrialNumberRule::getSort));
+        if(!trialNumberRules.isEmpty()){
+            String ids = trialNumberRules.stream()
+                    .map(o -> o.getId().toString())
+                    .collect(Collectors.joining(","));
+            TrialNumberRule trialNumberRule = trialNumberRules.get(0);
+            trialNumberRuleService.clearTrialNumber(trialNumberRule.getProjectId(),trialNumberRule.getContractId(),trialNumberRule.getType());
+            trialNumberRuleService.deleteLogic(Func.toLongList(ids));
+        }
+        List<TrialNumberRule> rules = trialNumberRuleService.getBaseMapper().selectList(Wrappers.<TrialNumberRule>query().lambda().eq(TrialNumberRule::getProjectId, projectId).eq(TrialNumberRule::getType, type).eq(TrialNumberRule::getStatus, 1).orderByAsc(TrialNumberRule::getSort));
+        if(!rules.isEmpty()){
+            for (TrialNumberRule rule : rules) {
+                rule.setId(null);
+                rule.setStatus(2);
+                rule.setContractId(contractId);
+            }
+            trialNumberRuleService.saveOrUpdateBatch(rules);
+            Map<String, String> map = trialNumberRuleService.getTrialNumber(projectId,contractId, type, null, false);
+            return R.data(map.get("trialNumber"));
+        }else {
+            return R.fail("请先在后管设置编号规则");
+        }
+    }
+
+
+
+
+
+
+}

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

@@ -346,4 +346,9 @@ public class ArchiveFileClientImpl implements ArchiveFileClient {
         iArchiveFileService.save(archiveFile);
     }
 
+    @Override
+    public List<ArchiveFile> getArchiveFileByArchiveIds(String archiveIds) {
+        return iArchiveFileService.getArchiveFileByArchivesId(archiveIds,null);
+    }
+
 }

+ 3 - 2
blade-service/blade-business/src/main/java/org/springblade/business/feignClient/InformationQueryClientImpl.java

@@ -127,10 +127,11 @@ public class InformationQueryClientImpl implements InformationQueryClient {
     }
 
     @Override
-    public InformationQuery getInfoByWbsId(Long wbsId) {
-        return informationQueryMapper.selectOne(new QueryWrapper<InformationQuery>().eq("wbs_id",wbsId));
+    public InformationQuery getInfoByWbsId(Long wbsId,Integer classify) {
+        return informationQueryMapper.selectOne(new QueryWrapper<InformationQuery>().eq("wbs_id",wbsId).eq("classify",classify));
     }
 
+
     @Override
     public void update(InformationQuery iq) {
         informationQueryMapper.updateById(iq);

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

@@ -57,6 +57,7 @@
         <result column="is_element" property="isElement"/>
         <result column="pdf_page_url" property="pdfPageUrl"/>
         <result column="fid" property="fid"/>
+        <result column="archive_sort" property="archiveSort"/>
         <result column="rectification" property="rectification"/>
         <result column="m_wbs_tree_contract_p_key_id" property="mWbsTreeContractPKeyId"/>
         <result column="u_image_classification_file_id" property="uImageClassificationFileId"/>
@@ -93,6 +94,16 @@
         <if test="vo.sourceType != null and vo.sourceType != ''">
             and u.source_type = #{vo.sourceType}
         </if>
+        <if test="vo.isArchive != null and vo.isArchive != ''">
+            <choose>
+                <when test="vo.isArchive == 0">
+                    AND (u.is_archive = #{vo.isArchive} OR u.is_archive IS NULL)
+                </when>
+                <otherwise>
+                    AND u.is_archive = #{vo.isArchive}
+                </otherwise>
+            </choose>
+        </if>
         <if test="vo.rectification == null and vo.archiveId == null">
             and (u.is_auto_file is null or u.is_auto_file != 1)
         </if>
@@ -166,7 +177,16 @@
         <if test="vo.sourceType != null and vo.sourceType != ''">
             and u.source_type = #{vo.sourceType}
         </if>
-
+        <if test="vo.isArchive != null and vo.isArchive != ''">
+            <choose>
+                <when test="vo.isArchive == 0">
+                    AND (u.is_archive = #{vo.isArchive} OR u.is_archive IS NULL)
+                </when>
+                <otherwise>
+                    AND u.is_archive = #{vo.isArchive}
+                </otherwise>
+            </choose>
+        </if>
         <if test="vo.rectification == null and vo.archiveId == null">
             and (u.is_auto_file is null or u.is_auto_file != 1)
         </if>
@@ -357,7 +377,7 @@
                 #{id}
             </foreach>
         </if>
-        order by sort,sort_num,create_time
+        order by archive_sort,sort,sort_num,create_time
     </select>
     <select id="getArchiveFileByFileIds" resultMap="archiveFileResultMap">
         select * from u_archive_file where is_deleted = 0
@@ -367,7 +387,7 @@
                 #{id}
             </foreach>
         </if>
-        order by sort,sort_num,create_time
+        order by archive_sort,sort,sort_num,create_time
     </select>
     <select id="getListByProjectId" resultType="org.springblade.business.entity.ArchiveFile">
         select *
@@ -421,7 +441,7 @@
         from u_archive_file
         where archive_id = #{archiveId}
           and is_deleted = 0
-        order by sort,sort_num,create_time
+        order by archive_sort,sort,sort_num,create_time
     </select>
 
 

+ 44 - 0
blade-service/blade-business/src/main/java/org/springblade/business/mapper/TrialAutoNumberMapper.java

@@ -0,0 +1,44 @@
+/*
+ *      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.business.mapper;
+
+import org.apache.ibatis.annotations.Param;
+import org.springblade.business.entity.TrialAutoNumber;
+import org.springblade.business.vo.TrialAutoNumberVO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import java.util.List;
+
+/**
+ *  Mapper 接口
+ *
+ * @author BladeX
+ * @since 2025-06-10
+ */
+public interface TrialAutoNumberMapper extends BaseMapper<TrialAutoNumber> {
+
+	/**
+	 * 自定义分页
+	 *
+	 * @param page
+	 * @param trialAutoNumber
+	 * @return
+	 */
+	List<TrialAutoNumberVO> selectTrialAutoNumberPage(IPage page, TrialAutoNumberVO trialAutoNumber);
+
+    void clearTrialAutoNumber(@Param("nameRuleId") Long nameRuleId);
+}

+ 22 - 0
blade-service/blade-business/src/main/java/org/springblade/business/mapper/TrialAutoNumberMapper.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.business.mapper.TrialAutoNumberMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="trialAutoNumberResultMap" type="org.springblade.business.entity.TrialAutoNumber">
+        <result column="id" property="id"/>
+        <result column="is_deleted" property="isDeleted"/>
+        <result column="auto_increment_number" property="autoIncrementNumber"/>
+        <result column="form_data_id" property="formDataId"/>
+        <result column="type" property="type"/>
+    </resultMap>
+    <update id="clearTrialAutoNumber">
+        update u_trial_auto_number set is_deleted = 1 where name_rule_id = #{nameRuleId}
+    </update>
+
+
+    <select id="selectTrialAutoNumberPage" resultMap="trialAutoNumberResultMap">
+        select * from u_trial_auto_number where is_deleted = 0
+    </select>
+
+</mapper>

+ 46 - 0
blade-service/blade-business/src/main/java/org/springblade/business/mapper/TrialNumberRuleMapper.java

@@ -0,0 +1,46 @@
+/*
+ *      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.business.mapper;
+
+import org.apache.ibatis.annotations.Param;
+import org.springblade.business.entity.TrialNumberRule;
+import org.springblade.business.vo.TrialNumberRuleVO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import java.util.List;
+
+/**
+ *  Mapper 接口
+ *
+ * @author BladeX
+ * @since 2025-06-10
+ */
+public interface TrialNumberRuleMapper extends BaseMapper<TrialNumberRule> {
+
+	/**
+	 * 自定义分页
+	 *
+	 * @param page
+	 * @param trialNumberRule
+	 * @return
+	 */
+	List<TrialNumberRuleVO> selectTrialNumberRulePage(IPage page, TrialNumberRuleVO trialNumberRule);
+
+    Integer selectMaxSort(@Param("projectId") Long projectId, @Param("contractId") Long contractId, @Param("type") Integer type);
+
+    void updateAutoIncrement(@Param("id") Long id);
+}

+ 34 - 0
blade-service/blade-business/src/main/java/org/springblade/business/mapper/TrialNumberRuleMapper.xml

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.business.mapper.TrialNumberRuleMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="trialNumberRuleResultMap" type="org.springblade.business.entity.TrialNumberRule">
+        <result column="id" property="id"/>
+        <result column="create_time" property="createTime"/>
+        <result column="create_user" property="createUser"/>
+        <result column="create_dept" property="createDept"/>
+        <result column="update_user" property="updateUser"/>
+        <result column="update_time" property="updateTime"/>
+        <result column="status" property="status"/>
+        <result column="is_deleted" property="isDeleted"/>
+        <result column="project_id" property="projectId"/>
+        <result column="contract_id" property="contractId"/>
+        <result column="type" property="type"/>
+        <result column="rule" property="rule"/>
+        <result column="data" property="data"/>
+        <result column="is_auto_increment" property="isAutoIncrement"/>
+    </resultMap>
+    <update id="updateAutoIncrement">
+        update u_trial_auto_number set is_deleted=1 where number_rule_id = #{id}
+    </update>
+
+
+    <select id="selectTrialNumberRulePage" resultMap="trialNumberRuleResultMap">
+        select * from u_trial_number_rule where is_deleted = 0
+    </select>
+    <select id="selectMaxSort" resultType="java.lang.Integer">
+        select IFNULL(MAX(sort), 0) from u_trial_number_rule where project_id = #{projectId} and contract_id = #{contractId} and type = #{type}
+    </select>
+
+</mapper>

+ 41 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/ITrialAutoNumberService.java

@@ -0,0 +1,41 @@
+/*
+ *      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.business.service;
+
+import org.springblade.business.entity.TrialAutoNumber;
+import org.springblade.business.vo.TrialAutoNumberVO;
+import org.springblade.core.mp.base.BaseService;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+/**
+ *  服务类
+ *
+ * @author BladeX
+ * @since 2025-06-10
+ */
+public interface ITrialAutoNumberService extends BaseService<TrialAutoNumber> {
+
+	/**
+	 * 自定义分页
+	 *
+	 * @param page
+	 * @param trialAutoNumber
+	 * @return
+	 */
+	IPage<TrialAutoNumberVO> selectTrialAutoNumberPage(IPage<TrialAutoNumberVO> page, TrialAutoNumberVO trialAutoNumber);
+
+}

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

@@ -17,7 +17,7 @@ public interface ITrialMaterialMobilizationService extends BaseService<TrialMate
 
     boolean mobilizationVerification(String number, String id, String contractId);
 
-    boolean mobilizationSubmit(TrialMaterialMobilization obj);
+    boolean mobilizationSubmit(TrialMaterialMobilizationDTO obj);
 
     TrialMaterialMobilization mobilizationDetail(Long id);
 

+ 59 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/ITrialNumberRuleService.java

@@ -0,0 +1,59 @@
+/*
+ *      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.business.service;
+
+import cn.hutool.core.lang.hash.Hash;
+import org.springblade.business.entity.TrialNumberRule;
+import org.springblade.business.vo.TrialNumberRuleVO;
+import org.springblade.business.vo.TrialNumberRuleVO1;
+import org.springblade.core.mp.base.BaseService;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springblade.core.secure.BladeUser;
+
+import java.io.FileNotFoundException;
+import java.util.Map;
+
+/**
+ *  服务类
+ *
+ * @author BladeX
+ * @since 2025-06-10
+ */
+public interface ITrialNumberRuleService extends BaseService<TrialNumberRule> {
+
+	/**
+	 * 自定义分页
+	 *
+	 * @param page
+	 * @param trialNumberRule
+	 * @return
+	 */
+	IPage<TrialNumberRuleVO> selectTrialNumberRulePage(IPage<TrialNumberRuleVO> page, TrialNumberRuleVO trialNumberRule);
+
+    Map<String,String> getTrialNumber(Long projectId,Long contractId, Integer type, Long nodeId, Boolean isSaveRedis);
+
+    TrialNumberRuleVO1 getTrialNumberRule(Long project,Long contractId, Integer type);
+    //编号规则发生改变,清空对应的编号
+    boolean clearTrialNumber(Long projectId, Long contractId, Integer type);
+
+	boolean checkTrialNumberIsExist(String trialNumber,Integer type,Long contractId);
+
+
+    Map<String, String> getEntrustNumber(Long pkeyId,Long contractId) throws FileNotFoundException;
+
+	void checkSave(Long contractId, int i, Long id, String autoIncrementNumber);
+}

+ 7 - 2
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/ArchiveFileServiceImpl.java

@@ -72,6 +72,7 @@ public class ArchiveFileServiceImpl extends BaseServiceImpl<ArchiveFileMapper, A
         pageVoList.forEach(vos -> {
             vos.setIsApprovalValue(new Integer("0").equals(vos.getStatus()) ? "未上报" : new Integer("1").equals(vos.getStatus()) ? "待审批" : new Integer("2").equals(vos.getStatus()) ? "已审批" : "已废除");
             vos.setIsCertificationValue(new Integer("1").equals(vos.getIsCertification()) ? "已认证" : "未认证");
+            vos.setIsArchive(vos.getIsArchive()==null?0: vos.getIsArchive());
             if (StringUtils.isNotEmpty(vos.getSheetSource())) {
                 sheetSourceList.forEach(source -> {
                     if (source.getDictKey().equals(vos.getSheetSource())) {
@@ -165,8 +166,12 @@ public class ArchiveFileServiceImpl extends BaseServiceImpl<ArchiveFileMapper, A
         }
         for (ArchiveFile vo : list) {
             // 修改所有的认证状态,如果是不需要认证就设置为已认证,如果是需要认证就设置为未认证
-            if (Func.isNotEmpty(vo.getIsNeedCertification()) && vo.getIsNeedCertification() == 0){
-                vo.setIsCertification(1);
+            if (Func.isNotEmpty(vo.getIsNeedCertification())){
+                if (vo.getIsNeedCertification() == 0) {
+                    vo.setIsCertification(1);
+                } else if (vo.getIsNeedCertification() == 1) {
+                    vo.setIsCertification(0);
+                }
             }
             //循环查看是否把需要审批改为不需要审批,  不可能把不需要审批改为需要审批 ,0不需要,1需要
             if (vo.getStatus() == 0 && vo.getIsApproval() == 0) {

+ 67 - 43
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/EntrustInfoServiceImpl.java

@@ -28,6 +28,7 @@ import org.springblade.business.feign.OperationLogClient;
 import org.springblade.business.mapper.EntrustInfoMapper;
 import org.springblade.business.service.IEntrustInfoService;
 import org.springblade.business.service.IInformationQueryService;
+import org.springblade.business.service.ITrialNumberRuleService;
 import org.springblade.business.vo.EntrustDataInfoVO;
 import org.springblade.business.vo.EntrustInfoVO;
 import org.springblade.business.vo.LoadDataInfoVO;
@@ -68,6 +69,7 @@ public class EntrustInfoServiceImpl extends BaseServiceImpl<EntrustInfoMapper, E
 	private final EntrustInfoMapper entrustInfoMapper;
     private final IInformationQueryService informationQueryService;
 	private final OperationLogClient operationLogClient;
+	private final ITrialNumberRuleService trialNumberRuleService;
 
     @Override
 	public IPage<EntrustInfoVO> selectEntrustInfoPage(IPage<EntrustInfoVO> page, EntrustInfoVO entrustInfo) {
@@ -122,22 +124,22 @@ public class EntrustInfoServiceImpl extends BaseServiceImpl<EntrustInfoMapper, E
 		}
 		String sampleId = "";
 		String contractId = "";
-        String sqlNodeName="select node_name, node_type from m_wbs_tree_private where p_key_id="+dataInfo.getString("nodeId");
+		String sqlNodeName="select node_name, node_type from m_wbs_tree_private where p_key_id="+dataInfo.getString("nodeId");
 		Map<String, Object> wbsTreePrivateMap = jdbcTemplate.queryForMap(sqlNodeName);
 		String nodeName = wbsTreePrivateMap.get("node_name").toString();
 		String nodeType = wbsTreePrivateMap.get("node_type").toString();
-		if(!"51".equals(nodeType) && !nodeName.equals("回弹法检测混凝土抗压强度")&&!nodeName.equals("路基压实度")&&!nodeName.equals("地基承载力")&&!nodeName.equals("路基路面弯沉")&&!nodeName.equals("锚杆")&&!nodeName.equals("喷射混凝土厚度")){
-            // 创建 委托单信息
-            if(!dataInfo.containsKey("sampleId")){
-                return R.fail("取样信息为sampleId不存在");
-            }else{
-                sampleId = dataInfo.getString("sampleId");
-            }
-        }else {
-            if(dataInfo.containsKey("sampleId")){
-                sampleId = dataInfo.getString("sampleId");
-            }
-        }
+		if(!"51".equals(nodeType)){
+			// 创建 委托单信息
+			if(!dataInfo.containsKey("sampleId")){
+				return R.fail("取样信息为sampleId不存在");
+			}else{
+				sampleId = dataInfo.getString("sampleId");
+			}
+		}else {
+			if(dataInfo.containsKey("sampleId")){
+				sampleId = dataInfo.getString("sampleId");
+			}
+		}
 		if(!dataInfo.containsKey("contractId")){
 			return R.fail("取样信息为contractId不存在");
 		}else{
@@ -146,24 +148,26 @@ public class EntrustInfoServiceImpl extends BaseServiceImpl<EntrustInfoMapper, E
 
 		String nodeErTreeId = dataInfo.getString("nodeErTreeId");
 
-        EntrustInfo entrustInfo=new EntrustInfo();
+		EntrustInfo entrustInfo=new EntrustInfo();
 		// 保存数据文件
-        if(!dataInfo.containsKey("sampleId")){
-            entrustInfo.setSampleStatus("0");
-        }else {
-            if(!"51".equals(nodeType) && !nodeName.equals("回弹法检测混凝土抗压强度")&&!nodeName.equals("路基压实度")&&!nodeName.equals("地基承载力")&&!nodeName.equals("路基路面弯沉")&&!nodeName.equals("锚杆")){
-                entrustInfo = baseMapper.selectOne(Wrappers.<EntrustInfo>query().lambda().eq(EntrustInfo::getSampleId, sampleId).eq(EntrustInfo::getContractId,contractId));
-            }else {
-                entrustInfo = baseMapper.selectOne(Wrappers.<EntrustInfo>query().lambda().eq(EntrustInfo::getId,dataInfo.get("id")).eq(EntrustInfo::getContractId,contractId));
-            }
-            if(entrustInfo==null && Func.isEmpty(entrustInfo)){
-                entrustInfo = new EntrustInfo();
-                //委托单未上报不进入样品流转 状态设置为0
-                entrustInfo.setSampleStatus("0");
-            }
-        }
+		if(!dataInfo.containsKey("sampleId")){
+			entrustInfo.setSampleStatus("0");
+		}else {
+			if(!"51".equals(nodeType)){
+				if (sampleId != null && !sampleId.isEmpty() && !"0".equals(sampleId)) {
+					entrustInfo = baseMapper.selectOne(Wrappers.<EntrustInfo>query().lambda().eq(EntrustInfo::getSampleId, sampleId).eq(EntrustInfo::getContractId,contractId));
+				}
+			}else {
+				entrustInfo = baseMapper.selectOne(Wrappers.<EntrustInfo>query().lambda().eq(EntrustInfo::getId,dataInfo.get("id")).eq(EntrustInfo::getContractId,contractId));
+			}
+			if(entrustInfo==null && Func.isEmpty(entrustInfo)){
+				entrustInfo = new EntrustInfo();
+				//委托单未上报不进入样品流转 状态设置为0
+				entrustInfo.setSampleStatus("0");
+			}
+		}
 		//WbsTreePrivate wbsTreePrivate = wbsTreePrivateClient.getNodeByPrimaryKeyId(nodeErTreeId);
-        WbsTreePrivate wbsTreePrivate=jdbcTemplate.query("select * from m_wbs_tree_private where p_key_id="+nodeErTreeId+" and status=1",new BeanPropertyRowMapper<>(WbsTreePrivate.class)).get(0);
+		WbsTreePrivate wbsTreePrivate=jdbcTemplate.query("select * from m_wbs_tree_private where p_key_id="+nodeErTreeId+" and status=1",new BeanPropertyRowMapper<>(WbsTreePrivate.class)).get(0);
 		String sql ="select * from m_wbs_form_element where is_deleted = 0 and dynamic_dict in(500,501,502)  and f_id="+wbsTreePrivate.getInitTableId();
 		List<Map<String, Object>> wbsFormElements = jdbcTemplate.queryForList(sql);
 
@@ -188,23 +192,43 @@ public class EntrustInfoServiceImpl extends BaseServiceImpl<EntrustInfoMapper, E
 				}
 			}
 		}
-        entrustInfo.setNodeId(dataInfo.get("nodeId").toString());
+		entrustInfo.setNodeId(dataInfo.get("nodeId").toString());
 		entrustInfo.setEntrustName(wbsTreePrivate.getNodeName());
-        if(dataInfo.containsKey("id")){
-            entrustInfo.setId(Long.parseLong(dataInfo.get("id").toString()));
-        }
-        this.saveOrUpdate(entrustInfo);
+		if(dataInfo.containsKey("id")){
+			entrustInfo.setId(Long.parseLong(dataInfo.get("id").toString()));
+		}
+		if(!dataInfo.containsKey("id")){
+			boolean b =true;
+			if(StringUtils.isNotEmpty(entrustInfo.getEntrustNo())){
+				trialNumberRuleService.checkTrialNumberIsExist(entrustInfo.getEntrustNo(), 3,Long.parseLong(entrustInfo.getContractId()));
+			}
+			if(!b){
+				throw new ServiceException("委托单编号已存在");
+			}
+		}
+		this.saveOrUpdate(entrustInfo);
+		String autoIncrementNumber=dataInfo.get("autoIncrementNumber")==null?"":dataInfo.get("autoIncrementNumber").toString();
+		String trialAutoNumber=dataInfo.get("trialNumber")==null?"":dataInfo.get("trialNumber").toString();
+		String entrustNo=entrustInfo.getEntrustNo()==null?"":entrustInfo.getEntrustNo();
+		if(StringUtils.isNotEmpty(autoIncrementNumber)){
+			if(trialAutoNumber.equals(entrustNo)){
+				trialNumberRuleService.checkSave(Long.parseLong(entrustInfo.getContractId()), 3, entrustInfo.getId(), autoIncrementNumber);
+			}
+			//bladeRedis.del("trialAutoNumber:" + entrustInfo.getContractId() + ":" + 3 + ":" + entrustInfo.getId() + ":" + "lock:" + autoIncrementNumber);
+		}
 		dataInfo.put("groupId",entrustInfo.getId());
 		dataInfo.put("pkeyId", dataInfo.getString("nodeErTreeId"));
-        if(StringUtils.isEmpty(entrustInfo.getEntrustNo())){
-            entrustInfo.setEntrustNo("");
-        }
-        if(StringUtils.isEmpty(entrustInfo.getEntrustName())){
-            entrustInfo.setEntrustName("");
-        }
-        dataInfo.put("entrustInfoName",entrustInfo.getEntrustNo()+entrustInfo.getEntrustName());
-        String pdfUrl = excelTabClient.saveEntrustTabData(dataInfo);
-        return R.data(200,pdfUrl,"操作成功");
+		if(StringUtils.isEmpty(entrustInfo.getEntrustNo())){
+			entrustInfo.setEntrustNo("");
+		}
+		if(StringUtils.isEmpty(entrustInfo.getEntrustName())){
+			entrustInfo.setEntrustName("");
+		}
+		dataInfo.put("entrustInfoName",entrustInfo.getEntrustNo()+entrustInfo.getEntrustName());
+		dataInfo.remove("autoIncrementNumber");
+		dataInfo.remove("trialNumber");
+		String pdfUrl = excelTabClient.saveEntrustTabData(dataInfo);
+		return R.data(200,pdfUrl,"操作成功");
 	}
 
 	/**

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

@@ -713,7 +713,7 @@ public class TaskServiceImpl extends BaseServiceImpl<TaskMapper, Task> implement
                                 String[] idss = query.stream()
                                         .map(item -> String.valueOf(item.getId()))
                                         .toArray(String[]::new);
-                                String update = "update u_entrust_info set status=3 where id in(" + String.join(",", idss) + ")";
+                                String update = "update u_entrust_info set status=4 where id in(" + String.join(",", idss) + ")";
                                 jdbcTemplate.execute(update);
                             }
                         }
@@ -2048,6 +2048,11 @@ public class TaskServiceImpl extends BaseServiceImpl<TaskMapper, Task> implement
 
                     }
 
+                    /*if(type == 3 && task.getApprovalType()== 9){
+
+                        result = excelTabClient.synPdfKeyInfo(contractId, task.getFormDataId(), classify, projectId, header);
+
+                    }else*/
                     if (type == 1) {
                         //重新保存
                         long startTime_1 = System.currentTimeMillis();
@@ -2150,6 +2155,8 @@ public class TaskServiceImpl extends BaseServiceImpl<TaskMapper, Task> implement
         return excelTabClient.synPDFInfo(contractId, nodePKeyIds, classify, projectId, header);
     }
 
+
+
     /**
      * 返回true代表满足条件 是超级管理员并且部门是在泓创智诚下面的部门
      */

+ 45 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialAutoNumberServiceImpl.java

@@ -0,0 +1,45 @@
+/*
+ *      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.business.service.impl;
+
+import org.springblade.business.entity.TrialAutoNumber;
+import org.springblade.business.vo.TrialAutoNumberVO;
+import org.springblade.business.mapper.TrialAutoNumberMapper;
+import org.springblade.business.service.ITrialAutoNumberService;
+import org.springblade.core.mp.base.BaseServiceImpl;
+import org.springframework.stereotype.Service;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+/**
+ *  服务实现类
+ *
+ * @author BladeX
+ * @since 2025-06-10
+ */
+@Service
+public class TrialAutoNumberServiceImpl extends BaseServiceImpl<TrialAutoNumberMapper, TrialAutoNumber> implements ITrialAutoNumberService {
+
+	@Override
+	public IPage<TrialAutoNumberVO> selectTrialAutoNumberPage(IPage<TrialAutoNumberVO> page, TrialAutoNumberVO trialAutoNumber) {
+		return page.setRecords(baseMapper.selectTrialAutoNumberPage(page, trialAutoNumber));
+	}
+
+    public void clearTrialAutoNumber(Long nameRuleId){
+        baseMapper.clearTrialAutoNumber(nameRuleId);
+    }
+
+}

+ 19 - 2
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialMaterialMobilizationServiceImpl.java

@@ -22,6 +22,7 @@ import org.springblade.business.mapper.TrialMaterialMobilizationMapper;
 import org.springblade.business.mapper.TrialSampleInfoMapper;
 import org.springblade.business.mapper.TrialSamplingRecordMapper;
 import org.springblade.business.service.ITrialMaterialMobilizationService;
+import org.springblade.business.service.ITrialNumberRuleService;
 import org.springblade.business.utils.PDFUtil;
 import org.springblade.business.vo.TrialMaterialMobilizationVO;
 import org.springblade.business.vo.TrialSamplingRecordVO;
@@ -68,6 +69,7 @@ public class TrialMaterialMobilizationServiceImpl extends BaseServiceImpl<TrialM
     private final NewIOSSClient newIOSSClient;
     private final JdbcTemplate jdbcTemplate;
     private final CommonFileClient commonFileClient;
+    private final ITrialNumberRuleService trialNumberRuleService;
 
     @Override
     public boolean mobilizationVerification(String number, String id, String contractId) {
@@ -88,12 +90,27 @@ public class TrialMaterialMobilizationServiceImpl extends BaseServiceImpl<TrialM
     }
 
     @Override
-    public boolean mobilizationSubmit(TrialMaterialMobilization obj) {
+    public boolean mobilizationSubmit(TrialMaterialMobilizationDTO obj) {
         if (ObjectUtil.isEmpty(SecureUtil.getUserId())) {
             throw new ServiceException("获取用户信息失败");
         }
+        boolean b=true;
+        if(StringUtils.isNotEmpty(obj.getMaterialNumber())){
+            b= trialNumberRuleService.checkTrialNumberIsExist(obj.getMaterialNumber(), 1,obj.getContractId());
+        }
+        if(!b){
+            throw new ServiceException("编号已存在");
+        }
         obj.setUserId(SecureUtil.getUserId());
-        return this.saveOrUpdate(obj);
+        this.saveOrUpdate(obj);
+        if(StringUtils.isNotEmpty(obj.getAutoIncrementNumber())){
+            if(obj.getTrialNumber().equals(obj.getMaterialNumber())){
+                trialNumberRuleService.checkSave(obj.getContractId(), 1, obj.getId(), obj.getAutoIncrementNumber());
+            }
+            //bladeRedis.del("trialAutoNumber:" + obj.getContractId() + ":" + 1 + ":" + obj.getId() + ":" + "lock:" + obj.getAutoIncrementNumber());
+        }
+
+        return true;
     }
 
     @Override

+ 455 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialNumberRuleServiceImpl.java

@@ -0,0 +1,455 @@
+/*
+ *      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.business.service.impl;
+
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+import org.springblade.business.entity.TrialAutoNumber;
+import org.springblade.business.entity.TrialNumberRule;
+import org.springblade.business.vo.TrialNumberRuleVO;
+import org.springblade.business.mapper.TrialNumberRuleMapper;
+import org.springblade.business.service.ITrialNumberRuleService;
+import org.springblade.business.vo.TrialNumberRuleVO1;
+import org.springblade.common.constant.CommonConstant;
+import org.springblade.common.utils.CommonUtil;
+import org.springblade.common.utils.SnowFlakeUtil;
+import org.springblade.core.log.exception.ServiceException;
+import org.springblade.core.mp.base.BaseServiceImpl;
+import org.springblade.core.redis.cache.BladeRedis;
+import org.springblade.core.secure.BladeUser;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.IoUtil;
+import org.springblade.core.tool.utils.ResourceUtil;
+import org.springblade.manager.entity.ContractInfo;
+import org.springblade.manager.entity.WbsTreePrivate;
+import org.springblade.manager.feign.WbsTreePrivateClient;
+import org.springblade.system.cache.ParamCache;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.SingleColumnRowMapper;
+import org.springframework.stereotype.Service;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+import javax.annotation.Resource;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.time.LocalDate;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ *  服务实现类
+ *
+ * @author BladeX
+ * @since 2025-06-10
+ */
+@Service
+public class TrialNumberRuleServiceImpl extends BaseServiceImpl<TrialNumberRuleMapper, TrialNumberRule> implements ITrialNumberRuleService {
+
+    @Resource
+    private JdbcTemplate jdbcTemplate;
+    @Resource
+    private BladeRedis bladeRedis;
+    @Resource
+    private  TrialAutoNumberServiceImpl trialAutoNumberService;
+
+
+    @Override
+	public IPage<TrialNumberRuleVO> selectTrialNumberRulePage(IPage<TrialNumberRuleVO> page, TrialNumberRuleVO trialNumberRule) {
+		return page.setRecords(baseMapper.selectTrialNumberRulePage(page, trialNumberRule));
+	}
+
+    @Override
+    public Map<String,String> getTrialNumber(Long projectId,Long contractId, Integer type,Long nodeId,Boolean isSaveRedis) {
+        HashMap<String, String> map = new HashMap<>();
+        StringBuilder trialNumber = new StringBuilder();
+        List<TrialNumberRule> rules;
+        if(contractId==null||contractId==0L){
+            rules = baseMapper.selectList(Wrappers.<TrialNumberRule>query().lambda().eq(TrialNumberRule::getProjectId, projectId).eq(TrialNumberRule::getType, type).eq(TrialNumberRule::getStatus,1).orderByAsc(TrialNumberRule::getSort));
+        }else {
+             rules = baseMapper.selectList(Wrappers.<TrialNumberRule>query().lambda().eq(TrialNumberRule::getContractId, contractId).eq(TrialNumberRule::getType, type).eq(TrialNumberRule::getStatus,2).orderByAsc(TrialNumberRule::getSort));
+        }
+        boolean flag=true;
+        int i=1;
+        do {
+            for (TrialNumberRule rule : rules) {
+                if(rule.getRule()==1){
+                    trialNumber.append(rule.getData());
+                } else if (rule.getRule()==2) {
+                    if(contractId!=null&&contractId!=0L){
+                        String sql1="select contract_number from m_contract_info where id="+contractId;
+                        String result = jdbcTemplate.query(sql1, rs -> {
+                            if (rs.next()) {
+                                return rs.getString(1);
+                            } else {
+                                return "";
+                            }
+                        });
+                        trialNumber.append(result==null?"":result);
+                    }else {
+                        trialNumber.append("TJ01");
+                    }
+                } else if (rule.getRule()==3) {
+                    if (nodeId!=null) {
+                        String sql2="select unique_code from m_wbs_tree_private where p_key_id="+nodeId+" and is_deleted=0";
+                        String  result = jdbcTemplate.query(sql2, rs -> {
+                            if (rs.next()) {
+                                return rs.getString(1);
+                            } else {
+                                return "";
+                            }
+                        });
+                        trialNumber.append(result==null?"":result);
+                    }else {
+                        trialNumber.append("SNY");
+                    }
+                } else if (rule.getRule()==4) {
+                    String currentYearStr = String.valueOf(LocalDate.now().getYear());
+                    trialNumber.append(currentYearStr);
+                } else if (rule.getRule()==5) {
+                    int currentMonthValue = LocalDate.now().getMonthValue();
+                    String currentMonthStr = String.format("%02d", currentMonthValue);
+                    trialNumber.append(currentMonthStr);
+                } else if (rule.getRule()==6) {
+                    if(StringUtils.isEmpty(rule.getData())){
+                        trialNumber.append("");
+                        map.put("autoIncrementNumber","");
+                        continue;
+                    }
+                    if(!isSaveRedis){
+                        trialNumber.append(rule.getData());
+                        map.put("autoIncrementNumber",rule.getData());
+                    }
+                    if(rule.getIsAutoIncrement()!=null&&rule.getIsAutoIncrement()==1){
+                        String autoIncrementNumber="";
+                        //如果是需要自增的 先要查出当前数据库中自增编号的最大值
+                        String sql3 = "SELECT auto_increment_number FROM u_trial_auto_number where type="+type+" and contract_id="+contractId+" and is_deleted=0 ORDER BY auto_increment_number DESC LIMIT 1";
+                        String maxNumber = jdbcTemplate.query(sql3, rs -> {
+                            if (rs.next()) {
+                                return rs.getObject(1, String.class);
+                            } else {
+                                return null;
+                            }
+                        });
+                        if(StringUtils.isEmpty(maxNumber)){
+                            autoIncrementNumber=rule.getData();
+                        }else {
+                            autoIncrementNumber=incrementFormattedNumberWithCheck(maxNumber,i);
+                        }
+//
+//                    String sql4="select auto_increment_number FROM u_trial_auto_number where type="+type+" and contract_id="+contractId+" and is_deleted=0  ORDER BY auto_increment_number ASC";
+//                    List<String> autoNumbers = jdbcTemplate.query(sql4, new SingleColumnRowMapper<>(String.class));
+//                    //判断自增的流水号是否是连续的 是连续的就在最大值加1,不是连续的先使用缺失的编号
+//                    List<String> missingNumbers = findMissingNumberPatterns(autoNumbers);
+//                    if(missingNumbers.isEmpty()){
+//                        while (true){
+//                            maxNumber=incrementFormattedNumberWithCheck(maxNumber);
+//                            Object o = bladeRedis.get("trialAutoNumber:" + contractId + ":" + type + ":" + nodeId + ":" + "lock:" + maxNumber);
+//                            if(o==null){
+//                                break;
+//                            }
+//                        }
+//                        autoIncrementNumber=maxNumber;
+//                    }else {
+//                        for (int i = 0; i < missingNumbers.size(); i++) {
+//                            autoIncrementNumber=missingNumbers.get(i);
+//                            Object o = bladeRedis.get("trialAutoNumber:" + contractId + ":" + type + ":" + nodeId + ":" + "lock:" + autoIncrementNumber);
+//                            if(o==null){
+//                                break;
+//                            }
+//                            autoIncrementNumber="";
+//                        }
+//                        if(autoIncrementNumber.equals("")){
+//                            while (true){
+//                                maxNumber=incrementFormattedNumberWithCheck(maxNumber);
+//                                Object o = bladeRedis.get("trialAutoNumber:" + contractId + ":" + type + ":" + nodeId + ":" + "lock:" + maxNumber);
+//                                if(o==null){
+//                                    break;
+//                                }
+//                            }
+//                            autoIncrementNumber=String.valueOf(maxNumber);
+//                        }
+//                    }
+//                      if (isSaveRedis) {
+//                        bladeRedis.setEx("trialAutoNumber:" + contractId + ":" + type + ":" + nodeId + ":" + "lock:" + autoIncrementNumber , autoIncrementNumber,10 * 60 * 1000L);
+//                      }
+                        map.put("autoIncrementNumber",autoIncrementNumber);
+                        trialNumber.append(autoIncrementNumber);
+                    }
+                    else {
+                        map.put("autoIncrementNumber","");
+                        trialNumber.append(rule.getData());
+                    }
+                }
+            }
+            if(isSaveRedis){
+                flag=checkTrialNumberIsExist(trialNumber.toString(),type,contractId);
+                i++;
+                if(!flag){
+                    trialNumber.setLength(0);
+                }
+            }
+        }while (!flag);
+        map.put("trialNumber",trialNumber.toString());
+        return map;
+    }
+
+    public String incrementFormattedNumberWithCheck(String data,int i) {
+        if (data == null || data.isEmpty()) {
+            return "0";
+        }
+
+        int length = data.length();
+        int number = Integer.parseInt(data);
+        number += i;
+
+        // 检查自增后的数字位数是否超过原始数据的长度
+        if (String.valueOf(number).length() > length) {
+            throw new ServiceException("自增后的编号超出原始格式位数限制:" + data);
+        }
+
+        return String.format("%0" + length + "d", number);
+    }
+
+    public List<String> findMissingNumberPatterns(List<String> autoNumbersStr) {
+        if (autoNumbersStr == null || autoNumbersStr.size() <= 1) {
+            return Collections.emptyList();
+        }
+
+        // 提取数字和最大长度
+        List<Long> numbers = new ArrayList<>();
+        int maxLength = 0;
+
+        for (String s : autoNumbersStr) {
+            try {
+                Long num = Long.parseLong(s);
+                numbers.add(num);
+                maxLength = Math.max(maxLength, s.length());
+            } catch (NumberFormatException ignored) {
+            }
+        }
+
+        if (numbers.size() <= 1) {
+            return Collections.emptyList();
+        }
+
+        // 排序
+        numbers.sort(Long::compareTo);
+
+        long start = numbers.get(0);
+        long end = numbers.get(numbers.size() - 1);
+        Set<Long> numberSet = new HashSet<>(numbers);
+
+        List<String> missing = new ArrayList<>();
+
+        for (long i = start; i <= end; i++) {
+            if (!numberSet.contains(i)) {
+                // 使用原始最长字符串的长度进行格式化
+                String formatted = String.format("%0" + maxLength + "d", i);
+                missing.add(formatted);
+            }
+        }
+
+        return missing;
+    }
+    @Override
+    public boolean checkTrialNumberIsExist(String trialNumber,Integer type,Long contractId){
+        String tableName="";
+        String number="";
+        if(type==1){
+            tableName="u_trial_material_mobilization";
+            number="material_number";
+        }
+        if(type==2){
+            tableName="u_trial_sample_info";
+            number="specification_number";
+        }
+        if(type==3){
+            tableName="u_entrust_info";
+            number="entrust_no";
+        }
+        if(type==4){
+            tableName="u_trial_self_inspection_record";
+            number="record_no";
+        }
+        if(type==5){
+            tableName="u_trial_self_inspection_record";
+            number="report_no";
+        }
+        String sql="select count(id) from "+tableName+" where "+number+" = '"+trialNumber+"' and is_deleted=0 and contract_id="+contractId;
+        System.out.println(sql);
+        Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
+        if(count==0){
+            return true;
+        }else {
+            return false;
+        }
+    }
+
+    @Override
+    public TrialNumberRuleVO1 getTrialNumberRule(Long projectId,Long contractId, Integer type) {
+        TrialNumberRuleVO1 vo1 = new TrialNumberRuleVO1();
+        List<TrialNumberRule> trialNumberRules;
+        if(contractId==0L){
+            trialNumberRules = baseMapper.selectList(Wrappers.<TrialNumberRule>query().lambda().eq(TrialNumberRule::getProjectId, projectId).eq(TrialNumberRule::getType, type).eq(TrialNumberRule::getStatus,1).orderByAsc(TrialNumberRule::getSort));
+        }else {
+            trialNumberRules = baseMapper.selectList(Wrappers.<TrialNumberRule>query().lambda().eq(TrialNumberRule::getContractId, contractId).eq(TrialNumberRule::getType, type).eq(TrialNumberRule::getStatus,2).orderByAsc(TrialNumberRule::getSort));
+        }
+        if(trialNumberRules.size()>0){
+            for (TrialNumberRule rule : trialNumberRules) {
+                if(rule.getRule()==2){
+                    if(rule.getContractId()==null||rule.getContractId()==0L){
+                        rule.setData("TJ01");
+                    }else {
+                        String sql1="select contract_number from m_contract_info where id="+contractId;
+                        String result = jdbcTemplate.query(sql1, rs -> {
+                            if (rs.next()) {
+                                return rs.getString(1);
+                            } else {
+                                return "";
+                            }
+                        });
+                        rule.setData(result);
+                    }
+                } else if (rule.getRule()==3) {
+                    rule.setData("SNY");
+                } else if (rule.getRule()==4) {
+                    String currentYearStr = String.valueOf(LocalDate.now().getYear());
+                    rule.setData(currentYearStr);
+                } else if (rule.getRule()==5) {
+                    int currentMonthValue = LocalDate.now().getMonthValue();
+                    String currentMonthStr = String.format("%02d", currentMonthValue);
+                    rule.setData(currentMonthStr);
+                }
+            }
+        }
+        if(trialNumberRules!=null){
+            Map<String, String> map = getTrialNumber(projectId,contractId, type, null, false);
+            vo1.setList(trialNumberRules);
+            vo1.setTrialNumber(map.get("trialNumber"));
+            return vo1;
+        }
+        return null;
+    }
+
+    /**
+     * type 1材料 2样品 3委托单 4记录表 5报告表
+     * @param projectId
+     * @param contractId
+     * @param type
+     * @return
+     */
+    @Override
+    public boolean clearTrialNumber(Long projectId, Long contractId, Integer type) {
+        if(contractId!=null&&contractId!=0L){
+//            String update;
+//            if(type==1){
+//                update="update u_trial_material_mobilization set material_number = NULL where contract_id="+contractId;
+//            } else if (type==2) {
+//                update="update u_trial_sample_info set specification_number = NULL where contract_id="+contractId;
+//            } else if (type==3) {
+//                update="update u_entrust_info set entrust_no = NULL where contract_id="+contractId+" and status=1";
+//            } else if (type==4) {
+//                update="update u_trial_self_inspection_record set record_no = NULL where contract_id="+contractId+" and task_status='未上报'";
+//            }else{
+//                update="update u_trial_self_inspection_record set report_no = NULL where contract_id="+contractId+" and task_status='未上报'";
+//            }
+//            jdbcTemplate.execute(update);
+            List<TrialNumberRule> trialNumberRules;
+            trialNumberRules = baseMapper.selectList(Wrappers.<TrialNumberRule>query().lambda().eq(TrialNumberRule::getContractId, contractId).eq(TrialNumberRule::getType, type).eq(TrialNumberRule::getStatus,2).orderByAsc(TrialNumberRule::getSort));
+            if(!trialNumberRules.isEmpty()){
+                boolean b = trialNumberRules.stream().anyMatch(t -> t.getRule() == 6);
+                if(b){
+                    String sql="update u_trial_auto_number set is_deleted=1 where contract_id="+contractId+" and type="+ type;
+                    jdbcTemplate.update(sql);
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public Map<String, String> getEntrustNumber(Long pkeyId,Long contractId) throws FileNotFoundException {
+        final Long nodeId=pkeyId;
+        // 合同段信息
+        String sql="select * from m_contract_info where id="+contractId;
+        ContractInfo contractInfo =jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(ContractInfo.class));
+        String sql1="select * from m_wbs_tree_private where p_key_id="+pkeyId;
+        // 节点数
+        WbsTreePrivate treePrivate = jdbcTemplate.queryForObject(sql1,new BeanPropertyRowMapper<>(WbsTreePrivate.class));
+        if (contractInfo == null) {
+            throw new ServiceException("合同段信息为null");
+        }
+        if (contractInfo.getContractType() == 2) { //3 监理
+            pkeyId = treePrivate.getJlerTreeId();
+        } else if (contractInfo.getContractType() == 3 || contractInfo.getContractType() == 8) { //业主
+            pkeyId = treePrivate.getYzerTreeId();
+        }else {
+            return null;
+        }
+        String sql2="select * from m_wbs_tree_private where p_key_id="+pkeyId;
+        WbsTreePrivate wbsTreePrivate1 = jdbcTemplate.queryForObject(sql2, new BeanPropertyRowMapper<>(WbsTreePrivate.class));
+        String fileUrl = wbsTreePrivate1.getHtmlUrl();
+        String file_path = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
+        String sys_file_net_url = ParamCache.getValue(CommonConstant.SYS_FILE_NET_URL);
+        File file1 = ResourceUtil.getFile(fileUrl);
+        InputStream fileInputStream;
+        if (file1.exists()) {
+            fileInputStream = new FileInputStream(file1);
+        } else {
+            String path = sys_file_net_url + fileUrl.replaceAll("//", "/").replaceAll(file_path, "");
+            fileInputStream = CommonUtil.getOSSInputStream(path);
+        }
+        String htmlString = IoUtil.readToString(fileInputStream);
+        Document doc = Jsoup.parse(htmlString);
+        Elements elementsWithPlaceholderxx = doc.select("el-input[placeholder*=委托单编号]");
+        if(!elementsWithPlaceholderxx.isEmpty()){
+            Element first = elementsWithPlaceholderxx.first();
+            String key = first.attr("id");
+            Map<String, String> map = getTrialNumber(Long.valueOf(wbsTreePrivate1.getProjectId()),contractId, 3, nodeId, true);
+            map.put(key,map.get("trialNumber"));
+            return map;
+        }
+        return null;
+    }
+    public void checkSave(Long contractId,int type,Long formDataId,String autoNumber){
+        List<TrialNumberRule> list = baseMapper.selectList(Wrappers.<TrialNumberRule>query().lambda().eq(TrialNumberRule::getContractId, contractId).eq(TrialNumberRule::getType, type).eq(TrialNumberRule::getStatus,2).orderByAsc(TrialNumberRule::getSort));
+            if(list!=null&&list.size()>0){
+                List<TrialNumberRule> collect = list.stream().filter(o -> o.getRule() == 6 && o.getIsAutoIncrement() == 1).collect(Collectors.toList());
+                if(!collect.isEmpty()){
+                    TrialAutoNumber one = trialAutoNumberService.getOne(Wrappers.lambdaQuery(TrialAutoNumber.class).eq(TrialAutoNumber::getFormDataId, formDataId).eq(TrialAutoNumber::getType, type));
+                    if(one==null){
+                        TrialAutoNumber trialAutoNumber = new TrialAutoNumber();
+                        trialAutoNumber.setId(SnowFlakeUtil.getId());
+                        trialAutoNumber.setContractId(contractId);
+                        trialAutoNumber.setType(type);
+                        trialAutoNumber.setNumberRuleId(collect.get(0).getId());
+                        trialAutoNumber.setFormDataId(formDataId);
+                        trialAutoNumber.setAutoIncrementNumber(autoNumber);
+                        trialAutoNumberService.save(trialAutoNumber);
+                    }
+                }
+            }
+    }
+
+}

+ 18 - 4
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialSampleInfoServiceImpl.java

@@ -23,6 +23,7 @@ import org.springblade.business.excel.TrialSampleInfoExcel;
 import org.springblade.business.mapper.TrialSampleInfoMapper;
 import org.springblade.business.mapper.TrialSamplingRecordMapper;
 import org.springblade.business.service.IEntrustInfoService;
+import org.springblade.business.service.ITrialNumberRuleService;
 import org.springblade.business.service.ITrialSampleInfoService;
 import org.springblade.business.utils.PDFUtil;
 import org.springblade.business.utils.StringSPUtils;
@@ -65,6 +66,7 @@ public class TrialSampleInfoServiceImpl extends BaseServiceImpl<TrialSampleInfoM
     private final TrialSamplingRecordMapper trialSamplingRecordMapper;
     private final JdbcTemplate jdbcTemplate;
     private final IEntrustInfoService entrustInfoService;
+    private final ITrialNumberRuleService trialNumberRuleService;
 
     @Override
     public boolean sampleVerification(String specificationNumber, String id, String contractId, String nodeId) {
@@ -133,10 +135,9 @@ public class TrialSampleInfoServiceImpl extends BaseServiceImpl<TrialSampleInfoM
     @Override
     public boolean sampleSubmit(TrialSampleInfoDTO obj) {
         //如果样品编号为空,那么就自动生成
-        if (ObjectUtil.isEmpty(obj.getSpecificationNumber())) {
-            this.buildNumber(obj);
-        }
-
+//        if (ObjectUtil.isEmpty(obj.getSpecificationNumber())) {
+//            this.buildNumber(obj);
+//        }
         TrialSampleInfo trialSampleInfo = BeanUtil.copyProperties(obj, TrialSampleInfo.class);
         if (trialSampleInfo != null) {
             if (ObjectUtils.isEmpty(trialSampleInfo.getMaterialCount())) {
@@ -145,7 +146,20 @@ public class TrialSampleInfoServiceImpl extends BaseServiceImpl<TrialSampleInfoM
             if (ObjectUtils.isEmpty(trialSampleInfo.getRepresentativeCount())) {
                 trialSampleInfo.setRepresentativeCount("0");
             }
+            boolean b =true;
+            if(StringUtils.isNotEmpty(obj.getSpecificationNumber())){
+                trialNumberRuleService.checkTrialNumberIsExist(obj.getSpecificationNumber(), 2,obj.getContractId());
+            }
+            if(!b){
+                throw new ServiceException("样品编号已存在");
+            }
             this.saveOrUpdate(trialSampleInfo);
+            if(StringUtils.isNotEmpty(obj.getAutoIncrementNumber())){
+                if(obj.getTrialNumber().equals(obj.getSpecificationNumber())){
+                    trialNumberRuleService.checkSave(obj.getContractId(), 2, obj.getId(), obj.getAutoIncrementNumber());
+                }
+                //bladeRedis.del("trialAutoNumber:" + obj.getContractId() + ":" + 2 + ":" + obj.getId() + ":" + "lock:" + obj.getAutoIncrementNumber());
+            }
 
             if (trialSampleInfo.getId() != null && obj.getMobilizationId() != null && obj.getMobilizationId() != -1) {
                 TrialSamplingRecord trialSamplingRecord = trialSamplingRecordMapper.selectByMobilizationIdAndSampleInfoId(obj.getMobilizationId(), trialSampleInfo.getId());

+ 44 - 2
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TrialSelfInspectionRecordServiceImpl.java

@@ -26,6 +26,7 @@ import org.springblade.business.mapper.TrialMaterialMobilizationMapper;
 import org.springblade.business.mapper.TrialSampleInfoMapper;
 import org.springblade.business.mapper.TrialSelfInspectionRecordMapper;
 import org.springblade.business.service.IEntrustInfoService;
+import org.springblade.business.service.ITrialNumberRuleService;
 import org.springblade.business.service.ITrialSelfInspectionRecordService;
 import org.springblade.business.utils.FileUtils;
 import org.springblade.business.utils.FileUtils2;
@@ -93,6 +94,7 @@ public class TrialSelfInspectionRecordServiceImpl extends BaseServiceImpl<TrialS
     private final InformationQueryServiceImpl informationQueryService;
     private final TrialDetectionDataServiceImpl trialDetectionDataService;
     private final IEntrustInfoService entrustInfoService;
+    private final ITrialNumberRuleService trialNumberRuleService;
 
     @Override
     public IPage<TrialSelfInspectionRecordVO> selfPage(IPage<TrialSelfInspectionRecord> page, TrialSelfInspectionRecordPageDTO dto) throws FileNotFoundException {
@@ -107,7 +109,24 @@ public class TrialSelfInspectionRecordServiceImpl extends BaseServiceImpl<TrialS
                 queryWrapper.lambda().in(TrialSelfInspectionRecord::getNodeId, pIds);
             }
             if (StringUtils.isNotEmpty(dto.getQueryValue())) {
-                queryWrapper.lambda().like(TrialSelfInspectionRecord::getTrialProjectName, dto.getQueryValue());
+                //查询委托单编码
+                List<EntrustInfo> entrustInfos = entrustInfoMapper.selectList(Wrappers.<EntrustInfo>lambdaQuery()
+                        .like(EntrustInfo::getEntrustNo, dto.getQueryValue()));
+                List<Long> entrustIds;
+                if(CollectionUtil.isNotEmpty(entrustInfos)){
+                    entrustIds = entrustInfos.stream().map(EntrustInfo::getId).collect(Collectors.toList());
+                } else {
+                    entrustIds = null;
+                }
+
+                queryWrapper.lambda().and(
+                        wq ->
+                            wq.like(TrialSelfInspectionRecord::getTrialProjectName, dto.getQueryValue()).or()
+                                    .like(TrialSelfInspectionRecord::getRecordNo, dto.getQueryValue()).or()
+                                    .like(TrialSelfInspectionRecord::getReportNo, dto.getQueryValue()).or()
+                                    .like(TrialSelfInspectionRecord::getSpecificationNumber, dto.getQueryValue()).or()
+                                    .in(CollectionUtil.isNotEmpty(entrustIds),TrialSelfInspectionRecord::getEntrustId, entrustIds)
+                );
             }
             if (org.apache.commons.lang.StringUtils.isNotEmpty(dto.getStartTime()) && org.apache.commons.lang.StringUtils.isNotEmpty(dto.getEndTime())) {
                 String endTime = dto.getEndTime();
@@ -268,7 +287,7 @@ public class TrialSelfInspectionRecordServiceImpl extends BaseServiceImpl<TrialS
      * @throws FileNotFoundException
      */
     private String getMergePdfToTrialNew(Long contractId, Long nodeId, Integer type) throws FileNotFoundException {
-        String sql = "select pdf_url,e_visa_pdf_url from u_information_query where wbs_id='" + nodeId + "' and contract_id ='" + contractId + "' and classify = '" + type + "'" ;
+        String sql = "select pdf_url,e_visa_pdf_url from u_information_query where wbs_id='" + nodeId + "' and status in(0,1,2) and contract_id ='" + contractId + "' and classify = '" + type + "'" ;
         List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
         if (maps.size() >= 1) {
             Map<String, Object> stringObjectMap = maps.get(0);
@@ -1120,6 +1139,29 @@ public class TrialSelfInspectionRecordServiceImpl extends BaseServiceImpl<TrialS
             //修改项目节点基础信息
             jdbcTemplate.update("update u_entrust_info set sample_status=4 where id ='"+dto.getEntrustId()+"'");
         }
+        String[] strings = dto.getTableType().split(",");
+        if(StringUtils.isNotEmpty(dto.getRecordAutoNumber())||StringUtils.isNotEmpty(dto.getReportAutoNumber())){
+            if (dto.getOldRecordNumber()!=null&&dto.getOldRecordNumber().equals(dto.getRecordNo())||dto.getOldReportNumber()!=null&&dto.getOldReportNumber().equals(dto.getReportNo())) {
+                if(strings.length==1){
+                    if(strings[0].equals("1")){
+                        if(StringUtils.isNotEmpty(dto.getRecordAutoNumber())){
+                            trialNumberRuleService.checkSave(Long.valueOf(dto.getProjectId()),4,dto.getId(),dto.getRecordAutoNumber());
+                        }
+                    }else {
+                        if(StringUtils.isNotEmpty(dto.getReportAutoNumber())){
+                            trialNumberRuleService.checkSave(Long.valueOf(dto.getProjectId()),5,dto.getId(),dto.getReportAutoNumber());
+                        }
+                    }
+                }else {
+                    if(StringUtils.isNotEmpty(dto.getRecordAutoNumber())){
+                        trialNumberRuleService.checkSave(Long.valueOf(dto.getProjectId()),4,dto.getId(),dto.getRecordAutoNumber());
+                    }
+                    if(StringUtils.isNotEmpty(dto.getReportAutoNumber())){
+                        trialNumberRuleService.checkSave(Long.valueOf(dto.getProjectId()),5,dto.getId(),dto.getReportAutoNumber());
+                    }
+                }
+            }
+        }
         return dto.getId().toString();
     }
 

+ 49 - 3
blade-service/blade-business/src/main/java/org/springblade/business/utils/PDFUtil.java

@@ -104,7 +104,8 @@ public class PDFUtil {
             String[] lines = text.split("[ \\n]+");
             for(int k=0;k<lines.length;k++){
                 String textStr = lines[k];
-                if(textStr.indexOf("*")>=0){
+                int index = textStr.indexOf("*");
+                if(index>=0 && textStr.charAt(index+1) != '✹'){
                     textStr = textStr.substring(textStr.lastIndexOf("*")+1,textStr.length());
                 }
 
@@ -115,7 +116,18 @@ public class PDFUtil {
                             txt=txt.substring(0,i);
                         }
                     }
-                    if (txt.length() >= 15 && Func.isNumeric(txt)) {
+                    if (txt.length() >= 15 && Func.isNumeric(txt)||(Func.isNumeric(txt)&&txt.length()==8&&txt.startsWith("123"))) {
+                        eVisaConfigList.add(txt);
+                    }
+                }
+                textS = Func.toStrArray("\\*",textStr);
+                for(String txt : textS){
+                    for (int i = 0; i < txt.length(); i++) {
+                        if (!Character.isDigit(txt.charAt(i))) {
+                            txt=txt.substring(0,i);
+                        }
+                    }
+                    if (txt.length() >= 15 && Func.isNumeric(txt)||(Func.isNumeric(txt)&&txt.length()==8&&txt.startsWith("123"))) {
                         eVisaConfigList.add(txt);
                     }
                 }
@@ -123,11 +135,45 @@ public class PDFUtil {
                 // 特殊处理
                 if(textStr.indexOf("1")>=0){
                     String txt = textStr.substring(textStr.indexOf("1"));
-                    if (txt.length() >= 15 && Func.isNumeric(txt)) {
+                    if (txt.length() >= 15 && Func.isNumeric(txt)||(Func.isNumeric(txt)&&txt.length()==8&&txt.startsWith("123"))) {
                         System.out.println(txt);
                         eVisaConfigList.add(txt);
                     }
                 }
+                if (textStr.contains("✹")) {
+                    String textString = textStr.substring(textStr.indexOf("✹") + 1);
+                    if (textString.contains("||✹")) {
+                        String[] textS1 = Func.toStrArray("\\|\\|✹",textString);
+                        for(String txt : textS1){
+                            for (int i = 0; i < txt.length(); i++) {
+                                if (!Character.isDigit(txt.charAt(i))) {
+                                    txt=txt.substring(0,i);
+                                }
+                            }
+                            if (txt.length() >= 15 && Func.isNumeric(txt)||(Func.isNumeric(txt)&&txt.length()==8&&txt.startsWith("123"))) {
+                                eVisaConfigList.add("✹" + txt);
+                            }
+                        }
+                    }
+                    if (textString.contains("*✹")) {
+                        String[] textS1 = Func.toStrArray("\\*✹",textString);
+                        for(String txt : textS1){
+                            for (int i = 0; i < txt.length(); i++) {
+                                if (!Character.isDigit(txt.charAt(i))) {
+                                    txt=txt.substring(0,i);
+                                }
+                            }
+                            if (txt.length() >= 15 && Func.isNumeric(txt)||(Func.isNumeric(txt)&&txt.length()==8&&txt.startsWith("123"))) {
+                                eVisaConfigList.add("✹" + txt);
+                            }
+                        }
+                    }
+                    if(textString.startsWith("1")){
+                        if (textString.length() >= 15 && Func.isNumeric(textString)) {
+                            eVisaConfigList.add("✹" + textString);
+                        }
+                    }
+                }
             }
 
             List<String> unique = eVisaConfigList.stream().distinct().collect(Collectors.toList());

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

@@ -160,7 +160,6 @@ public class ArchiveController {
         }
     }
 
-
     @Scheduled(cron = "0/30 * * * * ?")
     public void SplitPdfInfo() {
         //执行代码
@@ -168,7 +167,7 @@ public class ArchiveController {
         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));
-
+        log.info("分解html开始==="+query.size());
         if (query != null && query.size() >= 1) {
             for (ArchivesSplitInfoVO dataInfo : query) {
                 if (executor.getQueue().size() <= 10) {
@@ -198,6 +197,7 @@ public class ArchiveController {
 
     public void signTaskBatchpng(ArchivesSplitInfoVO taskSign) {
         try {
+            System.out.println("分解001");
             String archiveId = taskSign.getArchiveId();
             String fileUlr = taskSign.getFileUrl();
             String firstPage = FileUtils.getSysLocalFileUrl() + "archiveSplit/";
@@ -209,7 +209,7 @@ public class ArchiveController {
             int bkb = 0 ;
             //将imagePath 的数据转成一个可解析的html
             String htmlUrl = pngToHtml(firstPage, archiveId,taskSign.getFirstFileUrl());
-
+            System.out.println("分解002="+htmlUrl);
 
             if (htmlUrl.indexOf("_001.html") >= 0 && htmlUrl.indexOf("archiveSplit") >= 0) {
                 String htmlString = IoUtil.readToString(new FileInputStream(htmlUrl));
@@ -261,7 +261,7 @@ public class ArchiveController {
                     // 分解文件
                     String fmlUrl = FileUtils.getSysLocalFileUrl() + "archiveSplit/"+archiveId+"_cf_00"+i+".pdf";
                     getPdfByPage(startYm,endYm,fileUlr,fmlUrl);
-                    saveDataToMysql(fmlUrl,wjtm,taskSign.getId(),endYm-startYm+1,i,zrz);
+                    saveDataToMysql(fmlUrl,wjtm,taskSign.getId(),endYm-startYm+1,i,zrz,rq);
                     bkb =  endYm ;
                 }
             } else {
@@ -271,30 +271,31 @@ public class ArchiveController {
             // 添加封面信息
             String fmlUrl = FileUtils.getSysLocalFileUrl() + "archiveSplit/"+archiveId+"_fm_001.pdf";
             getPdfByPage(1,1,fileUlr,fmlUrl);
-            saveDataToMysql(fmlUrl,"封面",taskSign.getId(),1,-4,dutyUser);
+            saveDataToMysql(fmlUrl,"封面",taskSign.getId(),1,-4,dutyUser,"");
 
             // 卷内目录
             String jnmuUrl = FileUtils.getSysLocalFileUrl() + "archiveSplit/"+archiveId+"_jnml_001.pdf";
             getPdfByPage(baseStart,basePage,fileUlr,jnmuUrl);
-            saveDataToMysql(jnmuUrl,"卷内目录",taskSign.getId(),1,-3,dutyUser);
+            saveDataToMysql(jnmuUrl,"卷内目录",taskSign.getId(),1,-3,dutyUser,"");
 
             // 卷内备考表
             String jnbkbUrl = FileUtils.getSysLocalFileUrl() + "archiveSplit/"+archiveId+"_jnbkb_001.pdf";
             getPdfByPage(bkb+1,bkb+1,fileUlr,jnbkbUrl);
-            saveDataToMysql(jnbkbUrl,"卷内备考表",taskSign.getId(),1,100,dutyUser);
+            saveDataToMysql(jnbkbUrl,"卷内备考表",taskSign.getId(),1,100,dutyUser,"");
 
             // 背脊表
             String bjbUrl = FileUtils.getSysLocalFileUrl() + "archiveSplit/"+archiveId+"_beiji_001.pdf";
             String bjbUrlPng = FileUtils.getSysLocalFileUrl() + "archiveSplit/"+archiveId+"_beiji_001.png";
+
             getPdfByPage(bkb+2,bkb+2,fileUlr,bjbUrl);
 
-            File bgImgFile = new File(bjbUrl);
+            File bgImgFile = new File(bjbUrlPng);
             if (!bgImgFile.exists()) {
                 savePdfAsImage(1, bjbUrl, bjbUrlPng);
             }
-            String state = OcrTitle(bjbUrl,"3");
+            String state = OcrTitle(bjbUrlPng,"3");
             if(state.equals("1")){
-                saveDataToMysql(jnbkbUrl,"背脊表",taskSign.getId(),1,101,dutyUser);
+                saveDataToMysql(bjbUrl,"背脊表",taskSign.getId(),1,101,dutyUser,"");
             }
             bgImgFile.delete();
 
@@ -312,6 +313,10 @@ public class ArchiveController {
             jdbcTemplate.execute(taxkSql);
             jdbcTemplate.execute(taxkSql2);
 
+            // 删除html
+            File fileHtml = new File(fmlUrl);
+            fileHtml.delete();
+
             // 修改完成情况
             RedisTemplate.delete("splithtml-" + archiveId);
         } catch (Exception e) {
@@ -333,6 +338,7 @@ public class ArchiveController {
                     new InputStreamReader(process.getInputStream()));
             String htmlUrl;
             while ((htmlUrl = reader.readLine()) != null) {
+                System.out.println(htmlUrl);
                 if (htmlUrl.indexOf("html文件路径") >= 0 && htmlUrl.indexOf("_001.html") >= 0 && htmlUrl.indexOf("archiveSplit") >= 0) {
                     lasHhtmlUrl = htmlUrl.replace("html文件路径", "");
                 }
@@ -350,7 +356,7 @@ public class ArchiveController {
         }
     }
 
-    public String OcrTitle(String fileUrl, String type) {
+    public static String OcrTitle(String fileUrl, String type) {
         String lasHhtmlUrl = "";
         try {
             // 定义Python解释器路径和脚本路径
@@ -445,8 +451,7 @@ public class ArchiveController {
         }
     }
 
-    public int saveDataToMysql(String upFileUrl,String fileName,String fileId,int filePage,int sort,String dutyUser) {
-
+    public int saveDataToMysql(String upFileUrl,String fileName,String fileId,int filePage,int sort,String dutyUser,String fileTime) {
         // 获取封面信息
         long newPkId = SnowFlakeUtil.getId(); //主键Id
         File fmfile = new File(upFileUrl);
@@ -459,7 +464,7 @@ public class ArchiveController {
                         " drawing_no,cite_change_number,certification_time,e_visa_file,node_ext_id,file_type,archive_id,origin_id,filming_time,filmingor_time,tag_id,pic_code,refer_code,film_code,width,height,ftime,utime,del_time,sort,box_name,box_number,is_auto_file,is_archive,page_num, " +
                         " file_size,source_type,is_element,pdf_page_url,fid,rectification,classify,m_wbs_tree_contract_p_key_id,u_image_classification_file_id,archive_file_storage_type,node_tree_structure,date_name,archive_file_stroage_type,out_id,sort_num " +
                         "   ) " +
-                        " SELECT "+newPkId+",project_id,contract_id,node_id,file_number,'" + fileName + "',file_time,'" + FmPdfUrl + "','" + FmPdfUrl + "',"+filePage+",is_approval,is_certification,is_need_certification,'"+dutyUser+"',create_user,create_dept,create_time,update_user,update_time,status,is_deleted,sheet_type,sheet_source, " +
+                        " SELECT "+newPkId+",project_id,contract_id,node_id,file_number,'" + fileName + "','"+fileTime+"','" + FmPdfUrl + "','" + FmPdfUrl + "',"+filePage+",is_approval,is_certification,is_need_certification,'"+dutyUser+"',create_user,create_dept,create_time,update_user,update_time,status,is_deleted,sheet_type,sheet_source, " +
                         "        drawing_no,cite_change_number,certification_time,e_visa_file,node_ext_id,file_type,archive_id,origin_id,filming_time,filmingor_time,tag_id,pic_code,refer_code,film_code,width,height,ftime,utime,del_time,"+sort+",box_name,box_number,is_auto_file,is_archive,page_num, " +
                         "        file_size,source_type,is_element,pdf_page_url,fid,rectification,classify,m_wbs_tree_contract_p_key_id,u_image_classification_file_id,archive_file_storage_type,node_tree_structure,date_name,archive_file_stroage_type,out_id,sort_num " +
                         " from u_archive_file where id=" + fileId;

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

@@ -103,10 +103,6 @@ public class EVController {
                                 try {
                                     /*===============执行批量任务===============*/
                                     evDataService.signTaskBatch(dataInfo);
-                                    System.out.println("队列数量" + executor.getQueue().size());
-                                    System.out.println("活跃数量" + executor.getActiveCount());
-                                    System.out.println("总共数量" + executor.getTaskCount());
-                                    System.out.println("完成数量" + executor.getCompletedTaskCount());
                                 } catch (Exception e) {
                                     e.printStackTrace();
                                 }

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

@@ -101,6 +101,7 @@ public class EVDataServiceImpl implements EVDataService {
                 //添加电签策略
                 List<SealStrategyVO> strategyListByAXQ = getStrategyListByAXQ(taskApp, ids);
                 if (strategyListByAXQ == null || Func.isEmpty(strategyListByAXQ) || strategyListByAXQ.size() == 0) {
+                    ids = ids.replaceAll("✹", "");
                     List<Map<String, Object>> mapList = jdbcTemplate.queryForList("SELECT * from m_textdict_info where type=6  and is_deleted=0 and id in(" + ids + ")");
                     if (mapList != null && mapList.size() > 0) {
                         taskApp.setSigState(2);
@@ -511,16 +512,35 @@ public class EVDataServiceImpl implements EVDataService {
         String[] strArray = Func.toStrArray(task.getUserId());
         String[] userNames = Func.toStrArray(task.getNickName());
         List<Map<String, Object>> maps = new ArrayList<>();
+        String[] split = ids.split(",");
+        StringBuilder dqIds = new StringBuilder();
+        StringBuilder signIds = new StringBuilder();
+        for (String id : split) {
+            if (id != null && id.contains("✹")) {
+                signIds.append(id.substring(1)).append( ",");
+            } else {
+                dqIds.append(id).append( ",");
+            }
+        }
+        if (dqIds.length()>0) {
+            dqIds.deleteCharAt(dqIds.length()-1);
+        }
+        if (signIds.length()>0) {
+            signIds.deleteCharAt(signIds.length()-1);
+        }
         if(strArray!=null && strArray.length>0) {
             for (int i = 0; i < strArray.length; i++) {
-                String sqlinfo = " SELECT * from ( SELECT a.id as keyWord,a.project_id,a.pyzbx ,a.pyzby,(SELECT acc_code from blade_user where id='" + strArray[i] + "' and is_deleted=0  ) as sealId from m_textdict_info a where  a.type =2 and a.id in (" + ids + ")  and sig_role_id in (SELECT DISTINCT c.role_id from m_project_assignment_user c  where c.contract_id=" + task.getContractId() + " and user_id=" + strArray[i] + " and c.is_deleted=0 ) ) x where x.sealId is not null ";
-                if (task.getSigType() == 2) {
-                    sqlinfo = "SELECT a.id as keyWord,a.pyzbx,a.pyzby,b.certificate_number as sealId from m_textdict_info a ,m_sign_pfx_file b where a.sig_role_id = b.pfx_type and b.project_contract_role like '%" + task.getContractId() + "%' and a.is_deleted=0 and b.is_deleted=0 and a.type=6 and a.id in(" + ids + ")";
-                    System.out.println("东方中讯--签章--" + sqlinfo);
-                } else {
-                    System.out.println("东方中讯--签字--" + sqlinfo);
+                List<Map<String, Object>> maps2 = null;
+                if (dqIds.length() > 0) {
+                    String sqlinfo = " SELECT * from ( SELECT a.id as keyWord,a.project_id,a.pyzbx ,a.pyzby,(SELECT acc_code from blade_user where id='" + strArray[i] + "' and is_deleted=0  ) as sealId from m_textdict_info a where  a.type =2 and a.id in (" + dqIds + ")  and sig_role_id in (SELECT DISTINCT c.role_id from m_project_assignment_user c  where c.contract_id=" + task.getContractId() + " and user_id=" + strArray[i] + " and c.is_deleted=0 ) ) x where x.sealId is not null ";
+                    if (task.getSigType() == 2) {
+                        sqlinfo = "SELECT a.id as keyWord,a.pyzbx,a.pyzby,b.certificate_number as sealId from m_textdict_info a ,m_sign_pfx_file b where a.sig_role_id = b.pfx_type and b.project_contract_role like '%" + task.getContractId() + "%' and a.is_deleted=0 and b.is_deleted=0 and a.type=6 and a.id in(" + dqIds + ")";
+                        System.out.println("东方中讯--签章--" + sqlinfo);
+                    } else {
+                        System.out.println("东方中讯--签字--" + sqlinfo);
+                    }
+                    maps2 = jdbcTemplate.queryForList(sqlinfo);
                 }
-                List<Map<String, Object>> maps2 = jdbcTemplate.queryForList(sqlinfo);
                 if(CollectionUtil.isNotEmpty(maps2)) {
                     Map<String, List<Map<String, Object>>> peopleByAge = maps2.stream()
                             .collect(Collectors.groupingBy(hada -> (Func.toStr(hada.get("keyWord")))));
@@ -543,6 +563,25 @@ public class EVDataServiceImpl implements EVDataService {
                         }
                     }
                 }
+                if (signIds.length() > 0 && task.getSigType() != 2) {
+                    String sql = "SELECT * from ( SELECT a.conf_id as keyWord,0.0 as pyzbx ,0.0 as pyzby,(SELECT acc_code from blade_user where id = " + strArray[i] + " and is_deleted=0  ) as sealId " +
+                            "from m_sign_config_relation a where a.type = 1 and a.is_deleted = 0 and a.conf_id in (" + signIds + ") " +
+                            "and a.relation_id in (SELECT DISTINCT c.role_id from m_project_assignment_user c  where c.contract_id= " + task.getContractId() + " and user_id= " + strArray[i] + " and c.is_deleted=0 ) ) x where x.sealId is not null ";
+                    List<Map<String, Object>> maps3 = jdbcTemplate.queryForList(sql);
+                    System.out.println("东方中讯--签字--key =" + sql);
+                    if (!maps3.isEmpty()) {
+                        Map<String, List<Map<String, Object>>> peopleByAge = maps2.stream()
+                                .collect(Collectors.groupingBy(hada -> (Func.toStr(hada.get("keyWord")))));
+                        for (String keyId : peopleByAge.keySet()) {
+                            List<Map<String, Object>> keyList = peopleByAge.get(keyId);
+                            if (keyList != null && !keyList.isEmpty()) {
+                                Map<String, Object> map = keyList.get(0);
+                                map.put("keyWord", "✹" + map.get("keyWord"));
+                                maps.add(map);
+                            }
+                        }
+                    }
+                }
             }
         }
         return maps;
@@ -555,19 +594,36 @@ public class EVDataServiceImpl implements EVDataService {
         String[] userNames = Func.toStrArray(task.getNickName());
         List<SealStrategyVO> sealStrategyVOS = new ArrayList<>();
 
-
+        String[] split = ids.split(",");
+        StringBuilder dqIds = new StringBuilder();
+        StringBuilder signIds = new StringBuilder();
+        for (String id : split) {
+            if (id != null && id.contains("✹")) {
+                signIds.append(id.substring(1)).append( ",");
+            } else {
+                dqIds.append(id).append( ",");
+            }
+        }
+        if (dqIds.length()>0) {
+            dqIds.deleteCharAt(dqIds.length()-1);
+        }
+        if (signIds.length()>0) {
+            signIds.deleteCharAt(signIds.length()-1);
+        }
         if(strArray!=null && strArray.length>0){
             for (int i =0 ;i < strArray.length;i++) {
                 String userId =strArray[i];
-                String sqlinfo = "SELECT * from ( SELECT DISTINCT a.id,a.pyzbx ,a.pyzby,a.project_id,(SELECT signature_file_url from m_sign_pfx_file where is_register=1 and certificate_user_id='" + userId + "' and is_deleted=0  ) as signature_file_url, (SELECT wide from m_sign_pfx_file where is_register=1 and certificate_user_id='" + userId + "' and is_deleted=0  ) as wide ,(SELECT high from m_sign_pfx_file where is_register=1 and certificate_user_id='" + userId + "' and is_deleted=0  ) as high from m_textdict_info a where  a.type =2 and a.id in (" + ids + ") and sig_role_id in (SELECT DISTINCT c.role_id from m_project_assignment_user c  where c.contract_id=" + task.getContractId() + " and user_id=" + userId + " and c.is_deleted=0 ) ) x where x.signature_file_url is not null ";
-                if (task.getSigType() == 2) {
-                    sqlinfo = "SELECT a.id,a.pyzbx,a.pyzby,b.signature_file_url,b.id as sfId,a.project_id,b.certificate_password,b.certificate_user_name,b.certificate_number ,b.wide,b.high from m_textdict_info a ,m_sign_pfx_file b where a.sig_role_id = b.pfx_type and b.project_contract_role like '%" + task.getContractId() + "%' and a.is_deleted=0 and b.is_deleted=0 and a.type=6 and a.id in(" + ids + ") ";
-                    System.out.println("安心签--签章--=" + sqlinfo);
-                } else {
-                    System.out.println("安心签--签字--=" + sqlinfo);
+                List<Map<String, Object>> maps2 = null;
+                if (dqIds.length() > 0) {
+                    String sqlinfo = "SELECT * from ( SELECT DISTINCT a.id,a.pyzbx ,a.pyzby,a.project_id,(SELECT signature_file_url from m_sign_pfx_file where is_register=1 and certificate_user_id='" + userId + "' and is_deleted=0  ) as signature_file_url, (SELECT wide from m_sign_pfx_file where is_register=1 and certificate_user_id='" + userId + "' and is_deleted=0  ) as wide ,(SELECT high from m_sign_pfx_file where is_register=1 and certificate_user_id='" + userId + "' and is_deleted=0  ) as high from m_textdict_info a where  a.type =2 and a.id in (" + dqIds + ") and sig_role_id in (SELECT DISTINCT c.role_id from m_project_assignment_user c  where c.contract_id=" + task.getContractId() + " and user_id=" + userId + " and c.is_deleted=0 ) ) x where x.signature_file_url is not null ";
+                    if (task.getSigType() == 2) {
+                        sqlinfo = "SELECT a.id,a.pyzbx,a.pyzby,b.signature_file_url,b.id as sfId,a.project_id,b.certificate_password,b.certificate_user_name,b.certificate_number ,b.wide,b.high from m_textdict_info a ,m_sign_pfx_file b where a.sig_role_id = b.pfx_type and b.project_contract_role like '%" + task.getContractId() + "%' and a.is_deleted=0 and b.is_deleted=0 and a.type=6 and a.id in(" + dqIds + ") ";
+                        System.out.println("安心签--签章--=" + sqlinfo);
+                    } else {
+                        System.out.println("安心签--签字--=" + sqlinfo);
+                    }
+                    maps2 = jdbcTemplate.queryForList(sqlinfo);
                 }
-                List<Map<String, Object>> maps2 = jdbcTemplate.queryForList(sqlinfo);
-
                 if (maps2 != null && maps2.size() > 0) {
                     List<Map<String, Object>> maps = new ArrayList<>();
                     Map<String, List<Map<String, Object>>> peopleByAge = maps2.stream()
@@ -576,22 +632,42 @@ public class EVDataServiceImpl implements EVDataService {
                     for (String keyId : peopleByAge.keySet()) {
                         int exId = 0;
                         List<Map<String, Object>> keyList = peopleByAge.get(keyId);
-                        if (keyList != null && keyList.size() == 1) {
+                        if (keyList != null && keyList.size() == 1 && keyList.get(0).get("signature_file_url") != null) {
                             maps.addAll(keyList);
                             exId = 1;
                         } else if (keyList != null && keyList.size() >= 2) {
                             for (Map<String, Object> datax : keyList) {
-                                if ((datax.get("project_id") + "").equals(task.getProjectId())) {
+                                if ((datax.get("project_id") + "").equals(task.getProjectId()) && datax.get("signature_file_url") != null) {
                                     maps.add(datax);
                                     exId = 1;
                                 }
                             }
                         }
-                        if (exId == 0) {
+                        if (exId == 0 && keyList != null) {
                             maps.add(keyList.get(0));
                         }
                     }
-
+                    if (signIds.length() > 0 && task.getSigType() != 2) {
+                        String sql = "SELECT * from ( SELECT DISTINCT a.conf_id as id,0.0 as pyzbx ,0.0 as pyzby,(SELECT signature_file_url from m_sign_pfx_file where is_register=1 and certificate_user_id='"
+                                + userId + "' and is_deleted=0  ) as signature_file_url, (SELECT wide from m_sign_pfx_file where is_register=1 and certificate_user_id='"
+                                + userId + "' and is_deleted=0  ) as wide ,(SELECT high from m_sign_pfx_file where is_register=1 and certificate_user_id='"
+                                + userId + "' and is_deleted=0  ) as high from m_sign_config_relation a where a.type = 1 and a.is_deleted = 0 and a.conf_id in (" + signIds + ") and a.relation_id in (SELECT DISTINCT c.role_id from m_project_assignment_user c  where c.contract_id="
+                                + task.getContractId() + " and user_id=" + userId + " and c.is_deleted=0 ) ) x where x.signature_file_url is not null ";
+                        List<Map<String, Object>> maps3 = jdbcTemplate.queryForList(sql);
+                        System.out.println("安心签--签章--key =" + sql);
+                        if (!maps3.isEmpty()) {
+                            Map<String, List<Map<String, Object>>> peopleByAges = maps3.stream()
+                                    .collect(Collectors.groupingBy(hada -> (Func.toStr(hada.get("id")))));
+                            for (String keyId : peopleByAges.keySet()) {
+                                List<Map<String, Object>> keyList = peopleByAges.get(keyId);
+                                if (keyList != null && !keyList.isEmpty()) {
+                                    Map<String, Object> map = keyList.get(0);
+                                    map.put("id", "✹" + map.get("id"));
+                                    maps.add(map);
+                                }
+                            }
+                        }
+                    }
                     if (maps == null || maps.size() <= 0) {
                         break;
                     }

+ 7 - 1
blade-service/blade-e-visa/src/main/java/org/springblade/evisa/utils/FileUtils.java

@@ -108,7 +108,13 @@ public class FileUtils {
             if (url.isEmpty() || url.equals("")) {
                 return "0";
             }
-            InputStream pdfInputStream = CommonUtil.getOSSInputStream(url);
+            File file1 = new File(url);
+            InputStream pdfInputStream;
+            if(file1.exists()){
+                pdfInputStream = new FileInputStream(file1);
+            }else{
+                pdfInputStream = CommonUtil.getOSSInputStream(url);
+            }
             //获取这份文件的页数并设置签章策略
             //获取PDF文件
             PDDocument document = PDDocument.load(pdfInputStream);

+ 100 - 10
blade-service/blade-e-visa/src/main/java/org/springblade/evisa/utils/PDFUtils.java

@@ -30,7 +30,8 @@ public class PDFUtils {
 
             for(int k=0;k<lines.length;k++){
                 String textStr = lines[k];
-                if(textStr.indexOf("*")>=0){
+                int index = textStr.indexOf("*");
+                if(index>=0 && textStr.charAt(index+1) != '✹'){
                     textStr = textStr.substring(textStr.lastIndexOf("*")+1,textStr.length());
                 }
 
@@ -44,12 +45,23 @@ public class PDFUtils {
                     if (txt.length() >= 15 && Func.isNumeric(txt)||(Func.isNumeric(txt)&&txt.length()==8&&txt.startsWith("123"))) {
                         eVisaConfigList.add(txt);
                     }
-                    if (taskApp.getPdfDate() == null || taskApp.getPdfDate().isEmpty()) {
-                        Matcher matcher = pattern.matcher(txt);
-                        if(matcher.matches()){
-                            taskApp.setPdfDate(matcher.group(1));
+                }
+                if (taskApp.getPdfDate() == null || taskApp.getPdfDate().isEmpty()) {
+                    Matcher matcher = pattern.matcher(textStr);
+                    if(matcher.matches()){
+                        taskApp.setPdfDate(matcher.group(1));
+                    }
+                }
+                textS = Func.toStrArray("\\*",textStr);
+                for(String txt : textS){
+                    for (int i = 0; i < txt.length(); i++) {
+                        if (!Character.isDigit(txt.charAt(i))) {
+                            txt=txt.substring(0,i);
                         }
                     }
+                    if (txt.length() >= 15 && Func.isNumeric(txt)||(Func.isNumeric(txt)&&txt.length()==8&&txt.startsWith("123"))) {
+                        eVisaConfigList.add(txt);
+                    }
                 }
 
                 // 特殊处理
@@ -60,6 +72,40 @@ public class PDFUtils {
                         eVisaConfigList.add(txt);
                     }
                 }
+                if (textStr.contains("✹")) {
+                    String textString = textStr.substring(textStr.indexOf("✹") + 1);
+                    if (textString.contains("||✹")) {
+                        String[] textS1 = Func.toStrArray("\\|\\|✹",textString);
+                        for(String txt : textS1){
+                            for (int i = 0; i < txt.length(); i++) {
+                                if (!Character.isDigit(txt.charAt(i))) {
+                                    txt=txt.substring(0,i);
+                                }
+                            }
+                            if (txt.length() >= 15 && Func.isNumeric(txt)||(Func.isNumeric(txt)&&txt.length()==8&&txt.startsWith("123"))) {
+                                eVisaConfigList.add("✹" + txt);
+                            }
+                        }
+                    }
+                    if (textString.contains("*✹")) {
+                        String[] textS1 = Func.toStrArray("\\*✹",textString);
+                        for(String txt : textS1){
+                            for (int i = 0; i < txt.length(); i++) {
+                                if (!Character.isDigit(txt.charAt(i))) {
+                                    txt=txt.substring(0,i);
+                                }
+                            }
+                            if (txt.length() >= 15 && Func.isNumeric(txt)||(Func.isNumeric(txt)&&txt.length()==8&&txt.startsWith("123"))) {
+                                eVisaConfigList.add("✹" + txt);
+                            }
+                        }
+                    }
+                    if(textString.startsWith("1")){
+                        if (textString.length() >= 15 && Func.isNumeric(textString)) {
+                            eVisaConfigList.add("✹" + textString);
+                        }
+                    }
+                }
             }
 
 
@@ -86,11 +132,10 @@ public class PDFUtils {
             PDFTextStripper stripper = new PDFTextStripper();
             String text = stripper.getText(document);
             String[] lines = text.split("[ \\n]+");
-            String regex = "^\\d{4}年\\d{2}月\\d{2}日$";
-
             for(int k=0;k<lines.length;k++){
                 String textStr = lines[k];
-                if(textStr.indexOf("*")>=0){
+                int index = textStr.indexOf("*");
+                if(index>=0 && textStr.charAt(index+1) != '✹'){
                     textStr = textStr.substring(textStr.lastIndexOf("*")+1,textStr.length());
                 }
 
@@ -101,7 +146,18 @@ public class PDFUtils {
                             txt=txt.substring(0,i);
                         }
                     }
-                    if (txt.length() >= 15 && Func.isNumeric(txt)) {
+                    if (txt.length() >= 15 && Func.isNumeric(txt)||(Func.isNumeric(txt)&&txt.length()==8&&txt.startsWith("123"))) {
+                        eVisaConfigList.add(txt);
+                    }
+                }
+                textS = Func.toStrArray("\\*",textStr);
+                for(String txt : textS){
+                    for (int i = 0; i < txt.length(); i++) {
+                        if (!Character.isDigit(txt.charAt(i))) {
+                            txt=txt.substring(0,i);
+                        }
+                    }
+                    if (txt.length() >= 15 && Func.isNumeric(txt)||(Func.isNumeric(txt)&&txt.length()==8&&txt.startsWith("123"))) {
                         eVisaConfigList.add(txt);
                     }
                 }
@@ -109,11 +165,45 @@ public class PDFUtils {
                 // 特殊处理
                 if(textStr.indexOf("1")>=0){
                     String txt = textStr.substring(textStr.indexOf("1"));
-                    if (txt.length() >= 15 && Func.isNumeric(txt)) {
+                    if (txt.length() >= 15 && Func.isNumeric(txt)||(Func.isNumeric(txt)&&txt.length()==8&&txt.startsWith("123"))) {
                         System.out.println(txt);
                         eVisaConfigList.add(txt);
                     }
                 }
+                if (textStr.contains("✹")) {
+                    String textString = textStr.substring(textStr.indexOf("✹") + 1);
+                    if (textString.contains("||✹")) {
+                        String[] textS1 = Func.toStrArray("\\|\\|✹",textString);
+                        for(String txt : textS1){
+                            for (int i = 0; i < txt.length(); i++) {
+                                if (!Character.isDigit(txt.charAt(i))) {
+                                    txt=txt.substring(0,i);
+                                }
+                            }
+                            if (txt.length() >= 15 && Func.isNumeric(txt)||(Func.isNumeric(txt)&&txt.length()==8&&txt.startsWith("123"))) {
+                                eVisaConfigList.add("✹" + txt);
+                            }
+                        }
+                    }
+                    if (textString.contains("*✹")) {
+                        String[] textS1 = Func.toStrArray("\\*✹",textString);
+                        for(String txt : textS1){
+                            for (int i = 0; i < txt.length(); i++) {
+                                if (!Character.isDigit(txt.charAt(i))) {
+                                    txt=txt.substring(0,i);
+                                }
+                            }
+                            if (txt.length() >= 15 && Func.isNumeric(txt)||(Func.isNumeric(txt)&&txt.length()==8&&txt.startsWith("123"))) {
+                                eVisaConfigList.add("✹" + txt);
+                            }
+                        }
+                    }
+                    if(textString.startsWith("1")){
+                        if (textString.length() >= 15 && Func.isNumeric(textString)) {
+                            eVisaConfigList.add("✹" + textString);
+                        }
+                    }
+                }
             }
 
 

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

@@ -37,7 +37,7 @@ import static java.math.BigDecimal.ROUND_HALF_UP;
 
 
 /**
- * @author yangyj
+ * @author yangyjT(com.mixsmart.utils.CustomFunction).dateAfter(T(com.mixsmart.utils.CustomFunction).dateMax(E['m_20220928150650_1575019183173795840:key_9']),28)
  */
 public class CustomFunction {
 
@@ -450,13 +450,14 @@ public class CustomFunction {
             List<String> result = new ArrayList<>();
             if(ListUtils.isNotEmpty(dateList)&&ListUtils.isNotEmpty(offSet)){
                 for(int i=0;i<dateList.size();i++){
-                    String d= dateList.get(i);
+                    String d= dateList.get(i).replaceAll("[\"']", "");;
                     if(StringUtils.isNotEmpty(d)) {
                         if(d.contains(",")){
                             String[] arr=d.replaceAll("[\\[\\]\\s]+","").split(",");
                             d=arr[arr.length-1];
                         }
                         Integer n = StringUtils.handObj2Integer(offSet.size() > i ? offSet.get(i) : offSet.getLast());
+                        // 日期需要正确的格式,需要判断
                         DateTime dt = new DateTime(d);
                         dt.offset(DateField.HOUR_OF_DAY, 24 * n);
                         result.add(dt.toString(DatePattern.CHINESE_DATE_PATTERN));

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

@@ -23,6 +23,7 @@ public class TableInfo {
     private String contractId;
     private String classify;
     private String projectId;
+    private String isTypePrivatePid; //用于判断操作
     private String groupId = "0";
     // 用于实验
     private String testGroupId = "0";

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

@@ -19,6 +19,8 @@ import com.spire.xls.collections.PicturesCollection;
 import com.spire.xls.core.spreadsheet.HTMLOptions;
 import io.swagger.annotations.*;
 import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
 import lombok.SneakyThrows;
 import org.apache.commons.codec.Charsets;
 import org.apache.commons.io.IOUtils;
@@ -52,6 +54,7 @@ import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.constant.BladeConstant;
 import org.springblade.core.tool.utils.*;
 import org.springblade.manager.bean.TableInfo;
+import org.springblade.manager.dto.AddBussFileSortDTO;
 import org.springblade.manager.entity.*;
 import org.springblade.manager.enums.ExecuteType;
 import org.springblade.manager.mapper.ExcelTabMapper;
@@ -865,6 +868,7 @@ public class ExcelTabController extends BladeController {
         //这句代码在正式环境要加上
 
         if (Func.isNotEmpty(dataInfo) && dataInfo.getTabType() != null && dataInfo.getTabType() != 100L) {
+            int x=0;
             for (int i = 1; i < 6; i++) {
                 Element tr = trs.get(i);
                 Elements tds = tr.select("td");
@@ -874,8 +878,9 @@ public class ExcelTabController extends BladeController {
                     if (style.indexOf("font-size") >= 0) {
                         int fontsize = Integer.parseInt(style.substring(style.indexOf("font-size:") + 10, style.indexOf(".0pt")));
                         if (isWater) {
-                            if (StringUtils.isNotEmpty(data.text()) && fontsize >= 12) {
+                            if (StringUtils.isNotEmpty(data.text()) && fontsize >= 12&&x<=0) {
                                 trs.get(i - 1).select("td").get(0).text(projectInfo.getProjectName());
+                                x=x+1;
                             }
                         } else {
                             if (StringUtils.isNotEmpty(data.text()) && fontsize >= 14) {
@@ -1647,7 +1652,9 @@ public class ExcelTabController extends BladeController {
         //拿到所有的名字
         Set<String> strings = wbsTreeContractList.stream().map(o -> o.getNodeName()).collect(Collectors.toSet());
         //根据实际排序
-        List<WbsTreeContract> wbsTreeContractList2 = wbsTreeContractList.stream().sorted(Comparator.comparing(WbsTreeContract::getCreateTime)).collect(Collectors.toList());
+        boolean flag = wbsInfo.getNodeName().contains("_PL_");
+        List<WbsTreeContract> wbsTreeContractList2 = wbsTreeContractList.stream().filter(wbs -> flag || (wbs.getNodeName()!= null && !wbs.getNodeName().contains("_PL_")))
+                .sorted(Comparator.comparing(WbsTreeContract::getCreateTime)).collect(Collectors.toList());
         //如果数量对不上说明有错的情况就进来,进行修改,现在wbsTreeContractList2就是正常的
         if (strings.size() != wbsTreeContractList2.size()) {
             for (int i = 0; i < wbsTreeContractList2.size(); i++) {
@@ -1688,7 +1695,7 @@ public class ExcelTabController extends BladeController {
         String tabName = wbsTreeContract.getInitTableName();
         // 字段查询 并去掉公式字段
 
-        String colkeys = "SELECT GROUP_CONCAT(COLUMN_NAME) as colkeys from information_schema.COLUMNS c where c.table_name='" + tabName + "' and COLUMN_NAME not in('id','p_key_id')";
+        String colkeys = "SELECT GROUP_CONCAT(distinct COLUMN_NAME) as colkeys from information_schema.COLUMNS c where c.table_name='" + tabName + "' and COLUMN_NAME not in('id','p_key_id')";
         Map<String, Object> stringObjectMap = jdbcTemplate.queryForMap(colkeys);
         colkeys = stringObjectMap.get("colkeys") + "";
         // 复制表数据
@@ -1709,7 +1716,7 @@ public class ExcelTabController extends BladeController {
     /**
      * 上传文件
      *
-     * @param file 文件
+     * @param files 文件
      * @return ObjectStat
      */
     @SneakyThrows
@@ -1724,40 +1731,45 @@ public class ExcelTabController extends BladeController {
             @ApiImplicitParam(name = "classify", value = "classify", required = true),
             @ApiImplicitParam(name = "projectId", value = "projectId", required = true)
     })
-    public R addBussFile(@RequestParam("file") MultipartFile file, Long pkeyId, String nodeId, String contractId, String projectId, String classify) {
-
+    public R addBussFile(@RequestParam("file") MultipartFile[] file, Long pkeyId, String nodeId, String contractId, String projectId, String classify) {
+        List<TableFile>list=new ArrayList<>();
+        for (int i = 0; i < file.length; i++) {
+            R<BladeFile> bladeFile = iossClient.addFileInfo(file[i]);
+            BladeFile bladeFile1 = bladeFile.getData();
+            TableFile tableFile = new TableFile();
+            String fileExtension = FileUtil.getFileExtension(bladeFile1.getName()).toLowerCase();
+            tableFile.setTabId(pkeyId + "");
+            tableFile.setName(file[i].getOriginalFilename());
+            tableFile.setContractId(Long.valueOf(contractId));
+            tableFile.setClassify(Integer.parseInt(classify));
+            tableFile.setType(2);
+            tableFile.setDomainUrl(bladeFile1.getLink());
+            tableFile.setIsDeleted(0);
+            tableFile.setExtension(fileExtension);
+
+            NewBladeFile newBladeFile = new NewBladeFile();
+            if (fileExtension.contains("xlsx")) {
+                newBladeFile = this.commonFileClient.excelToPdf(file[i]);
+                tableFile.setDomainPdfUrl(newBladeFile.getPdfUrl());
+            } else if (fileExtension.contains("xls")) {
+                newBladeFile = this.commonFileClient.excelToPdf(file[i]);
+                tableFile.setDomainPdfUrl(newBladeFile.getPdfUrl());
+            } else if (fileExtension.contains("docx")) {
+                newBladeFile = this.commonFileClient.wordToPdf(file[i]);
+                tableFile.setDomainPdfUrl(newBladeFile.getPdfUrl());
+            } else if (fileExtension.contains("png") || fileExtension.contains("jpg") || fileExtension.contains("webp") || fileExtension.contains("apng") ||
+                    fileExtension.contains("bmp") || fileExtension.contains("jepg") || fileExtension.contains("tif") || fileExtension.contains("gif")) {
+                newBladeFile = this.commonFileClient.pngOrJpgToPdf(file[i]);
+                tableFile.setDomainPdfUrl(newBladeFile.getPdfUrl());
+            } else if (fileExtension.contains("pdf")) {
+                tableFile.setDomainPdfUrl(bladeFile1.getLink());
+            }
 
-        R<BladeFile> bladeFile = iossClient.addFileInfo(file);
-        BladeFile bladeFile1 = bladeFile.getData();
-        TableFile tableFile = new TableFile();
-        String fileExtension = FileUtil.getFileExtension(bladeFile1.getName()).toLowerCase();
-        tableFile.setTabId(pkeyId + "");
-        tableFile.setName(file.getOriginalFilename());
-        tableFile.setType(2);
-        tableFile.setDomainUrl(bladeFile1.getLink());
-        tableFile.setIsDeleted(0);
-        tableFile.setExtension(fileExtension);
-
-        NewBladeFile newBladeFile = new NewBladeFile();
-        if (fileExtension.contains("xlsx")) {
-            newBladeFile = this.commonFileClient.excelToPdf(file);
-            tableFile.setDomainPdfUrl(newBladeFile.getPdfUrl());
-        } else if (fileExtension.contains("xls")) {
-            newBladeFile = this.commonFileClient.excelToPdf(file);
-            tableFile.setDomainPdfUrl(newBladeFile.getPdfUrl());
-        } else if (fileExtension.contains("docx")) {
-            newBladeFile = this.commonFileClient.wordToPdf(file);
-            tableFile.setDomainPdfUrl(newBladeFile.getPdfUrl());
-        } else if (fileExtension.contains("png") || fileExtension.contains("jpg") || fileExtension.contains("webp") || fileExtension.contains("apng") ||
-                fileExtension.contains("bmp") || fileExtension.contains("jepg") || fileExtension.contains("tif") || fileExtension.contains("gif")) {
-            newBladeFile = this.commonFileClient.pngOrJpgToPdf(file);
-            tableFile.setDomainPdfUrl(newBladeFile.getPdfUrl());
-        } else if (fileExtension.contains("pdf")) {
-            tableFile.setDomainPdfUrl(bladeFile1.getLink());
+            tableFile.setStatus("finished");
+            list.add(tableFile);
         }
 
-        tableFile.setStatus("finished");
-        tableFileService.save(tableFile);
+        tableFileService.saveBatch(list);
 
         // 生成单个pdf
         excelTabService.getBussPdfInfo(pkeyId);
@@ -1788,7 +1800,7 @@ public class ExcelTabController extends BladeController {
             informationQueryClient.saveInfo(query);
         }
         excelTabService.getBussPdfs(nodeId, classify, contractId, projectId);
-        return R.data(tableFile.getId());
+        return R.status(true);
     }
 
     @GetMapping("/show-buss-tab")
@@ -1809,6 +1821,8 @@ public class ExcelTabController extends BladeController {
         excelTabService.getBussPdfInfo(pkeyId);
         //重新生成PDF修改queryInfo
         excelTabService.getBussPdfs(nodeId, classify, wbsTreeContract.getContractId(), wbsTreeContract.getProjectId());
+        WbsTreeContract contract = wbsTreeContractService.getById(Long.parseLong(nodeId));
+        wbsTreeContractService.checkNodeAllDate(contract);
         return R.data("成功");
     }
 
@@ -1980,6 +1994,15 @@ public class ExcelTabController extends BladeController {
             dataArray.add(dataInfo);
         }
 
+        String singnType ="2";
+        if(dataInfo.containsKey("signType")){
+            singnType=dataInfo.getString("signType");
+        } else {
+            singnType = "";
+        }
+
+      //  dataInfo.getJSONObject("dataInfo").getJSONArray("orderList");
+
         JSONObject tableInfo1 = dataArray.getJSONObject(0);
         String nodeId = tableInfo1.getString("nodeId");
         String contractId = tableInfo1.getString("contractId");
@@ -2022,7 +2045,7 @@ public class ExcelTabController extends BladeController {
         }
 
         //保存数据到数据库
-        R<Object> result = this.excelTabService.saveOrUpdateInfo(tableInfoList);
+        R<Object> result = this.excelTabService.saveOrUpdateInfo(tableInfoList,singnType);
         RandomNumberHolder.RandomTemplateTypeclear();
         RandomNumberHolder.RandomWbsTreeContractclear();
         executionTime.info("----数据保存结束----");
@@ -2030,11 +2053,50 @@ public class ExcelTabController extends BladeController {
             return R.fail(result.getMsg());
         }
         executionTime.info("----数据合并前----");
-
-        BladeUser user = SecureUtil.getUser();
-        //异步生成pdf 和 合并pdf
-        excelTabService.synchronizedPdf(tableInfoList,nodeId + ":" + user.getUserId(), classify, contractId, projectId);
-
+        List<String> errorPKeyIds = new ArrayList<>();
+        //单个pdf加载
+        tableInfoList = (List<TableInfo>) result.getData();
+        if (tableInfoList != null) {
+            String finalSingnType = singnType;
+            tableInfoList.parallelStream().forEach(tableInfo -> {
+                R bussPdfInfo = null;
+                try {
+                    if(finalSingnType.equals("1") && tableInfo.getProjectId().equals("1630011899725201410") && (tableInfo.getIsTypePrivatePid().equals("1559714325173080065") || tableInfo.getIsTypePrivatePid().equals("1559479719236702210") )){
+                        System.out.println("12312312");
+                    }else{
+                        bussPdfInfo = excelTabService.getBussPdfInfo(Long.parseLong(tableInfo.getPkeyId()));
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+                if (bussPdfInfo!=null && (ObjectUtil.isEmpty(bussPdfInfo) || bussPdfInfo.getCode() != 200)) {
+                    //如果返回的单张pdfUrl为空,那么表示发生异常,返回异常信息
+                    errorPKeyIds.add(tableInfo.getPkeyId());
+                }
+            });
+        }
+        //检查当前节点下所有的未隐藏的表单日期是否填写完整
+        WbsTreeContract contract = wbsTreeContractService.getById(Long.parseLong(nodeId));
+        if(contract!=null){
+            wbsTreeContractService.checkNodeAllDate(contract);
+        }
+        executionTime.info("----数据保存完毕 ----");
+        //发生异常后直接返回,不进行合并
+        if (errorPKeyIds.size() > 0) {
+            List<AppWbsTreeContractVO> errorTabs = new LinkedList<>();
+            for (AppWbsTreeContractVO appWbsTreeContractVO : tableAll) {
+                if (errorPKeyIds.contains(appWbsTreeContractVO.getPKeyId().toString())) {
+                    errorTabs.add(appWbsTreeContractVO);
+                }
+            }
+            if (errorTabs.size() > 0) {
+                List<String> names = errorTabs.stream().map(WbsTreeContract::getNodeName).collect(Collectors.toList());
+                return R.fail("以下的表在生成pdf文件时发生了异常【" + StringUtils.join(names, "、") + "】");
+            }
+        }
+        executionTime.info("----数据合并前 ----");
+        //合并pdf加载
+        excelTabService.getBussPdfs(nodeId, classify, contractId, projectId);
         executionTime.info("---PDF合并耗时---");
         //更新缓存
         informationQueryClient.delAsyncWbsTree(contractId);
@@ -2244,7 +2306,7 @@ public class ExcelTabController extends BladeController {
         //公式填充
         this.excelTabService.formulaFillData(tableInfoList, Long.parseLong(nodeId), ExecuteType.INSPECTION);
         //保存数据到数据库
-        R<Object> result = this.excelTabService.saveOrUpdateInfo(tableInfoList);
+        R<Object> result = this.excelTabService.saveOrUpdateInfo(tableInfoList,"");
         if (!result.isSuccess()) {
             R.fail(result.getMsg());
             return;
@@ -2435,7 +2497,7 @@ public class ExcelTabController extends BladeController {
                                         String textainfo = element.text();
                                         if (textainfo == null || textainfo == "" || Func.isEmpty(textainfo)) {
                                             int x1, y1;
-                                            if (element.html().indexOf("x1") >= 0 && element.html().indexOf("y1") >= 0) {
+                                            if ((element.html().indexOf("x1") >= 0 && element.html().indexOf("y1") >= 0) || (element.hasAttr("x1") && element.hasAttr("y1"))) {
                                                 if (element.html().indexOf("el-tooltip") >= 0) {
                                                     x1 = Integer.parseInt(element.children().get(0).children().get(0).attr("x1"));
                                                     y1 = Integer.parseInt(element.children().get(0).children().get(0).attr("y1"));
@@ -4366,6 +4428,43 @@ public class ExcelTabController extends BladeController {
 
 
     }
+    @Data
+    @AllArgsConstructor
+    @NoArgsConstructor
+    public static class BussfileDTO{
+        private String name;
+        private String url;
+    }
+    @PostMapping("/previewBussfile")
+    public R<List<BussfileDTO>> previewBussfile(@RequestPart("file")MultipartFile[] file){
+        List<BussfileDTO>list=new ArrayList<>();
+        for (int i = 0; i < file.length; i++){
+            BussfileDTO dto = new BussfileDTO();
+            R<BladeFile> bladeFile = iossClient.addFileInfo(file[i]);
+            BladeFile bladeFile1 = bladeFile.getData();
+            String fileExtension = FileUtil.getFileExtension(bladeFile1.getName()).toLowerCase();
+            NewBladeFile newBladeFile = new NewBladeFile();
+            if (fileExtension.contains("xlsx")) {
+                newBladeFile = this.commonFileClient.excelToPdf(file[i]);
+                dto.setUrl(newBladeFile.getPdfUrl());
+            } else if (fileExtension.contains("xls")) {
+                newBladeFile = this.commonFileClient.excelToPdf(file[i]);
+                dto.setUrl(newBladeFile.getPdfUrl());
+            } else if (fileExtension.contains("docx")) {
+                newBladeFile = this.commonFileClient.wordToPdf(file[i]);
+                dto.setUrl(newBladeFile.getPdfUrl());
+            } else if (fileExtension.contains("png") || fileExtension.contains("jpg") || fileExtension.contains("webp") || fileExtension.contains("apng") ||
+                    fileExtension.contains("bmp") || fileExtension.contains("jepg") || fileExtension.contains("tif") || fileExtension.contains("gif")) {
+                newBladeFile = this.commonFileClient.pngOrJpgToPdf(file[i]);
+                dto.setUrl(newBladeFile.getPdfUrl());
+            } else if (fileExtension.contains("pdf")) {
+                dto.setUrl(bladeFile1.getLink());
+            }
+            dto.setName(file[i].getOriginalFilename());
+            list.add(dto);
+        }
+        return R.data(list);
+    }
 
     /**
      * 质检附件追加
@@ -4381,11 +4480,12 @@ public class ExcelTabController extends BladeController {
             @ApiImplicitParam(name = "nodeId", value = "nodeId", required = true),
 
     })
-    public R addBussFile(@RequestParam("file") MultipartFile[] file, String nodeId, Integer type, Long contractId, Integer classify, BladeUser b) {
+    public R addBussFile(Integer classify,Long contractId,@RequestParam("file") MultipartFile[] file, String nodeId, Integer type,BladeUser b) {
         List<TableFile> fileList = new ArrayList<>();
         if (file != null && file.length >= 1) {
-            for (MultipartFile multipartFile : file) {
-                R<BladeFile> bladeFile = iossClient.addFileInfo(multipartFile);
+            for (int i = 0; i < file.length; i++) {
+
+                R<BladeFile> bladeFile = iossClient.addFileInfo(file[i]);
                 BladeFile bladeFile1 = bladeFile.getData();
 
                 TableFile tableFile = new TableFile();
@@ -4393,7 +4493,7 @@ public class ExcelTabController extends BladeController {
                 String fileExtension = FileUtil.getFileExtension(bladeFile1.getName()).toLowerCase();
                 tableFile.setTabId(nodeId + "");
                 tableFile.setContractId(contractId);
-                tableFile.setName(multipartFile.getOriginalFilename());
+                tableFile.setName(file[i].getOriginalFilename());
                 tableFile.setType(type); //10 代表附件
                 if (type == 10 || type == 11 || type == 12 || type == 20 || type == 21 || type == 22) {
                     tableFile.setDomainPdfUrl(bladeFile1.getLink());
@@ -4403,8 +4503,26 @@ public class ExcelTabController extends BladeController {
                 tableFile.setExtension(fileExtension);
                 tableFile.setClassify(classify);
                 fileList.add(tableFile);
+                NewBladeFile newBladeFile = new NewBladeFile();
+                if (fileExtension.contains("xlsx")) {
+                    newBladeFile = this.commonFileClient.excelToPdf(file[i]);
+                    tableFile.setDomainPdfUrl(newBladeFile.getPdfUrl());
+                } else if (fileExtension.contains("xls")) {
+                    newBladeFile = this.commonFileClient.excelToPdf(file[i]);
+                    tableFile.setDomainPdfUrl(newBladeFile.getPdfUrl());
+                } else if (fileExtension.contains("docx")) {
+                    newBladeFile = this.commonFileClient.wordToPdf(file[i]);
+                    tableFile.setDomainPdfUrl(newBladeFile.getPdfUrl());
+                } else if (fileExtension.contains("png") || fileExtension.contains("jpg") || fileExtension.contains("webp") || fileExtension.contains("apng") ||
+                        fileExtension.contains("bmp") || fileExtension.contains("jepg") || fileExtension.contains("tif") || fileExtension.contains("gif")) {
+                    newBladeFile = this.commonFileClient.pngOrJpgToPdf(file[i]);
+                    tableFile.setDomainPdfUrl(newBladeFile.getPdfUrl());
+                } else if (fileExtension.contains("pdf")) {
+                    tableFile.setDomainPdfUrl(bladeFile1.getLink());
+                }
             }
             tableFileService.saveOrUpdateBatch(fileList);
+
             String file_path = FileUtils.getSysLocalFileUrl();
             String sys_isonline = ParamCache.getValue(CommonConstant.SYS_ISONLINE);
             List<TableFileVO> data = tableFileService.selectTableFileListByTen(Long.valueOf(nodeId + ""), Integer.valueOf(classify));
@@ -4417,7 +4535,9 @@ public class ExcelTabController extends BladeController {
             if (tabpdf2.exists()) {
                 tabpdf2.delete();
             }
-            FileUtils.mergePdfPublicMethods(datainfo, listPdf);
+            if(datainfo.size()>=1){
+                FileUtils.mergePdfPublicMethods(datainfo, listPdf);
+            }
             String netUrl = "";
             BladeFile bladeFile = this.newIOSSClient.uploadFile(nodeId + ".pdf", listPdf);
             if (bladeFile != null && ObjectUtils.isNotEmpty(bladeFile.getLink())) {
@@ -4432,7 +4552,7 @@ public class ExcelTabController extends BladeController {
             WbsTreeContract wbsTreeContract = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(WbsTreeContract.class));
             if (ObjectUtil.isNotEmpty(wbsTreeContract.getNodeClass())) {
                 if (wbsTreeContract.getNodeClass().equals(Integer.valueOf(2))) {
-                    InformationQuery iq = informationQueryClient.getInfoByWbsId(wbsTreeContract.getPKeyId());
+                    InformationQuery iq = informationQueryClient.getInfoByWbsId(wbsTreeContract.getPKeyId(),classify);
                     if (iq == null) {
                         iq = new InformationQuery();
                         iq.setId(SnowFlakeUtil.getId());
@@ -4473,6 +4593,24 @@ public class ExcelTabController extends BladeController {
         }
     }
 
+    @PostMapping("/add-bussfile-node-sort")
+    public R addBussFileNodeSort(@RequestBody AddBussFileSortDTO dto){
+        List<TableFile> tableFileList = tableFileService.list(new LambdaQueryWrapper<>(TableFile.class).eq(TableFile::getClassify, dto.getClassify()).eq(TableFile::getContractId, dto.getContractId()).eq(TableFile::getTabId, dto.getId()).eq(TableFile::getType, dto.getType()));
+        System.out.println(tableFileList);
+        if(dto.getList().length>0&&!tableFileList.isEmpty()){
+            for (TableFile file : tableFileList) {
+                for (int i = 0; i < dto.getList().length; i++) {
+                    if(dto.getList()[i].equals(file.getName())){
+                        file.setSort(i);
+                        break;
+                    }
+                }
+            }
+            return R.status(tableFileService.updateBatchById(tableFileList));
+       }
+       return R.status(true);
+    }
+
 
     @PostMapping("/save_nodeId")
     @ApiOperationSupport(order = 72)
@@ -4523,11 +4661,13 @@ public class ExcelTabController extends BladeController {
                         obj.put("projectId", projectId);
                         obj.put("isCollapseLoad", true);
                         obj.put("isRenderForm", true);
+                        obj.put("isTypePrivatePid", tab.getIsTypePrivatePid());
                         array.add(obj);
                     }
                 }
                 js2.put("orderList", array);
                 js.put("dataInfo", js2);
+                js.put("signType", "1");
                 js.put("isNotDelOldHtml", 1);
                 this.saveBussData2(js);
             }

+ 17 - 2
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/TableFileController.java

@@ -53,7 +53,9 @@ import org.springblade.manager.service.ITableFileService;
 import org.springblade.core.boot.ctrl.BladeController;
 
 import java.rmi.ServerException;
+import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 /**
@@ -136,8 +138,11 @@ public class TableFileController extends BladeController {
                 updateWrapper.set("tab_file_type", 1);
                 wbsTreeContractService.update(updateWrapper);
                 WbsTreeContract wbsTreeContract = wbsTreeContractService.getBaseMapper().selectOne(new QueryWrapper<WbsTreeContract>().eq("p_key_id", tableFile.getTabId()));
-                if(wbsTreeContract.getNodeClass().equals(Integer.valueOf(2))){
-                    InformationQuery infoByWbsId = informationQueryClient.getInfoByWbsId(Long.valueOf(tableFile.getTabId()));
+                if(Objects.equals(wbsTreeContract.getNodeClass(), 2)){
+                    Integer classify =
+                            Arrays.asList("1", "2", "3").contains(wbsTreeContract.getTableOwner()) ? 1 :
+                                    Arrays.asList("4", "5", "6").contains(wbsTreeContract.getTableOwner()) ? 2 : 1;
+                    InformationQuery infoByWbsId = informationQueryClient.getInfoByWbsId(Long.valueOf(tableFile.getTabId()),classify);
                     if(ObjectUtil.isNotEmpty(infoByWbsId)){
                         String sql="DELETE FROM u_information_query WHERE id="+infoByWbsId.getId();
                         jdbcTemplate.execute(sql);
@@ -275,4 +280,14 @@ public class TableFileController extends BladeController {
         }
         return R.data("成功");
     }
+    @PostMapping("/sort")
+    @ApiOperationSupport(order = 1)
+    @ApiOperation(value = "附件排序", notes = "传入listids")
+    public R sort(@RequestBody List<TableFile> list){
+        int i=1;
+        for (TableFile file : list) {
+            file.setSort(i++);
+        }
+      return R.status(tableFileService.updateBatchById(list));
+    }
 }

+ 8 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/feign/ExcelTabClientImpl.java

@@ -38,6 +38,7 @@ import org.springblade.manager.service.IWbsTreePrivateService;
 import org.springblade.manager.utils.ExcelInfoUtils;
 import org.springblade.manager.utils.FileUtils;
 import org.springblade.manager.utils.RandomNumberHolder;
+import org.springblade.manager.vo.AppWbsTreeContractVO;
 import org.springblade.manager.vo.TrialSelfDataRecordVO1;
 import org.springblade.resource.feign.NewIOSSClient;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -884,4 +885,11 @@ public class ExcelTabClientImpl implements ExcelTabClient {
         return R.data(resultMapList);
     }
 
+    @Override
+    public R synPdfKeyInfo(String contractId, String nodeIds, String classify, String projectId, String authorization) throws Exception {
+
+        excelTabService.synPdfKeyInfo(nodeIds, classify, contractId, projectId);
+        return R.success("成功");
+    }
+
 }

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

@@ -1368,6 +1368,7 @@ public class ExecutorMeter extends FormulaExecutor {
                              certificate.setCurrentPeriodEndPay(rebateIncentiveAdvPay.getEndPay());
                              certificate.setCurrentPeriodPay(rebateIncentiveAdvPay.getCurrentPay());
                              certificate.setPreviousPeriodEndPay(rebateIncentiveAdvPay.getPreviousPay());
+                             certificate.setInvertState(BigDecimal.valueOf(-1));
                          }else if("违约罚金".equals(certificate.getChapterSeq())){
                              certificate.setCurrentPeriodPay(ic.getCurrentPeriodPay());
                              ic.setPreviousPeriodEndPay(icPre.getCurrentPeriodEndPay());

+ 32 - 13
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ArchiveTreeContractMapper.xml

@@ -102,6 +102,7 @@
         <result column="value" property="value"/>
         <result column="key" property="key"/>
         <result column="contract_id" property="contractId"/>
+        <result column="project_id" property="projectId"/>
         <result column="has_children" property="hasChildren"/>
         <result column="displayHierarchy" property="displayHierarchy"/>
         <result column="majorDataType" property="majorDataType"/>
@@ -131,7 +132,9 @@
         <result column="reviewer" property="reviewer"/>
         <result column="specification" property="specification"/>
         <result column="archive_name_suffix" property="archiveNameSuffix"/>
-        <result column="tree_number" property="treeNumber"/>
+<!--        <result column="tree_number" property="treeNumber"/>-->
+        <association property="treeNumber" javaType="java.lang.Integer" select="selectFileNumber"
+                     column="{id=id,projectId=project_id,code=code,contractId=contract_id,extType=ext_type}"/>
     </resultMap>
 
 
@@ -230,17 +233,9 @@
         d.specification,
         d.archive_name_suffix,
         d.contract_id,
-        (SELECT CASE WHEN count(1) > 0 THEN 1 ELSE 0 END FROM m_archive_tree_contract WHERE parent_id = d.id and is_deleted = 0 and project_id = #{projectId})
-        AS "has_children",
-        (SELECT  count(1)  FROM m_archive_tree_contract a
-                        inner join u_archive_file b on b.node_id = a.id and b.is_deleted = a.is_deleted and b.project_id = a.project_id and (b.is_auto_file is null or b.is_auto_file != 1)
-                           WHERE  a.is_deleted = 0
-                             and a.project_id = #{projectId}
-                             and (FIND_IN_SET(d.id,a.ancestors) or a.id = d.id)
-        <if test="code!=null and code!=''">
-            AND (a.tree_code = #{code} or a.tree_code = #{contractId} or a.parent_id = 0)
-        </if>
-        ) as tree_number
+        d.project_id,
+        #{code} as code,
+        (SELECT CASE WHEN count(1) > 0 THEN 1 ELSE 0 END FROM m_archive_tree_contract WHERE parent_id = d.id and is_deleted = 0 and project_id = #{projectId}) AS "has_children"
         FROM
         m_archive_tree_contract d
         WHERE
@@ -253,12 +248,35 @@
         </if>
         ORDER BY d.tree_sort, d.sort
     </select>
+    <!-- 文件收集 归档树的文件数量 -->
+    <select id="selectFileNumber" resultType="java.lang.Integer">
+        SELECT  count(1)  FROM m_archive_tree_contract a
+        inner join u_archive_file b on b.node_id = a.id and b.is_deleted = a.is_deleted and b.project_id = a.project_id and (b.is_auto_file is null or b.is_auto_file != 1)
+        WHERE  a.is_deleted = 0
+        and a.project_id = #{projectId}
+        <choose>
+            <when test="extType != null and extType == 1">
+                and ( 	b.node_id in( select id from  m_archive_tree_contract where FIND_IN_SET(#{id},ancestors) or a.id = #{id}) OR
+                b.node_ext_id in(  select id from  m_archive_tree_contract where FIND_IN_SET(#{id},ancestors) or a.id = #{id}))
+            </when>
+            <otherwise>
+                and (FIND_IN_SET(#{id},a.ancestors) or a.id = #{id})
+            </otherwise>
+        </choose>
+
+        <if test="code!=null and code!=''">
+            AND (a.tree_code = #{code} or a.tree_code = #{contractId} or a.parent_id = 0)
+        </if>
+    </select>
+
+
 
     <select id="tree2" resultMap="ArchiveTreeContractVO2ResultMap">
         SELECT
         id,
         parent_id,
         contract_id,
+        project_id,
         node_name AS title,
         id AS "value",
         id AS "key",
@@ -281,7 +299,8 @@
         archive_auto_group_id,
         from_id,
         tree_sort,
-        tree_code
+        tree_code,
+        tree_code as code
         FROM m_archive_tree_contract
         WHERE is_deleted = 0 and project_id = #{projectId}
         <if test=" tenantId!=null and tenantId!='' ">

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

@@ -34,13 +34,14 @@
     </select>
 
     <select id="selectTableFileList" resultMap="TableFileVO">
-        select *,domain_url as url from m_table_file where is_deleted = 0 and type=2 and tab_id = #{pKid}
+        select *,domain_url as url from m_table_file where is_deleted = 0 and type=2 and tab_id = #{pKid} order by sort asc
     </select>
     <select id="getAllFileByIds" resultType="org.springblade.manager.entity.TableFile">
         SELECT mtf.* from m_table_file mtf WHERE is_deleted = 0 and classify = #{classify} and type = 2 and tab_id in
         <foreach collection="ids" item="id" open="(" close=")" separator=",">
             #{id}
         </foreach>
+        ORDER BY sort ASC
     </select>
 
     <delete id="delDataById">
@@ -51,10 +52,10 @@
     </delete>
 
     <select id="selectTableFileListByTen" resultMap="TableFileVO">
-        select *,domain_url as url from m_table_file where is_deleted = 0  and classify = #{classify} and type in (10,11,12,20,21,22) and tab_id = #{pKid}
+        select *,domain_pdf_url as url from m_table_file where is_deleted = 0  and classify = #{classify} and type in (10,11,12,20,21,22) and tab_id = #{pKid} Order by sort ASC
     </select>
 
     <select id="selectTableFileList1" resultMap="TableFileVO">
-        select *,domain_url as url from m_table_file where is_deleted = 0 and (type=20 or type=21 or type=22) and tab_id = #{pKid}
+        select *,domain_pdf_url as url from m_table_file where is_deleted = 0 and (type=20 or type=21 or type=22) and tab_id = #{pKid} Order by sort ASC
     </select>
 </mapper>

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

@@ -437,7 +437,13 @@
     <select id="updateAllNodeTabById" resultType="org.springblade.manager.entity.WbsTreeContract">
         update m_wbs_tree_contract
         set excel_id= #{aPrivate.excelId},
-            node_name = #{aPrivate.nodeName},
+            node_name = CASE
+                            WHEN LOCATE('_PL_', node_name) > 0 THEN
+                                CONCAT( #{aPrivate.nodeName}, SUBSTRING(node_name, LOCATE('_PL_', node_name), LENGTH(node_name)))
+                            WHEN LOCATE('__', node_name) > 0 THEN
+                                CONCAT( #{aPrivate.nodeName},  SUBSTRING(node_name, LOCATE('__', node_name), LENGTH(node_name)))
+                            ELSE #{aPrivate.nodeName}
+                END,
             full_name = #{aPrivate.fullName},
             init_table_name = #{aPrivate.initTableName},
             is_link_table = 2,

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

@@ -106,7 +106,7 @@ public interface IExcelTabService extends BaseService<ExcelTab> {
     /**
      * 结果信息持久化
      */
-    R<Object> saveOrUpdateInfo(List<TableInfo> tableInfoList) throws SQLException;
+    R<Object> saveOrUpdateInfo(List<TableInfo> tableInfoList,String singType) throws SQLException;
 
     Map<String, String> getTablbCols(String pkeyid, String colkey) throws FileNotFoundException;
 
@@ -122,6 +122,8 @@ public interface IExcelTabService extends BaseService<ExcelTab> {
     // 多个pdf 合并
     void getBussPdfs(String nodeId, String classify, String contractId, String projectId) throws Exception;
 
+    void synPdfKeyInfo(String nodeId, String classify, String contractId, String projectId) throws Exception;
+
     // 试验
 
     /**

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

@@ -89,6 +89,8 @@ public interface IWbsTreeContractService extends BaseService<WbsTreeContract> {
 
     EKeyDto getEKey(String contractId, Long pKeyId, String wbsId);
 
+    boolean checkNodeAllDate(WbsTreeContract contract);
+
     Integer findIsExistTreeNode(List<String> ids);
 
     List<WbsTreeContract> queryListByPIds(List<Long> pIds);

部分文件因文件數量過多而無法顯示