Răsfoiți Sursa

Merge remote-tracking branch 'origin/test-merge' into test-merge

LHB 4 zile în urmă
părinte
comite
678df1f945

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

@@ -1,252 +1,252 @@
-/*
-
-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.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;
-            }
-        }
-    }
-}
-*/
+//
+//
+//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.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;
+//            }
+//        }
+//    }
+//}
+//

+ 50 - 44
blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveAiNameServiceImpl.java

@@ -24,7 +24,7 @@ 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;
@@ -34,6 +34,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
+import java.io.IOException;
 import java.text.SimpleDateFormat;
 import java.util.*;
 import java.util.concurrent.Semaphore;
@@ -57,55 +58,60 @@ public class ArchiveAiNameServiceImpl extends BaseServiceImpl<ArchiveAiNameMappe
 	@Autowired
 	private JdbcTemplate jdbcTemplate;
 
-	@Autowired
-	private DeepSeekClient deepSeekClient;
+//	@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
+//	@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 void syncCreatAiName(List<ArchiveAiName> aiNames) throws IOException {
+
+    }
+
+    @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));

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

@@ -56,7 +56,6 @@ 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;

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

@@ -240,7 +240,6 @@
             )
         </if>
         order by
-        u.sort,
         <if test="vo.nodeIds != null and vo.nodeIds != ''">
             case
             when t.tree_sort regexp '^[a-zA-Z]' then 0  -- 字母开头的排在前面
@@ -249,7 +248,7 @@
             end,
             t.tree_sort,
         </if>
-        u.sort_num,u.create_time
+        u.sort,u.sort_num,u.create_time
         limit #{current}, #{size}
     </select>
 

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

@@ -3,6 +3,8 @@ package org.springblade.business.service.impl;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
 import org.apache.commons.lang.StringUtils;
 import org.springblade.archive.feign.ArchiveInspectionInfoClient;
 import org.springblade.business.entity.ArchiveFile;
@@ -129,6 +131,7 @@ public class ArchiveFileServiceImpl extends BaseServiceImpl<ArchiveFileMapper, A
         this.saveBatch(JSONArray.parseArray(JSONObject.toJSONString(list), ArchiveFile.class));
     }
 
