Kaynağa Gözat

Merge branch 'dev' of http://219.151.181.73:3000/zhuwei/bladex into dev

lvy 1 ay önce
ebeveyn
işleme
d418d7e218
13 değiştirilmiş dosya ile 469 ekleme ve 83 silme
  1. 17 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/FindAndReplaceDto1.java
  2. 8 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/feign/ArchiveFileClient.java
  3. 11 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/dto/MoveNodeDTO.java
  4. 20 0
      blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchiveFileController.java
  5. 7 2
      blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java
  6. 103 0
      blade-service/blade-business/src/main/java/org/springblade/business/feignClient/ArchiveFileClientImpl.java
  7. 2 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/ArchiveFileMapper.java
  8. 9 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/ArchiveFileMapper.xml
  9. 13 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreeContractController.java
  10. 8 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreeContractMapper.java
  11. 28 7
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreeContractMapper.xml
  12. 8 2
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IWbsTreeContractService.java
  13. 235 71
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeContractServiceImpl.java

+ 17 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/FindAndReplaceDto1.java

@@ -0,0 +1,17 @@
+package org.springblade.business.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springblade.archive.dto.FindAndReplaceDto;
+import org.springblade.business.entity.ArchiveFile;
+
+import java.util.List;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class FindAndReplaceDto1 {
+    private FindAndReplaceDto dto;
+    private List<ArchiveFile> list;
+}

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

@@ -4,7 +4,9 @@ import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import org.springblade.archive.dto.FindAndReplaceDto;
 import org.springblade.archive.dto.SendsWebSocketArchiveDTO;
+import org.springblade.business.dto.FindAndReplaceDto1;
 import org.springblade.business.entity.ArchiveFile;
 import org.springblade.business.vo.ArchiveFileVO;
 import org.springblade.common.constant.BusinessConstant;
@@ -167,4 +169,10 @@ public interface ArchiveFileClient {
 
     @PostMapping(API_PREFIX + "/getArchiveFileByArchiveIds")
     List<ArchiveFile> getArchiveFileByArchiveIds(@RequestParam String archiveIds);
+
+    @PostMapping(API_PREFIX + "/findAndReplace")
+    boolean findAndReplace(@RequestBody FindAndReplaceDto1 dto1);
+
+    @PostMapping(API_PREFIX + "/getAllArchiveFileByIds")
+    List<ArchiveFile> getAllArchiveFileByIds(@RequestBody List<String> strList);
 }

+ 11 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/dto/MoveNodeDTO.java

@@ -0,0 +1,11 @@
+package org.springblade.manager.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class MoveNodeDTO {
+    private List<Long> leftPkeyIds;
+    private Long rightPkeyId;
+}

+ 20 - 0
blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchiveFileController.java

@@ -10,9 +10,12 @@ import io.swagger.annotations.*;
 import lombok.AllArgsConstructor;
 import lombok.SneakyThrows;
 import org.apache.commons.lang.StringUtils;
+import org.springblade.archive.dto.FindAndReplaceDto;
+import org.springblade.archive.entity.ArchivesAuto;
 import org.springblade.archive.service.IArchivesAutoService;
 import org.springblade.archive.utils.FileUtils;
 import org.springblade.archive.vo.ArchiveDataVo;
+import org.springblade.business.dto.FindAndReplaceDto1;
 import org.springblade.business.entity.ArchiveFile;
 import org.springblade.business.feign.ArchiveFileClient;
 import org.springblade.business.feign.MetadataClassificationClient;
@@ -461,4 +464,21 @@ public class ArchiveFileController extends BladeController {
         }
         return  R.success("操作成功");
     }
+
+    @PostMapping("/findAndReplace")
+    @ApiOperationSupport(order = 12)
+    @ApiOperation(value = "查找并替换", notes = "传入ids")
+    public R findAndReplace(@RequestBody FindAndReplaceDto dto){
+        List<ArchiveFile> archiveFiles = archiveFileClient.getAllArchiveFileByArchiveIds(Func.toStrList(dto.getIds()));
+        return R.status(archiveFileClient.findAndReplace(archiveFiles,dto));
+    }
+
+    @PostMapping("/findAndReplace")
+    @ApiOperationSupport(order = 12)
+    @ApiOperation(value = "查找并替换", notes = "传入ids")
+    public R findAndReplace(@RequestBody FindAndReplaceDto dto){
+        List<ArchiveFile> archiveFiles = archiveFileClient.getAllArchiveFileByIds(Func.toStrList(dto.getIds()));
+        FindAndReplaceDto1 dto1 = new FindAndReplaceDto1(dto, archiveFiles);
+        return R.status(archiveFileClient.findAndReplace(dto1));
+    }
 }

+ 7 - 2
blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java

@@ -222,7 +222,7 @@ public class InformationWriteQueryController extends BladeController {
         String sgSuffix="";
         String jlSuffix="";
         if(queryList.size()>0){
-            String sql1="Select sg_suffix,jl_suffix from m_project_info where id="+queryList.get(0).getProjectId()+" and is_deleted=0";
+            String sql1="Select sg_suffix,jl_suffix,template_type from m_project_info where id="+queryList.get(0).getProjectId()+" and is_deleted=0";
             List<ProjectInfo> projectInfos = jdbcTemplate.query(sql1, new BeanPropertyRowMapper<>(ProjectInfo.class));
             if(projectInfos.size()>0){
                 sgSuffix=projectInfos.get(0).getSgSuffix()==null?"":projectInfos.get(0).getSgSuffix();
@@ -238,7 +238,11 @@ public class InformationWriteQueryController extends BladeController {
                     if (nameRuleList != null && nameRuleList.getData() != null && !nameRuleList.getData().isEmpty()) {
                         nameRule = String.join("-", nameRuleList.getData());
                     }
-                    result  = nodeBaseInfoServiceClient.getNameRuleByRule(nameRule, contract.getPKeyId()+"");
+                    if(projectInfos.get(0)!=null&&projectInfos.get(0).getTemplateType()==2){
+                        result  = nodeBaseInfoServiceClient.getNameRuleByRule(nameRule, contract.getPKeyId()+"");
+                    }else {
+                        result=wbsParamClient.createFileTitle(contract);
+                    }
                 }else {
                     result=nodeNameMap.get(query.getId());
                     //同时修改工程划分节点命名规则
@@ -272,6 +276,7 @@ public class InformationWriteQueryController extends BladeController {
         return R.status(this.informationQueryService.updateBatchById(queryList));
     }
 
+
     public List<String> getNameRuleByPkeyId(Long pKeyId, Long projectId) {
         NameRuleVo vo = new NameRuleVo();
         String sql2="select * from m_wbs_param where node_id="+pKeyId+" and type=200"+" and is_deleted=0 and k='FILE_TITLE'";

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

@@ -8,7 +8,10 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.AllArgsConstructor;
 import org.apache.commons.lang.StringUtils;
+import org.springblade.archive.dto.FindAndReplaceDto;
+import org.springblade.archive.entity.ArchivesAuto;
 import org.springblade.archive.vo.ArchivesAutoVO;
+import org.springblade.business.dto.FindAndReplaceDto1;
 import org.springblade.business.entity.ArchiveFile;
 import org.springblade.business.feign.ArchiveFileClient;
 import org.springblade.business.mapper.ArchiveFileMapper;
@@ -16,6 +19,7 @@ import org.springblade.business.service.IArchiveFileService;
 import org.springblade.business.service.ITaskService;
 import org.springblade.business.vo.ArchiveFileVO;
 import org.springblade.common.utils.FileUtils;
+import org.springblade.core.log.exception.ServiceException;
 import org.springblade.manager.entity.ContractInfo;
 import org.springblade.manager.enums.StorageTypeEnum;
 import org.springblade.manager.feign.ContractClient;
@@ -25,6 +29,8 @@ import org.springframework.web.bind.annotation.RestController;
 import java.math.BigDecimal;
 import java.util.*;
 import java.util.function.Function;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
 
@@ -352,4 +358,101 @@ public class ArchiveFileClientImpl implements ArchiveFileClient {
         return iArchiveFileService.getArchiveFileByArchivesId(archiveIds,null);
     }
 
+    @Override
+    public boolean findAndReplace(FindAndReplaceDto1 dto1) {
+        List<ArchiveFile> archiveFiles = dto1.getList();
+        FindAndReplaceDto dto = dto1.getDto();
+        List<ArchiveFile> updates = new ArrayList<>();
+
+        for (ArchiveFile archiveFile : archiveFiles) {
+            String originalName = archiveFile.getFileName();
+            if (StringUtils.isEmpty(originalName) || StringUtils.isEmpty(dto.getQuery())) {
+                continue;
+            }
+
+            if (!originalName.contains(dto.getQuery())) {
+                continue;
+            }
+
+            String newName = processFileName(originalName, dto);
+            if (!originalName.equals(newName)) {
+                ArchiveFile update = new ArchiveFile();
+                update.setId(archiveFile.getId());
+                update.setFileName(newName);
+                updates.add(update);
+            }
+        }
+
+        if (!updates.isEmpty()) {
+            return iArchiveFileService.updateBatchById(updates);
+        }
+        return true;
+    }
+
+    private String processFileName(String fileName, FindAndReplaceDto dto) {
+        String query = dto.getQuery();
+        String replace = dto.getReplace();
+
+        switch (dto.getType()) {
+            case 1: // 在指定位置插入
+                return handleInsertAtPosition(fileName, query, replace, dto.getPosition());
+
+            case 2: // 普通替换
+                return handleReplace(fileName, query, replace, false);
+
+            default: // 删除匹配内容
+                return handleReplace(fileName, query, "", true);
+        }
+    }
+
+    private String handleInsertAtPosition(String fileName, String query, String replace, Integer position) {
+        if (position == null) {
+            return fileName; // 没有指定位置时保持原样
+        }
+
+        StringBuilder sb = new StringBuilder();
+        int lastIndex = 0;
+        int index = fileName.indexOf(query);
+
+        while (index != -1) {
+            // 添加未处理部分
+            sb.append(fileName, lastIndex, index);
+
+            // 根据位置插入内容
+            switch (position) {
+                case 1: // 在查询内容前插入
+                    sb.append(replace).append(query);
+                    break;
+                case 2: // 在查询内容后插入
+                    sb.append(query).append(replace);
+                    break;
+                default:
+                    throw new ServiceException("请选择正确的定位条件");
+            }
+
+            lastIndex = index + query.length();
+            index = fileName.indexOf(query, lastIndex);
+        }
+
+        // 添加剩余部分
+        sb.append(fileName.substring(lastIndex));
+        return sb.toString();
+    }
+
+    private String handleReplace(String fileName, String query, String replacement, boolean isLiteral) {
+        if (isLiteral) {
+            // 字面量替换(避免正则表达式特殊字符问题)
+            return fileName.replace(query, replacement);
+        } else {
+            // 使用正则表达式替换,需要转义特殊字符
+            String escapedQuery = Pattern.quote(query); // 自动转义所有特殊字符
+            return fileName.replaceAll(escapedQuery, Matcher.quoteReplacement(replacement));
+        }
+    }
+
+    @Override
+    public List<ArchiveFile> getAllArchiveFileByIds(List<String> strList) {
+        return fileMapper.getAllArchiveFileByIds(strList);
+    }
+
 }

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

@@ -120,4 +120,6 @@ public interface ArchiveFileMapper extends BaseMapper<ArchiveFile> {
      * @return
      */
     Map<String, BigDecimal> getAllArchiveAutoByContractTypeSummary(@Param("projectId") Long projectId);
+
+    List<ArchiveFile> getAllArchiveFileByIds(@Param("strList") List<String> strList);
 }

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

@@ -554,4 +554,13 @@
       ) a
 
     </select>
+    <select id="getAllArchiveFileByIds" resultType="org.springblade.business.entity.ArchiveFile">
+        select * from u_archive_file where is_deleted = 0
+        <if test="strList != null and strList != ''">
+            and id in
+            <foreach collection="strList" item="id" open="(" separator="," close=")">
+                #{id}
+            </foreach>
+        </if>
+    </select>
 </mapper>

+ 13 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreeContractController.java

@@ -38,6 +38,7 @@ import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.utils.IoUtil;
 import org.springblade.core.tool.utils.ObjectUtil;
 import org.springblade.core.tool.utils.ResourceUtil;
+import org.springblade.manager.dto.MoveNodeDTO;
 import org.springblade.manager.dto.TableSortDTO;
 import org.springblade.manager.dto.WbsTreeContractDTO2;
 import org.springblade.manager.entity.*;
@@ -868,7 +869,19 @@ public class WbsTreeContractController extends BladeController {
         return iWbsTreeContractService.exportTree(contractId,response);
     }
 
+    @GetMapping("/getSiblingWbsContract")
+    @ApiOperation(value = "获取同一层级的所有节点节点")
+    @ApiOperationSupport(order = 32)
+    public R <List<WbsTreeContract>> getSiblingWbsContract(@RequestParam Long pKeyId){
+        return iWbsTreeContractService.getSiblingWbsContract(pKeyId);
+    }
 
+    @PostMapping("/moveNode")
+    @ApiOperation(value = "跨节点移动")
+    @ApiOperationSupport(order = 33)
+    public R moveNode (@RequestBody MoveNodeDTO dto){
+        return iWbsTreeContractService.moveNode(dto);
+    }
 
 
 

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

@@ -176,6 +176,13 @@ public interface WbsTreeContractMapper extends EasyBaseMapper<WbsTreeContract> {
 
     void updatePartitionCodeByPKyId(@Param("wbsTreeContract") WbsTreeContract wbsTreeContract);
 
-    Integer findIsExistTreeNode(List<String> ids);
+    List<WbsTreeContract> getSiblingWbsContract(@Param("pKeyId") Long pKeyId);
 
+    List<WbsTreeContract> getWbsTreeContractsByPKeyIds(@Param("pKeyIds") List<Long> pKeyIds);
+
+    List<WbsTreeContract> getChildWbsTreeContracts(@Param("pKeyId") Long pKeyId);
+
+    void updateAncestorsPid(@Param("ancestorsPId") String ancestorsPId, @Param("ancestors") String ancestors,@Param("pKeyId")Long pKeyId);
+
+    void updateWbsTreeAncestors(@Param("contract")WbsTreeContract contract);
 }

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

@@ -843,6 +843,14 @@
             WHERE p_key_id = #{wbsTreeContract.pKeyId}
         </if>
     </update>
+    <update id="updateAncestorsPid">
+        UPDATE m_wbs_tree_contract
+        SET ancestors_p_id = #{ancestorsPId},ancestors = #{ancestors}
+        WHERE p_key_id = #{pKeyId}
+    </update>
+    <update id="updateWbsTreeAncestors">
+        update m_wbs_tree_contract set p_id = #{contract.pId},parent_id=#{contract.parentId},ancestors_p_id = #{contract.ancestorsPId},ancestors = #{contract.ancestors} where p_key_id = #{contract.pKeyId}
+    </update>
 
     <select id="selectQueryValueLikeNodeName" resultMap="ResultMap">
         select *
@@ -980,6 +988,15 @@
           AND wtc.wbs_id = #{wbsId}
           AND wtc.is_deleted = 0;
     </select>
+    <select id="findIsExistTreeNode" resultType="java.lang.Integer">
+        SELECT count(0) FROM `m_wbs_tree_contract` a
+        left join m_wbs_tree_private b on a.is_type_private_pid = b.p_key_id
+        where a.p_key_id in
+          <foreach collection="list" item="item" open="(" close=")" separator=",">
+              #{item}
+          </foreach>
+        and (b.p_key_id is null or b.is_deleted = 1)
+    </select>
     <select id="selectListForcheckAllNodeDate" resultType="org.springblade.manager.entity.WbsTreeContract">
         select * from m_wbs_tree_contract where
        <if test="projectId!=null and projectId!=''">
@@ -1039,14 +1056,18 @@
           </foreach>
 
     </select>
-    <select id="findIsExistTreeNode" resultType="java.lang.Integer">
-        SELECT count(0) FROM `m_wbs_tree_contract` a
-        left join m_wbs_tree_private b on a.is_type_private_pid = b.p_key_id
-        where a.p_key_id in
-        <foreach collection="list" item="item" open="(" close=")" separator=",">
-            #{item}
+    <select id="getSiblingWbsContract" resultType="org.springblade.manager.entity.WbsTreeContract">
+        select * from m_wbs_tree_contract where p_id= (select p_id from m_wbs_tree_contract where p_key_id=#{pKeyId}) and is_deleted=0;
+    </select>
+    <select id="getWbsTreeContractsByPKeyIds" resultType="org.springblade.manager.entity.WbsTreeContract">
+        select p_key_id,parent_id,p_id,ancestors,ancestors_p_id from m_wbs_tree_contract where p_key_id in (
+        <foreach collection="pKeyIds" item="pkeyId" separator=",">
+            #{pkeyId}
         </foreach>
-        and (b.p_key_id is null or b.is_deleted = 1)
+        ) and is_deleted=0
+    </select>
+    <select id="getChildWbsTreeContracts" resultType="org.springblade.manager.entity.WbsTreeContract">
+        select p_key_id,ancestors,ancestors_p_id from m_wbs_tree_contract where ancestors_p_id like #{pKeyId}  and is_deleted=0
     </select>
 
 </mapper>

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

@@ -4,6 +4,7 @@ import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.springblade.business.dto.EKeyDto;
 import org.springblade.core.mp.base.BaseService;
 import org.springblade.core.tool.api.R;
+import org.springblade.manager.dto.MoveNodeDTO;
 import org.springblade.manager.dto.RangeInfo;
 import org.springblade.manager.dto.WbsTreeContractDTO;
 import org.springblade.manager.dto.WbsTreeContractDTO2;
@@ -95,9 +96,12 @@ public interface IWbsTreeContractService extends BaseService<WbsTreeContract> {
 
     boolean checkNodeAllDate(WbsTreeContract contract);
 
-    List<APIWbsContractSubdivisionVo> getWbsContractSubdivision(String contractId);
+    Integer findIsExistTreeNode(List<String> ids);
 
     List<WbsTreeContract> queryListByPIds(List<Long> pIds);
+
+    List<APIWbsContractSubdivisionVo> getWbsContractSubdivision(String contractId);
+
     ResponseEntity<Resource> exportTree(Long contractId, HttpServletResponse response) throws IOException, InvalidFormatException;
 
     R importPartitionCode(MultipartFile file);
@@ -106,5 +110,7 @@ public interface IWbsTreeContractService extends BaseService<WbsTreeContract> {
 
     R getImportProgress(Long projectId, Long contractId);
 
-    Integer findIsExistTreeNode(List<String> ids);
+    R<List<WbsTreeContract>> getSiblingWbsContract(Long pKeyId);
+
+    R moveNode(MoveNodeDTO dto);
 }

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

@@ -2,6 +2,7 @@ package org.springblade.manager.service.impl;
 
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.json.JSONUtil;
+import cn.hutool.system.SystemUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
@@ -72,6 +73,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.io.ByteArrayResource;
 import org.springframework.core.io.Resource;
 import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.http.ContentDisposition;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
@@ -95,12 +97,14 @@ import java.math.BigInteger;
 import java.math.MathContext;
 import java.math.RoundingMode;
 import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Function;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 
 @Service
@@ -127,6 +131,7 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
     private final WbsFormElementMapper wbsFormElementMapper;
     private final TrialCyAccessoriesClient trialCyAccessoriesClient;
     private final WbsTreeContractStatisticsClient wbsTreeContractStatisticsClient;
+    private final FormulaDataBlockMapper formulaDataBlockMapper;
 
 
 
@@ -3189,7 +3194,7 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
 
                     }
                 }
-                bladeRedis.setEx("import:projectId:"+wbsTreeContractRoot.getProjectId()+"contractId:"+wbsTreeContractRoot.getContractId(), "100%",5L);
+                bladeRedis.setEx("import:projectId:"+wbsTreeContractRoot.getProjectId()+"contractId:"+wbsTreeContractRoot.getContractId(), "100",7L);
             } catch (Exception e) {
                 bladeRedis.del("import:projectId:"+wbsTreeContractRoot.getProjectId()+"contractId:"+wbsTreeContractRoot.getContractId());
             }finally {
@@ -3250,6 +3255,11 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
         return true;
     }
 
+    @Override
+    public Integer findIsExistTreeNode(List<String> ids) {
+        return 0;
+    }
+
 
     /**
      * 展开所有合并单元格并将值填充到每个单元格
@@ -4480,7 +4490,7 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
         String templatePath = "/mnt/sdc/Users/hongchuangyanfa/Desktop/excel/gcdcTemplate.xlsx";
         //String templatePath = "C:\\upload\\excel\\gcdc.xlsx";
         // 查询数据
-        String sql = "select * from m_wbs_tree_contract where contract_id = " + contractId +
+        String sql = "select *,CONCAT(ancestors_p_id, ',', p_key_id) AS ancestors_p_id from m_wbs_tree_contract where contract_id = " + contractId +
                 " and is_deleted = 0 and type = 1 and node_type != 6 and p_id != 0";
         List<WbsTreeContract> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(WbsTreeContract.class));
 
@@ -4504,8 +4514,8 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                 .collect(Collectors.toMap(
                         WbsTreeContract::getPKeyId,
                         unit -> list.stream()
-                                .filter(item -> item.getAncestors() != null &&
-                                        item.getAncestors().contains(unit.getPKeyId().toString()))
+                                .filter(item -> item.getAncestorsPId() != null &&
+                                        item.getAncestorsPId().contains(unit.getPKeyId().toString()))
                                 .collect(Collectors.toList())
                 ));
 
@@ -4513,15 +4523,17 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
         for (Map.Entry<Long, List<WbsTreeContract>> entry : unitProjectMap.entrySet()) {
             Long unitId = entry.getKey();
             List<WbsTreeContract> unitProjects = entry.getValue();
-
-            // 获取单位工程名称
-            String unitName = unitProjects.stream()
-                    .filter(item -> item.getPKeyId().equals(unitId))
-                    .findFirst()
-                    .map(WbsTreeContract::getNodeName)
-                    .orElse("未知单位工程");
+            String sql1="Select * from m_wbs_tree_contract where p_key_id="+unitId;
+            WbsTreeContract unitNode=jdbcTemplate.queryForObject(sql1,new BeanPropertyRowMapper<>(WbsTreeContract.class));
+            unitProjects.add(unitNode);
+//            // 获取单位工程名称
+//            String unitName = unitProjects.stream()
+//                    .filter(item -> item.getPKeyId().equals(unitId))
+//                    .findFirst()
+//                    .map(WbsTreeContract::getNodeName)
+//                    .orElse("未知单位工程");
             // 创建安全的sheet名称
-            String safeUnitName = unitName.replaceAll("[\\\\/*\\[\\]:?]", "_");
+            String safeUnitName = unitNode.getNodeName().replaceAll("[\\\\/*\\[\\]:?]", "_");
             if (safeUnitName.length() > 31) {
                 safeUnitName = safeUnitName.substring(0, 31);
             }
@@ -4547,8 +4559,8 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
         }
 
          //保存文件到本地(本地测试放开,正式环境不需要)
-//         String outputPath = "C:\\upload\\excel\\111.xlsx";
-//        saveWorkbookToFile(workbook, outputPath);
+         //String outputPath = "C:\\upload\\excel\\111.xlsx";
+         //saveWorkbookToFile(workbook, outputPath);
 
         // 同时返回给浏览器下载
         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
@@ -4558,13 +4570,12 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
         ByteArrayResource resource = new ByteArrayResource(outputStream.toByteArray());
 
 
-        // 对中文文件名进行URL编码
-        String filename = "划分导出(请勿修改隐藏列).xlsx";
-        String encodedFilename = URLEncoder.encode(filename, "UTF-8")
-                .replaceAll("\\+", "%20"); // 替换+号为%20,确保兼容性
-
+        // 设置响应头
+        String fileName = "工程划分(请勿删除或修隐藏列).xlsx";
+        String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString())
+                .replaceAll("\\+", "%20");
         return ResponseEntity.ok()
-                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedFilename + "\"; filename*=utf-8''" + encodedFilename)
+                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=" + encodedFileName)
                 .contentType(MediaType.APPLICATION_OCTET_STREAM)
                 .contentLength(resource.contentLength())
                 .body(resource);
@@ -4595,6 +4606,7 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
         List<WbsTreeContract> wbsTreeContractList = new ArrayList<>();
         int totalCount = 0;
         int successCount = 0;
+        Map<Long, String>map=new HashMap<>();
         try (InputStream inputStream = file.getInputStream();
              XSSFWorkbook workbook = new XSSFWorkbook(inputStream)) {
 
@@ -4618,13 +4630,16 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                         if (isValidCell(pkeyCell) && isValidCell(codeCell)) {
                             String pkeyId = getCellValue(pkeyCell);
                             String partitionCode = getCellValue(codeCell);
-
+                            if(map.containsKey(Long.parseLong(pkeyId))){
+                                continue;
+                            }
                             if (StringUtils.isNotBlank(pkeyId) && StringUtils.isNotBlank(partitionCode)) {
                                 totalCount++;
                                 WbsTreeContract wbsTreeContract = new WbsTreeContract();
                                 wbsTreeContract.setPKeyId(Long.parseLong(pkeyId.trim()));
                                 wbsTreeContract.setPartitionCode(partitionCode.trim());
                                 wbsTreeContractList.add(wbsTreeContract);
+                                map.put(wbsTreeContract.getPKeyId(),wbsTreeContract.getPartitionCode());
                                 successCount++;
                             }
                         }
@@ -4649,6 +4664,7 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
         return R.status(false);
     }
 
+
     @Override
     public Boolean getIsImport(Long projectId, Long contractId) {
         Object o = bladeRedis.get("import:projectId:" + projectId + "contractId:" + contractId);
@@ -4669,9 +4685,72 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
         }
     }
 
+
+
     @Override
-    public Integer findIsExistTreeNode(List<String> ids) {
-        return baseMapper.findIsExistTreeNode(ids);
+    public R<List<WbsTreeContract>> getSiblingWbsContract(Long pKeyId) {
+        return  R.data(wbsTreeContractMapper.getSiblingWbsContract(pKeyId));
+    }
+
+    @Override
+    public R moveNode(MoveNodeDTO dto) {
+        if(dto.getLeftPkeyIds().isEmpty()){
+            throw new ServiceException("请选择需要移动的节点");
+        }
+        if(dto.getRightPkeyId()==null){
+            throw new ServiceException("请选择要移动到哪个节点");
+        }
+        List<WbsTreeContract> list= wbsTreeContractMapper.getWbsTreeContractsByPKeyIds(dto.getLeftPkeyIds());
+        WbsTreeContract moveFatherNode = this.getById(list.get(0).getPId());
+        WbsTreeContract fatherContract = this.getById(dto.getRightPkeyId());
+
+        String sql="SELECT * from m_formula_data_block WHERE sw_id = "+moveFatherNode.getId()+" and contract_id ="+moveFatherNode.getContractId()+" and  type =0";
+        List<FormulaDataBlock> formulaDataBlocks1 = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(FormulaDataBlock.class));
+
+        String sql1="SELECT * from m_formula_data_block WHERE sw_id = "+fatherContract.getId()+" and contract_id ="+fatherContract.getContractId()+" and  type =0";
+        List<FormulaDataBlock> formulaDataBlocks2 = jdbcTemplate.query(sql1, new BeanPropertyRowMapper<>(FormulaDataBlock.class));
+        List<ElementBlock> elementBlocks1=new ArrayList<>();
+        List<ElementBlock> elementBlocks2=new ArrayList<>();
+        if(formulaDataBlocks2.size()>0){
+            if(formulaDataBlocks1.size()>0){
+                elementBlocks1= JSON.parseArray(formulaDataBlocks1.get(0).getVal(), ElementBlock.class);
+                elementBlocks2= JSON.parseArray(formulaDataBlocks2.get(0).getVal(), ElementBlock.class);
+                elementBlocks2.addAll(elementBlocks1);
+                formulaDataBlocks2.get(0).setVal(JSON.toJSONString(elementBlocks2));
+                formulaDataBlockMapper.updateById(formulaDataBlocks2.get(0));
+            }
+        }else {
+            if(formulaDataBlocks1.size()>0){
+                elementBlocks1= JSON.parseArray(formulaDataBlocks1.get(0).getVal(), ElementBlock.class);
+                FormulaDataBlock insert = new FormulaDataBlock();
+                insert.setContractId(Long.parseLong(fatherContract.getContractId()));
+                insert.setType(0);
+                insert.setSwId(fatherContract.getId());
+                insert.setVal(JSON.toJSONString(elementBlocks1));
+                formulaDataBlockMapper.insert(insert);
+            }
+        }
+        for (WbsTreeContract contract : list) {
+            String oldancestorsPId = contract.getAncestorsPId();
+            String oldancestors = contract.getAncestors();
+            contract.setPId(fatherContract.getPKeyId());
+            contract.setParentId(fatherContract.getId());
+            contract.setAncestorsPId(fatherContract.getAncestorsPId()+","+contract.getPId());
+            contract.setAncestors(fatherContract.getAncestors());
+            //查出当前节点所有子节点。
+            List<WbsTreeContract> childContracts = wbsTreeContractMapper.getChildWbsTreeContracts(contract.getPKeyId());
+            if(!childContracts.isEmpty()){
+                for (WbsTreeContract childContract : childContracts) {
+                    String ancestorsPId =  childContract.getAncestorsPId();
+                    ancestorsPId=ancestorsPId.replace(oldancestorsPId,contract.getAncestorsPId());
+                    String ancestors = childContract.getAncestors();
+                    ancestors=ancestors.replace(oldancestors,contract.getAncestors());
+                    wbsTreeContractMapper.updateAncestorsPid(ancestorsPId,ancestors,childContract.getPKeyId());
+                }
+            }
+            this.wbsTreeContractMapper.updateWbsTreeAncestors(contract);
+        }
+        return R.success("操作成功");
     }
 
     /**
@@ -4795,13 +4874,14 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
             Row row = sheet.createRow(rowNum);
 
             // 解析祖级节点
-            String[] ancestors = leafNode.getAncestors().split(",");
+            String[] ancestors = leafNode.getAncestorsPId().split(",");
 
             // 转换为 List<Long>
             List<Long> ancestorIds = Arrays.stream(ancestors)
                     .map(Long::parseLong)
                     .collect(Collectors.toList());
 
+            ancestorIds.add(leafNode.getPKeyId());
             // 根据叶子节点类型填充各级工程数据
             fillEngineeringDataByLeafType(row, unitProjects, ancestorIds, mergeMap, rowNum, centerStyle, leafNode.getNodeType());
 
@@ -4816,6 +4896,7 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
     private List<WbsTreeContract> findLeafNodesByPriority(List<WbsTreeContract> projects) {
         // 按照节点类型优先级:子分项(5) -> 分项(4) -> 子分部(3) -> 分部(2) -> 单位工程(18)
         List<WbsTreeContract> leafNodes = new ArrayList<>();
+        Set<Long> ancestorIds= new HashSet<>();
 
         // 1. 先找子分项工程 (节点类型5)
         leafNodes = projects.stream()
@@ -4823,39 +4904,90 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                 .collect(Collectors.toList());
 
         if (!leafNodes.isEmpty()) {
-            return leafNodes;
+            sortLeafNodes(leafNodes);
         }
+        ancestorIds= leafNodes.stream()
+                .map(WbsTreeContract::getAncestorsPId)
+                .filter(Objects::nonNull)
+                .flatMap(ancestors -> Arrays.stream(ancestors.split(",")))
+                .map(String::trim)
+                .filter(id -> !id.isEmpty())
+                .map(Long::parseLong)
+                .collect(Collectors.toSet());
 
         // 2. 如果没有子分项,找分项工程 (节点类型4)
-        leafNodes = projects.stream()
-                .filter(item -> item.getNodeType() == 4)
+        Set<Long> finalAncestorIds = ancestorIds;
+        List<WbsTreeContract> items=projects.stream()
+                .filter(item -> item.getNodeType() == 4 && !finalAncestorIds.contains(item.getPKeyId()))
                 .collect(Collectors.toList());
-
-        if (!leafNodes.isEmpty()) {
-            return leafNodes;
-        }
+        if(!items.isEmpty()&&items.size()>0){
+            leafNodes.addAll(items);
+        }
+        ancestorIds = leafNodes.stream()
+                .map(WbsTreeContract::getAncestorsPId)
+                .filter(Objects::nonNull)
+                .flatMap(ancestors -> Arrays.stream(ancestors.split(",")))
+                .map(String::trim)
+                .filter(id -> !id.isEmpty())
+                .map(Long::parseLong)
+                .collect(Collectors.toSet());
 
         // 3. 如果没有分项,找子分部工程 (节点类型3)
-        leafNodes = projects.stream()
-                .filter(item -> item.getNodeType() == 3)
+        Set<Long> finalAncestorIds1 = ancestorIds;
+        List<WbsTreeContract> subDivisional = projects.stream()
+                .filter(item -> item.getNodeType() == 3&& !finalAncestorIds1.contains(item.getPKeyId()))
                 .collect(Collectors.toList());
-
-        if (!leafNodes.isEmpty()) {
-            return leafNodes;
-        }
-
+        if(!subDivisional.isEmpty()&&subDivisional.size()>0){
+            leafNodes.addAll(subDivisional);
+        }
+        ancestorIds = leafNodes.stream()
+                .map(WbsTreeContract::getAncestorsPId)
+                .filter(Objects::nonNull)
+                .flatMap(ancestors -> Arrays.stream(ancestors.split(",")))
+                .map(String::trim)
+                .filter(id -> !id.isEmpty())
+                .map(Long::parseLong)
+                .collect(Collectors.toSet());
+        Set<Long> finalAncestorIds2 = ancestorIds;
         // 4. 如果没有子分部,找分部工程 (节点类型2)
-        leafNodes = projects.stream()
-                .filter(item -> item.getNodeType() == 2)
+        List<WbsTreeContract> divisional = projects.stream()
+                .filter(item -> item.getNodeType() == 2&& !finalAncestorIds2.contains(item.getPKeyId()))
                 .collect(Collectors.toList());
+        if(!divisional.isEmpty()&&divisional.size()>0){
+            leafNodes.addAll(divisional);
+        }
+        ancestorIds = leafNodes.stream()
+                .map(WbsTreeContract::getAncestorsPId)
+                .filter(Objects::nonNull)
+                .flatMap(ancestors -> Arrays.stream(ancestors.split(",")))
+                .map(String::trim)
+                .filter(id -> !id.isEmpty())
+                .map(Long::parseLong)
+                .collect(Collectors.toSet());
+        Set<Long> finalAncestorIds3 = ancestorIds;
 
-        if (!leafNodes.isEmpty()) {
-            return leafNodes;
+        // 5. 最后找单位工程 (节点类型18)
+        List<WbsTreeContract> unit = projects.stream()
+                .filter(item -> item.getNodeType() == 18&&!finalAncestorIds3.contains(item.getPKeyId()))
+                .collect(Collectors.toList());
+        if(!unit.isEmpty()&&unit.size()>0){
+            leafNodes.addAll(unit);
         }
+        return sortLeafNodes(leafNodes);
+    }
 
-        // 5. 最后找单位工程 (节点类型18)
-        return projects.stream()
-                .filter(item -> item.getNodeType() == 18)
+    // 排序方法:先按pId排序,pId相同则按sort排序(null值排在最后)
+    private List<WbsTreeContract> sortLeafNodes(List<WbsTreeContract> nodes) {
+        return nodes.stream()
+                .sorted(Comparator
+                        .comparing(WbsTreeContract::getPId)
+                        .thenComparing(
+                                Comparator.comparing(
+                                        WbsTreeContract::getSort,
+                                        Comparator.nullsLast(Comparator.naturalOrder())
+                                )
+                        )
+                )
                 .collect(Collectors.toList());
     }
 
@@ -5005,8 +5137,11 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
         mergeMap.get(col).add(new CellRangeAddress(rowNum, rowNum, col, col));
     }
 
+
+
     // 应用合并单元格 - 添加居中样式参数
     private void applyMergedRegions(Sheet sheet, Map<Integer, List<CellRangeAddress>> mergeMap, CellStyle centerStyle) {
+
         // 使用Set来记录已经合并的区域,避免重复合并
         Set<String> mergedRegions = new HashSet<>();
 
@@ -5112,7 +5247,7 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                     } else {
                         // 值不同,合并之前的区域
                         if (mergeStart < mergeEnd) {
-                            mergeSingleColumnIfNotExists(sheet, col, mergeStart, mergeEnd, centerStyle, mergedRegions);
+                            mergeSingleColumnIfNotExists(sheet, col, mergeStart, mergeEnd, centerStyle, mergedRegions,false);
                         }
                         // 开始新的合并区域
                         mergeStart = rowNum;
@@ -5123,48 +5258,77 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
 
                 // 合并最后一段区域
                 if (mergeStart < mergeEnd) {
-                    mergeSingleColumnIfNotExists(sheet, col, mergeStart, mergeEnd, centerStyle, mergedRegions);
+                    mergeSingleColumnIfNotExists(sheet, col, mergeStart, mergeEnd, centerStyle, mergedRegions,false);
                 }
             }
         }
     }
 
-    // 合并名称列和对应的划分编码列(检查是否已存在)
+    // 在合并名称列和对应编码列时,需要清空被合并单元格的值,只保留第一个单元格的值
     private void mergeNameAndCodeColumns(Sheet sheet, int nameCol, int startRow, int endRow, CellStyle centerStyle, Set<String> mergedRegions) {
         // 合并名称列
-        mergeSingleColumnIfNotExists(sheet, nameCol, startRow, endRow, centerStyle, mergedRegions);
+        mergeSingleColumnIfNotExists(sheet, nameCol, startRow, endRow, centerStyle, mergedRegions, true);
 
         // 合并对应的划分编码列
         int codeCol = getCorrespondingCodeColumn(nameCol);
         if (codeCol != -1) {
-            mergeSingleColumnIfNotExists(sheet, codeCol, startRow, endRow, centerStyle, mergedRegions);
+            mergeSingleColumnIfNotExists(sheet, codeCol, startRow, endRow, centerStyle, mergedRegions, true);
         }
     }
 
-    // 合并单列并设置样式(检查是否已存在)
-    private void mergeSingleColumnIfNotExists(Sheet sheet, int col, int startRow, int endRow, CellStyle style, Set<String> mergedRegions) {
-        String regionKey = col + ":" + startRow + ":" + endRow;
-
-        if (!mergedRegions.contains(regionKey)) {
-            CellRangeAddress mergedRegion = new CellRangeAddress(startRow, endRow, col, col);
-
-            // 检查是否已经存在相同的合并区域
-            boolean alreadyExists = false;
-            for (int i = 0; i < sheet.getNumMergedRegions(); i++) {
-                CellRangeAddress existingRegion = sheet.getMergedRegion(i);
-                if (existingRegion.getFirstColumn() == col &&
-                        existingRegion.getFirstRow() == startRow &&
-                        existingRegion.getLastRow() == endRow) {
-                    alreadyExists = true;
-                    break;
+    // 合并单列并设置样式(添加clearValues参数来控制是否清空被合并单元格的值)
+    private void mergeSingleColumnIfNotExists(Sheet sheet, int col, int startRow, int endRow, CellStyle style,
+                                              Set<String> mergedRegions, boolean clearValues) {
+        try {
+            String regionKey = col + ":" + startRow + ":" + endRow;
+
+            if (!mergedRegions.contains(regionKey)) {
+                CellRangeAddress mergedRegion = new CellRangeAddress(startRow, endRow, col, col);
+
+                // 检查是否已经存在相同的合并区域
+                boolean alreadyExists = false;
+                for (int i = 0; i < sheet.getNumMergedRegions(); i++) {
+                    CellRangeAddress existingRegion = sheet.getMergedRegion(i);
+                    if (existingRegion.getFirstColumn() == col &&
+                            existingRegion.getFirstRow() == startRow &&
+                            existingRegion.getLastRow() == endRow) {
+                        alreadyExists = true;
+                        break;
+                    }
                 }
-            }
 
-            if (!alreadyExists) {
-                sheet.addMergedRegion(mergedRegion);
-                setMergedRegionStyle(sheet, mergedRegion, style);
-                mergedRegions.add(regionKey);
+                if (!alreadyExists) {
+                    // 如果需要清空值,保留第一个单元格的值,清空其他单元格的值
+                    if (clearValues && startRow < endRow) {
+                        // 获取第一个单元格的值
+                        Row firstRow = sheet.getRow(startRow);
+                        Cell firstCell = firstRow != null ? firstRow.getCell(col) : null;
+                        String firstValue = firstCell != null ? getCellStringValue(firstCell) : "";
+
+                        // 清空被合并区域中其他单元格的值
+                        for (int rowNum = startRow + 1; rowNum <= endRow; rowNum++) {
+                            Row row = sheet.getRow(rowNum);
+                            if (row != null) {
+                                Cell cell = row.getCell(col);
+                                if (cell != null) {
+                                    cell.setCellValue(""); // 清空值
+                                }
+                            }
+                        }
+
+                        // 确保第一个单元格有正确的值(防止被意外清空)
+                        if (firstCell != null) {
+                            firstCell.setCellValue(firstValue);
+                        }
+                    }
+
+                    sheet.addMergedRegion(mergedRegion);
+                    setMergedRegionStyle(sheet, mergedRegion, style);
+                    mergedRegions.add(regionKey);
+                }
             }
+        } catch (Exception e) {
+            e.printStackTrace();
         }
     }