+
     @Override
     public void updateArchiveFileSort(List<ArchiveFileVO> list) {
         List<Integer> listInt = new ArrayList<>();
@@ -140,17 +143,54 @@ public class ArchiveFileServiceImpl extends BaseServiceImpl<ArchiveFileMapper, A
         StringBuffer ids2 = new StringBuffer();
         Map<Long, Integer> mapkey = new HashMap<>();
         Collections.sort(listInt);
+
+        // 创建原始ID到原始nodeId的映射
+        Map<Long, String> originalIdToNodeIdMap = new HashMap<>();
+        // 创建原始ID到原始排序的映射
+        Map<Long, Integer> originalIdToSortMap = new HashMap<>();
+        for (ArchiveFileVO vo : list) {
+            originalIdToNodeIdMap.put(vo.getId(), vo.getNodeId());
+            originalIdToSortMap.put(vo.getId(), vo.getSort());
+        }
+
         for (int i = 0; i < list.size(); i++) {
-            ids2.append(list.get(i).getId() + ",");
-            list.get(i).setSort(listInt.get(i));
-            list.get(i).setArchiveSort(i);
-            if (list.get(i).getIsUpdateUrl() != null && list.get(i).getIsUpdateUrl() == 1) {
-                ids.append(list.get(i).getId() + ",");
-                if (list.get(i).getRectification() != null && list.get(i).getRectification() == 1) {
-                    list.get(i).setRectification(2);
+            ArchiveFileVO currentVO = list.get(i);
+            ids2.append(currentVO.getId() + ",");
+
+            // 保存原始数据
+            String originalNodeId = originalIdToNodeIdMap.get(currentVO.getId());
+            Integer originalSort = originalIdToSortMap.get(currentVO.getId());
+
+            // 设置新的排序值
+            currentVO.setSort(listInt.get(i));
+            currentVO.setArchiveSort(i);
+
+            // 只有位置发生变化的文件才需要更新nodeId
+            if (!listInt.get(i).equals(originalSort)) {
+                // 获取下一个文件的nodeId(如果存在)
+                if (i < list.size() - 1) {
+                    ArchiveFileVO nextVO = list.get(i + 1);
+                    String nextNodeId = originalIdToNodeIdMap.get(nextVO.getId());
+
+                    // 将当前文件的nodeId设置为下一个文件的nodeId
+                    currentVO.setNodeId(nextNodeId);
+                } else {
+                    // 如果是最后一个文件且被移动了,保持原来的nodeId
+                    currentVO.setNodeId(originalNodeId);
+                }
+            } else {
+                // 位置没有变化的文件保持原来的nodeId
+                currentVO.setNodeId(originalNodeId);
+            }
+
+            if (currentVO.getIsUpdateUrl() != null && currentVO.getIsUpdateUrl() == 1) {
+                ids.append(currentVO.getId() + ",");
+                if (currentVO.getRectification() != null && currentVO.getRectification() == 1) {
+                    currentVO.setRectification(2);
                 }
             }
         }
+
         // 删除oss文件
         if (ids != null && ids.length() > 0) {
             List<String> removeFiles = new ArrayList<>();

+ 8 - 2
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreePrivateController.java

@@ -475,8 +475,8 @@ public class WbsTreePrivateController extends BladeController {
             @ApiImplicitParam(name = "parentId", value = "父级id"),
             @ApiImplicitParam(name = "projectId", value = "项目id")
     })
-    public R<List<WbsTreePrivateVO>> lazyTree(String wbsId, String wbsType, Long parentId, String projectId) {
-        List<WbsTreePrivateVO> tree = wbsTreePrivateService.lazyTree(wbsId, wbsType, parentId, projectId);
+    public R<List<WbsTreePrivateVO>> lazyTree(String wbsId, String wbsType, Long parentId, String projectId,Integer type) {
+        List<WbsTreePrivateVO> tree = wbsTreePrivateService.lazyTree(wbsId, wbsType, parentId, projectId,type);
         if (tree != null && tree.size() > 0) {
             return R.data(tree);
         }
@@ -1097,4 +1097,10 @@ public class WbsTreePrivateController extends BladeController {
         IPage<TreeNodeVOByTabType> page = wbsTreePrivateService.tabTypeLazyTreeByProject(Condition.getPage(query), parentId, projectId, titleName);
         return R.data(page);
     }
+    @PostMapping("/copyNode")
+    @ApiOperationSupport(order = 50)
+    @ApiOperation(value = "复制节点")
+    public R copyNode(List<String>leftIds,List<String>rightIds){
+        return R.status(wbsTreePrivateService.copyNode(leftIds,rightIds));
+    }
 }

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

@@ -39,7 +39,7 @@ public interface WbsTreePrivateMapper extends EasyBaseMapper<WbsTreePrivate> {
 
     void updateDeletedByCondition(String id, String wbsId, String projectId);
 
-    List<WbsTreePrivateVO> lazyTree(String wbsId, Integer wbsType, Long parentId, String projectId);
+    List<WbsTreePrivateVO> lazyTree(String wbsId, Integer wbsType, Long parentId, String projectId,Integer type);
 
     List<TreeNodeVOByTabType> tabTypeLazyTree(IPage page, Long parentId, String projectId, String titleName);
 
@@ -155,4 +155,6 @@ public interface WbsTreePrivateMapper extends EasyBaseMapper<WbsTreePrivate> {
     List<ArchiveSyncLogVO> getContractAllLogMonthPack(@Param("contractId") Long contractId);
 
     List<Long> getContractAllLogWbsNodeIds(@Param("contractId") Long contractId);
+
+    List<WbsTreePrivate> selectAllChildNode(@Param("leftIds") List<String> leftIds);
 }

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

@@ -387,6 +387,9 @@
             m_wbs_tree_private d
         WHERE
             d.is_deleted = 0
+        <if test="type != null and wbsType != '' and type =1">
+          AND  (d.is_buss_show != 1 OR d.is_buss_show IS NULL)
+        </if>
         AND d.parent_id = #{parentId}
         AND d.project_id = #{projectId}
             <if test="wbsType != null and wbsType != '' and wbsType != -1">
@@ -1063,4 +1066,16 @@
         select DISTINCT wbs_node_id from u_contract_log  WHERE
             contract_id = #{contractId}
     </select>
+    <select id="selectAllChildNode" resultType="org.springblade.manager.entity.WbsTreePrivate">
+        SELECT DISTINCT *
+        FROM m_wbs_tree_private
+        WHERE is_deleted = 0
+        <if test="leftList != null and leftList.size() > 0">
+            AND (
+            <foreach collection="leftList" item="item" separator=" OR ">
+                FIND_IN_SET(#{item}, ancestors_p_id)
+            </foreach>
+            )
+        </if>
+    </select>
 </mapper>

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

@@ -26,7 +26,7 @@ public interface IWbsTreePrivateService extends BaseService<WbsTreePrivate> {
 
     boolean removeTableByCondition(String id, String wbsId, String projectId);
 
-    List<WbsTreePrivateVO> lazyTree(String wbsId, String wbsType, Long parentId, String projectId);
+    List<WbsTreePrivateVO> lazyTree(String wbsId, String wbsType, Long parentId, String projectId,Integer type);
 
     // 项目级 表单类型划分
     IPage<TreeNodeVOByTabType> tabTypeLazyTree(IPage<TreeNodeVOByTabType> page, Long parentId, String projectId, String titleName);
@@ -115,4 +115,6 @@ public interface IWbsTreePrivateService extends BaseService<WbsTreePrivate> {
     List<ArchiveSyncLogVO> getContractAllLogMonthPack(Long contractId);
 
     List<Long> getContractAllLogWbsNodeIds(Long contractId);
+
+    boolean copyNode(List<String> leftIds, List<String> rightIds);
 }

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

@@ -2954,15 +2954,15 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
             for (int i = 2; i <= sheet.getLastRowNum(); i++) {
                 Row row = sheet.getRow(i);
                 if (row == null) continue;
-                if(StringUtils.isEmpty(getCellValue(row.getCell(1)))){
-                    throw new ServerException("单位工程类型名称不能为空");
-                }
-                if(StringUtils.isEmpty(getCellValue(row.getCell(3)))){
-                    throw new ServerException("单位工程名称不能为空");
-                }
-                if(StringUtils.isEmpty(getCellValue(row.getCell(5)))){
-                    throw new ServerException("分部工程名称不能为空");
-                }
+//                if(StringUtils.isEmpty(getCellValue(row.getCell(1)))){
+//                    throw new ServerException("单位工程类型名称不能为空");
+//                }
+//                if(StringUtils.isEmpty(getCellValue(row.getCell(3)))){
+//                    throw new ServerException("单位工程名称不能为空");
+//                }
+//                if(StringUtils.isEmpty(getCellValue(row.getCell(5)))){
+//                    throw new ServerException("分部工程名称不能为空");
+//                }
                 // 获取每一列的值
                 String unitCode = getCellValue(row.getCell(0)); // A列:单位工程编号
                 String unitName = getCellValue(row.getCell(1)); // B列:单位工程名称

+ 108 - 2
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreePrivateServiceImpl.java

@@ -260,10 +260,10 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
     }
 
     @Override
-    public List<WbsTreePrivateVO> lazyTree(String wbsId, String wbsType, Long parentId, String projectId) {
+    public List<WbsTreePrivateVO> lazyTree(String wbsId, String wbsType, Long parentId, String projectId, Integer type) {
         //获取请求头中的authorization
         String headerAuthorization = getHeaderAuthorization();
-        List<WbsTreePrivateVO> wbsTreePrivateVOS = baseMapper.lazyTree(wbsId, Integer.valueOf(wbsType), parentId, projectId);
+        List<WbsTreePrivateVO> wbsTreePrivateVOS = baseMapper.lazyTree(wbsId, Integer.valueOf(wbsType), parentId, projectId,type);
         //判断如果是客户端就进入分支 把包含委托单的节点删除
         if (headerAuthorization != null && !"".equals(headerAuthorization) && headerAuthorization.contains("client_secret") && wbsTreePrivateVOS.size() > 0) {
             JSONArray objects = JSONUtil.parseArray(wbsTreePrivateVOS);
@@ -3205,6 +3205,112 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
         return baseMapper.getContractAllLogWbsNodeIds(contractId);
     }
 
+    @Override
+    public boolean copyNode(List<String> leftIds, List<String> rightIds) {
+        List<WbsTreePrivate> leftLists = baseMapper.selectAllChildNode(leftIds);
+        for (String rightId : rightIds) {
+            // 每次循环都创建一个新的集合作为副本
+            List<WbsTreePrivate> workingList = leftLists.stream()
+                    .map(node -> {
+                        // 创建每个节点的副本
+                        WbsTreePrivate copy = new WbsTreePrivate();
+                        BeanUtils.copyProperties(copy, node);
+                        return copy;
+                    })
+                    .collect(Collectors.toList());
+            WbsTreePrivate rightWbsTreePrivate = baseMapper.getByPKeyId(Long.parseLong(rightId));
+
+            // 找到leftLists中所有的根节点(没有在leftLists中作为子节点出现的节点)
+            Set<Long> allPIds = workingList.stream()
+                    .map(WbsTreePrivate::getPId)
+                    .filter(Objects::nonNull)
+                    .collect(Collectors.toSet());
+
+            List<WbsTreePrivate> rootNodes = workingList.stream()
+                    .filter(node -> !allPIds.contains(node.getPKeyId()))
+                    .collect(Collectors.toList());
+
+            // 为每个根节点重新设置属性,并将其放到rightWbsTreePrivate节点下
+            for (WbsTreePrivate rootNode : rootNodes) {
+                // 重新分配节点值
+                reassignNodeValues(workingList, rootNode, rightWbsTreePrivate);
+            }
+            this.insertBatch(workingList,500);
+        }
+        return true;
+    }
+    // 添加一个辅助方法来重新分配节点值
+    private void reassignNodeValues(List<WbsTreePrivate> leftLists, WbsTreePrivate rootNode, WbsTreePrivate rightWbsTreePrivate) {
+        // 创建节点映射以便快速查找
+        Map<Long, WbsTreePrivate> nodeMap = leftLists.stream()
+                .collect(Collectors.toMap(WbsTreePrivate::getPKeyId, node -> node));
+
+        // 为根节点生成新的随机ID
+        Long newRootId = SnowFlakeUtil.getId();
+        Long newRootPKeyId = SnowFlakeUtil.getId();
+
+        // 设置根节点属性,使其成为rightWbsTreePrivate的子节点
+        rootNode.setId(newRootId);
+        rootNode.setPKeyId(newRootPKeyId);
+        rootNode.setParentId(rightWbsTreePrivate.getId());
+        rootNode.setPId(rightWbsTreePrivate.getPKeyId());
+
+        // ancestors设置为rightWbsTreePrivate的ancestors加上rightWbsTreePrivate的id
+        if (rightWbsTreePrivate.getAncestors() != null && !rightWbsTreePrivate.getAncestors().isEmpty()) {
+            rootNode.setAncestors(rightWbsTreePrivate.getAncestors() + "," + rightWbsTreePrivate.getId());
+        } else {
+            rootNode.setAncestors(String.valueOf(rightWbsTreePrivate.getId()));
+        }
+
+        // ancestors_p_id设置为rightWbsTreePrivate的ancestors_p_id加上rightWbsTreePrivate的pKeyId
+        if (rightWbsTreePrivate.getAncestorsPId() != null && !rightWbsTreePrivate.getAncestorsPId().isEmpty()) {
+            rootNode.setAncestorsPId(rightWbsTreePrivate.getAncestorsPId() + "," + rightWbsTreePrivate.getPKeyId());
+        } else {
+            rootNode.setAncestorsPId(String.valueOf(rightWbsTreePrivate.getPKeyId()));
+        }
+
+        // 更新所有子节点
+        updateChildNodes(nodeMap, rootNode, rootNode.getAncestors(), rootNode.getAncestorsPId(), newRootPKeyId);
+    }
+
+    // 递归更新子节点属性
+    private void updateChildNodes(Map<Long, WbsTreePrivate> nodeMap, WbsTreePrivate parentNode, String parentAncestors, String parentAncestorsPId, Long parentPKeyId) {
+        // 查找当前节点的所有直接子节点(通过pId匹配父节点的pKeyId)
+        List<WbsTreePrivate> childNodes = nodeMap.values().stream()
+                .filter(node -> node.getPId() != null && node.getPId().equals(parentNode.getPKeyId()))
+                .collect(Collectors.toList());
+
+        // 更新每个子节点的属性
+        for (WbsTreePrivate childNode : childNodes) {
+            // 为子节点生成新的随机ID
+            Long newChildId = SnowFlakeUtil.getId();
+            Long newChildPKeyId = SnowFlakeUtil.getId();
+
+            // id设置为新的随机ID
+            childNode.setId(newChildId);
+
+            // pKeyId设置为新的随机ID
+            childNode.setPKeyId(newChildPKeyId);
+
+            // parentId设置为父节点的id
+            childNode.setParentId(parentNode.getId());
+
+            // pId设置为父节点的pKeyId
+            childNode.setPId(parentPKeyId);
+
+            // ancestors设置为父节点的ancestors加上父节点的id
+            childNode.setAncestors(parentAncestors + "," + parentNode.getId());
+
+            // ancestors_p_id设置为父节点的ancestors_p_id加上父节点的pKeyId
+            childNode.setAncestorsPId(parentAncestorsPId + "," + parentPKeyId);
+
+            // 递归更新孙子节点
+            updateChildNodes(nodeMap, childNode, childNode.getAncestors(), childNode.getAncestorsPId(), newChildPKeyId);
+        }
+    }
+
+
+
     public void diGuiWbs(int i) {
         QueryWrapper<WbsTreePrivate> wbsTreePrivateQueryWrapper = new QueryWrapper<>();
         wbsTreePrivateQueryWrapper.select("p_key_id", "id", "p_id", "wbs_id", "project_id", "parent_id", "ancestors");

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

@@ -503,7 +503,7 @@ public class WbsTreeServiceImpl extends BaseServiceImpl<WbsTreeMapper, WbsTree>
             if (("1").equals(type)) {//节点
                 if (ObjectUtil.isEmpty(projectId)) {//公有
                     Set<WbsTree> resultNodes = new HashSet<>();
-                    List<WbsTree> wbsTrees = baseMapper.selectList(Wrappers.<WbsTree>lambdaQuery().eq(WbsTree::getType, 1).eq(WbsTree::getWbsId, wbsId).like(WbsTree::getNodeName, queryValue));
+                    List<WbsTree> wbsTrees = baseMapper.selectList(Wrappers.<WbsTree>lambdaQuery().eq(WbsTree::getType, 1).eq(WbsTree::getWbsId, wbsId).and(wrapper -> wrapper.like(WbsTree::getNodeName, queryValue).or().like(WbsTree::getImportMatchingInfo, queryValue)));
                     this.getParentNodesPublicWbs(wbsTrees, resultNodes);
                     resultNodes.addAll(wbsTrees);
                     List<WbsTreeQueryValueVO> wbsTreeQueryValueVOS = BeanUtil.copyProperties(resultNodes, WbsTreeQueryValueVO.class);
@@ -516,7 +516,7 @@ public class WbsTreeServiceImpl extends BaseServiceImpl<WbsTreeMapper, WbsTree>
                     }
                 } else {//私有
                     Set<WbsTreePrivate> resultNodes = new HashSet<>();
-                    List<WbsTreePrivate> wbsTreePrivates = wbsTreePrivateMapper.selectList(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getType, 1).eq(WbsTreePrivate::getWbsId, wbsId).eq(WbsTreePrivate::getProjectId, projectId).like(WbsTreePrivate::getNodeName, queryValue));
+                    List<WbsTreePrivate> wbsTreePrivates = wbsTreePrivateMapper.selectList(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getType, 1).eq(WbsTreePrivate::getWbsId, wbsId).eq(WbsTreePrivate::getProjectId, projectId).and(wrapper -> wrapper.like(WbsTreePrivate::getNodeName, queryValue).or().like(WbsTreePrivate::getFullName, queryValue)));
                     this.getParentNodesPrivateWbs(wbsTreePrivates, resultNodes, projectId, wbsId);
                     resultNodes.addAll(wbsTreePrivates);
                     List<WbsTreePrivateQueryValueVO> wbsTreePrivateQueryValueVOS = BeanUtil.copyProperties(resultNodes, WbsTreePrivateQueryValueVO.class);