Browse Source

Merge remote-tracking branch 'origin/master' into master

yangyj 11 months ago
parent
commit
9301bffbd1
21 changed files with 769 additions and 32 deletions
  1. 4 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/feign/WbsTreeContractClient.java
  2. 40 0
      blade-service-api/blade-meter-api/src/main/java/org/springblade/meter/vo/InventoryFormMeterVO2.java
  3. 69 0
      blade-service-api/blade-meter-api/src/main/java/org/springblade/meter/vo/MeterImport3VO.java
  4. 45 0
      blade-service-api/blade-meter-api/src/main/java/org/springblade/meter/vo/MeterImport3VO2.java
  5. 3 0
      blade-service-api/blade-meter-api/src/main/java/org/springblade/meter/vo/MeterTreeContractVO.java
  6. 113 10
      blade-service/blade-business/src/main/java/org/springblade/business/controller/ConstructionLedgerController.java
  7. 1 1
      blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java
  8. 2 1
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/ContractLogWbsMapper.java
  9. 8 5
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/ContractLogWbsMapper.xml
  10. 4 1
      blade-service/blade-business/src/main/java/org/springblade/business/service/IContractLogWbsService.java
  11. 5 2
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/ContractLogWbsServiceImpl.java
  12. 12 3
      blade-service/blade-manager/src/main/java/org/springblade/manager/feign/WbsTreeContractClientImpl.java
  13. 30 4
      blade-service/blade-meter/src/main/java/org/springblade/meter/controller/MeterTreeController.java
  14. 11 4
      blade-service/blade-meter/src/main/java/org/springblade/meter/mapper/MeterTreeContractMapper.java
  15. 22 1
      blade-service/blade-meter/src/main/java/org/springblade/meter/mapper/MeterTreeContractMapper.xml
  16. 6 0
      blade-service/blade-meter/src/main/java/org/springblade/meter/service/MeterTreeContractService.java
  17. 1 0
      blade-service/blade-meter/src/main/java/org/springblade/meter/service/MeterTreeProjectService.java
  18. 1 0
      blade-service/blade-meter/src/main/java/org/springblade/meter/service/MeterTreeSystemService.java
  19. 364 0
      blade-service/blade-meter/src/main/java/org/springblade/meter/service/impl/MeterTreeContractServiceImpl.java
  20. 13 0
      blade-service/blade-meter/src/main/java/org/springblade/meter/service/impl/MeterTreeProjectServiceImpl.java
  21. 15 0
      blade-service/blade-meter/src/main/java/org/springblade/meter/service/impl/MeterTreeSystemServiceImpl.java

+ 4 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/feign/WbsTreeContractClient.java

@@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestParam;
 
 import java.util.List;
+import java.util.Set;
 
 import static org.springblade.core.launch.constant.AppConstant.APPLICATION_NAME_PREFIX;
 
@@ -76,6 +77,9 @@ public interface WbsTreeContractClient {
     @GetMapping(API_PREFIX + "/getContractNodeByPrimaryKeyId")
     WbsTreeContract getContractNodeByPrimaryKeyId(@RequestParam String primaryKeyId);
 
+    @PostMapping(API_PREFIX + "/getContractNodeByPrimaryKeyIds")
+    List<WbsTreeContract> getContractNodeByPrimaryKeyIds(@RequestBody List<String> supplementPKeyIds);
+
     @PostMapping(API_PREFIX + "/removeContractTreeNode")
     Boolean removeContractTreeNode(@RequestBody List<String> ids);
 

+ 40 - 0
blade-service-api/blade-meter-api/src/main/java/org/springblade/meter/vo/InventoryFormMeterVO2.java

@@ -0,0 +1,40 @@
+/*
+ *      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.meter.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.meter.entity.InventoryFormMeter;
+
+import java.math.BigDecimal;
+
+/**
+ * 合同计量单元导入模板3专用,中间表携带是否被计量标识
+ *
+ * @author BladeX
+ * @since 2023-11-29
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class InventoryFormMeterVO2 extends InventoryFormMeter {
+	private static final long serialVersionUID = 1L;
+
+	@ApiModelProperty(value = "是否被计量0是1否")
+	private Integer isMeter;
+
+}

+ 69 - 0
blade-service-api/blade-meter-api/src/main/java/org/springblade/meter/vo/MeterImport3VO.java

@@ -0,0 +1,69 @@
+package org.springblade.meter.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springblade.core.tool.node.INode;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @Param   合同计量单元导入模板3专用,携带标识当前是新增节点还是原生节点
+ * @Author wangwl
+ * @Date 2023/12/26 15:38
+ **/
+@Data
+public class MeterImport3VO implements INode<MeterImport3VO> {
+    /**
+     * 主键ID
+     */
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long id;
+
+    /**
+     * 父节点ID
+     */
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long parentId;
+
+    /**
+     * 子孙节点
+     */
+    @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    private List<MeterImport3VO> children;
+
+    /**
+     * 是否有子孙节点
+     */
+    @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    private Boolean hasChildren;
+
+    @Override
+    public List<MeterImport3VO> getChildren() {
+        if (this.children == null) {
+            this.children = new ArrayList<>();
+        }
+        return this.children;
+    }
+
+    @ApiModelProperty(value = "0原生1新增")
+    private Integer isNew;
+
+    private String nodeName;
+
+    private Integer nodeType;
+    private String remarks;
+    private String contractPicture;
+
+    @ApiModelProperty(value = "项目id")
+    private Long projectId;
+
+    @ApiModelProperty(value = "合同段id")
+    private Long contractId;
+
+    @ApiModelProperty(value = "祖级id")
+    private String ancestor;
+}

+ 45 - 0
blade-service-api/blade-meter-api/src/main/java/org/springblade/meter/vo/MeterImport3VO2.java

@@ -0,0 +1,45 @@
+package org.springblade.meter.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springblade.core.tool.node.INode;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @Param   合同计量单元导入模板3专用,通过计量id和清单id确定是否存在数据
+ * @Author wangwl
+ * @Date 2023/12/26 15:38
+ **/
+@Data
+public class MeterImport3VO2  {
+
+    private Long meterId;
+    private Long formId;
+
+    public MeterImport3VO2() {
+    }
+
+    public MeterImport3VO2(Long meterId, Long formId) {
+        this.meterId = meterId;
+        this.formId = formId;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        MeterImport3VO2 that = (MeterImport3VO2) o;
+        return Objects.equals(meterId, that.meterId) && Objects.equals(formId, that.formId);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(meterId, formId);
+    }
+}

+ 3 - 0
blade-service-api/blade-meter-api/src/main/java/org/springblade/meter/vo/MeterTreeContractVO.java

@@ -24,4 +24,7 @@ public class MeterTreeContractVO extends MeterTreeContract {
     @ApiModelProperty(value = "是否已经计量:0否1是")
     private Integer isMeter;
 
+    @ApiModelProperty(value = "是否已经计量:0否1是")
+    private String nodeTypeName;
+
 }

+ 113 - 10
blade-service/blade-business/src/main/java/org/springblade/business/controller/ConstructionLedgerController.java

@@ -2,28 +2,36 @@ package org.springblade.business.controller;
 
 import cn.hutool.core.date.DateUtil;
 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.validation.Valid;
 
+import lombok.Data;
 import org.apache.commons.lang.StringUtils;
 import org.springblade.business.entity.ContractLog;
 import org.springblade.business.service.IContractLogWbsService;
 import org.springblade.business.service.IInformationQueryService;
 import org.springblade.business.vo.QueryProcessDataVO;
+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.secure.utils.AuthUtil;
 import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.BeanUtil;
 import org.springblade.core.tool.utils.Func;
 import org.springblade.core.tool.utils.ObjectUtil;
 import org.springblade.manager.entity.WbsTreeContract;
 import org.springblade.manager.feign.ContractClient;
 import org.springblade.manager.feign.WbsTreeContractClient;
 import org.springblade.manager.vo.WbsTreeContractTreeVOS;
+import org.springblade.manager.vo.WbsTreeContractVO8;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.RequestParam;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -33,10 +41,11 @@ import org.springblade.business.wrapper.ConstructionLedgerWrapper;
 import org.springblade.business.service.IConstructionLedgerService;
 import org.springblade.core.boot.ctrl.BladeController;
 
+import java.io.Serializable;
+import java.text.SimpleDateFormat;
 import java.time.Duration;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 /**
@@ -61,6 +70,8 @@ public class ConstructionLedgerController extends BladeController {
 
     private final IContractLogWbsService contractLogWbsService;
 
+    private final InformationWriteQueryController informationWriteQueryController;
+
     /**
      * 获取当前合同段的划分树
      *
@@ -103,9 +114,9 @@ public class ConstructionLedgerController extends BladeController {
     @PostMapping("/list")
     @ApiOperationSupport(order = 2)
     @ApiOperation(value = "分页(建议)", notes = "传入constructionLedger")
-    public R<IPage<ConstructionLedgerVO>> list(@Valid @RequestBody ConstructionLedgerVO vo) {
-//		ConstructionLedger ledger = new ConstructionLedger();
-//		BeanUtils.copyProperties(vo, ledger);
+    public R<IPage<ConstructionLedgerVO>> list(@Valid @RequestBody ConstructionLedgerVO vo) throws NoSuchFieldException, IllegalAccessException {
+        //ConstructionLedger ledger = new ConstructionLedger();
+        //BeanUtils.copyProperties(vo, ledger);
 
         Query query = new Query();
         query.setCurrent(vo.getCurrent());
@@ -119,8 +130,17 @@ public class ConstructionLedgerController extends BladeController {
             node = this.wbsTreeContractClient.getContractWbsTreeByContractIdAndId(Long.parseLong(vo.getWbsIds().get(0)), vo.getContractId());
         }
 
-        List<QueryProcessDataVO> queryDataResult;
-        if (!new Integer("6").equals(node.getNodeType()) && ObjectUtil.isNotEmpty(node.getMajorDataType())  && !Arrays.asList("1,2,3,4".split(",")).contains(node.getMajorDataType().toString())) {
+        if (node.getParentId().equals(0L)) {
+            throw new ServiceException("请从第三层级节点开始进行检索");
+        } else if (node.getAncestors().split(",").length == 2) {
+            WbsTreeContract root = wbsTreeContractClient.getContractWbsTreeByContractIdAndId(node.getParentId(), Long.parseLong(node.getContractId()));
+            if (root.getParentId().equals(0L)) {
+                throw new ServiceException("请从第三层级节点开始进行检索");
+            }
+        }
+
+        /*List<QueryProcessDataVO> queryDataResult;
+        if (!new Integer("6").equals(node.getNodeType()) && ObjectUtil.isNotEmpty(node.getMajorDataType()) && !Arrays.asList("1,2,3,4".split(",")).contains(node.getMajorDataType().toString())) {
             //非填报节点
             queryDataResult = this.informationQueryService.queryProcessDataByParentIdAndContractId(node.getId().toString(), 1, vo.getContractId().toString());
         } else {
@@ -128,6 +148,20 @@ public class ConstructionLedgerController extends BladeController {
             queryDataResult = this.informationQueryService.queryProcessDataByPrimaryKeyIdAndClassify(node.getPKeyId().toString(), 1);
         }
         vo.setWbsIds(queryDataResult.stream().map(QueryProcessDataVO::getPrimaryKeyId).distinct().collect(Collectors.toList()));
+        */
+
+        List<WbsTreeContractVO8> lowestNodes = new ArrayList<>();
+        WbsTreeContractVO8 vo8 = BeanUtil.copyProperties(node, WbsTreeContractVO8.class);
+        informationWriteQueryController.lowestNodesRecursively(lowestNodes, Collections.singleton(vo8), node.getContractId());
+
+        if (lowestNodes.size() <= 0) {
+            if (!node.getNodeType().equals(6)) {
+                return R.data(null);
+            }
+            vo.setWbsIds(Collections.singletonList(String.valueOf(node.getPKeyId())));
+        } else {
+            vo.setWbsIds(lowestNodes.stream().distinct().map(WbsTreeContractVO8::getPKeyId).map(String::valueOf).collect(Collectors.toList()));
+        }
 
         if (vo.getSiteStartTime() != null && vo.getSiteEndTime() != null) {
             pages = this.constructionLedgerService.page(Condition.getPage(query), Condition.getQueryWrapper(new ConstructionLedger()).lambda().in(ConstructionLedger::getWbsId, vo.getWbsIds()).between(ConstructionLedger::getSiteStartTime, vo.getSiteStartTime(), vo.getSiteEndTime()));
@@ -136,10 +170,30 @@ public class ConstructionLedgerController extends BladeController {
         }
 
         IPage<ConstructionLedgerVO> voiPage = ConstructionLedgerWrapper.build().pageVO(pages);
+        List<ConstructionLedgerVO> records = voiPage.getRecords();
+        if (records.size() <= 0) {
+            return R.data(null);
+        }
+
+        Set<String> collect = voiPage.getRecords().stream().map(ConstructionLedgerVO::getWbsId).map(String::valueOf).collect(Collectors.toSet());
+        List<String> wbsIds = vo.getWbsIds();
+        List<String> supplementPKeyIds = wbsIds.stream().filter(f -> !collect.contains(f)).distinct().collect(Collectors.toList());
+        if (supplementPKeyIds.size() > 0) {
+            supplementConstructionLedger(supplementPKeyIds, node);
+        }
 
+        //找到最开始的施工日志,如果存在数据则使用最开始的时间,如果没有再使用自定义编辑的时间
+        List<Long> param = voiPage.getRecords().stream().map(ConstructionLedgerVO::getWbsId).distinct().collect(Collectors.toList());
+
+        List<ContractLog> contractLogs = this.contractLogWbsService.queryContractLogNewOrOldDataBySelectPrimaryKeyIdAndClassify(new ListDTO(param, 7, "OLD"));
+        Map<Long, ContractLog> maps = contractLogs.stream().collect(Collectors.toMap(ContractLog::getId, Function.identity()));
         voiPage.getRecords().forEach(vos -> {
+
+            vos.setStation(vos.getSite()); //TODO 暂时这样处理
+
             //找到最开始的施工日志,如果存在数据则使用最开始的时间,如果没有再使用自定义编辑的时间
-            ContractLog contractLog = this.contractLogWbsService.queryContractLogNewOrOldDataBySelectPrimaryKeyIdAndClassify(vos.getWbsId().toString(), 7, "OLD");
+            //ContractLog contractLog = this.contractLogWbsService.queryContractLogNewOrOldDataBySelectPrimaryKeyIdAndClassify(vos.getWbsId().toString(), 7, "OLD");
+            ContractLog contractLog = maps.getOrDefault(vos.getWbsId(), null);
             if (contractLog != null) {
                 //获取最开始的填报时间
                 String recordTime = contractLog.getRecordTime();
@@ -162,7 +216,6 @@ public class ConstructionLedgerController extends BladeController {
                 vos.setSiteTimeStr(DateUtil.format(vos.getSiteStartTime(), "yyyy-MM-dd"));
             }
 
-
             vos.setDetectionTimeStr(DateUtil.format(vos.getSiteEndTime(), "yyyy-MM-dd"));
             vos.setDetectionStartTimeValue(DateUtil.format(vos.getDetectionStartTime(), "yyyy-MM-dd"));
             vos.setDetectionEndTimeValue(DateUtil.format(vos.getDetectionEndTime(), "yyyy-MM-dd"));
@@ -180,6 +233,56 @@ public class ConstructionLedgerController extends BladeController {
         return R.data(voiPage);
     }
 
+    @Data
+    public class ListDTO implements Serializable {
+        List<Long> pKeyIds;
+        Integer classify;
+        String newOrOld;
+
+        public ListDTO(List<Long> pKeyIds, Integer classify, String newOrOld) {
+            this.pKeyIds = pKeyIds;
+            this.classify = classify;
+            this.newOrOld = newOrOld;
+        }
+    }
+
+    /**
+     * 增补台账
+     */
+    @Async
+    public void supplementConstructionLedger(List<String> supplementPKeyIds, WbsTreeContract node) {
+        List<ConstructionLedger> alreadyExistConstructionLedgers = constructionLedgerService.getBaseMapper().selectList(Wrappers.<ConstructionLedger>lambdaQuery().select(ConstructionLedger::getWbsId).in(ConstructionLedger::getWbsId, supplementPKeyIds));
+        if (!alreadyExistConstructionLedgers.isEmpty()) {
+            Set<String> wbsIds = alreadyExistConstructionLedgers.stream().map(ConstructionLedger::getWbsId).map(String::valueOf).collect(Collectors.toSet());
+            supplementPKeyIds.removeIf(wbsIds::contains);
+        }
+
+        if (supplementPKeyIds.size() > 0) {
+            List<WbsTreeContract> contractNodeByPrimaryKeyIds = wbsTreeContractClient.getContractNodeByPrimaryKeyIds(supplementPKeyIds); //只获取工序节点
+            if (contractNodeByPrimaryKeyIds.size() > 0) {
+                List<ConstructionLedger> constructionLedgers = new ArrayList<>();
+                for (WbsTreeContract wbsTreeContract : contractNodeByPrimaryKeyIds) {
+                    ConstructionLedger ledger = new ConstructionLedger();
+                    ledger.setId(SnowFlakeUtil.getId());
+                    ledger.setStation(ObjectUtil.isNotEmpty(wbsTreeContract.getFullName()) ? wbsTreeContract.getFullName() : wbsTreeContract.getNodeName());
+                    ledger.setSite(ObjectUtil.isNotEmpty(wbsTreeContract.getFullName()) ? wbsTreeContract.getFullName() : wbsTreeContract.getNodeName());
+
+                    ledger.setIsBeton(wbsTreeContract.getIsConcrete());
+                    ledger.setWbsId(wbsTreeContract.getPKeyId());
+
+                    ledger.setContractId(Long.parseLong(node.getContractId()));
+                    ledger.setProjectId(Long.parseLong(node.getProjectId()));
+                    ledger.setCreateTime(new Date());
+                    ledger.setCreateUser(AuthUtil.getUserId());
+                    ledger.setIsDeleted(0);
+
+                    constructionLedgers.add(ledger);
+                }
+                constructionLedgerService.saveBatch(constructionLedgers, 1000);
+            }
+        }
+    }
+
     /**
      * 新增
      */

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

@@ -3591,7 +3591,7 @@ public class InformationWriteQueryController extends BladeController {
      * @param lowestNodes 结果集
      * @param nodes       初始入参节点
      */
-    private void lowestNodesRecursively(List<WbsTreeContractVO8> lowestNodes, Set<WbsTreeContractVO8> nodes, String contractId) {
+    public void lowestNodesRecursively(List<WbsTreeContractVO8> lowestNodes, Set<WbsTreeContractVO8> nodes, String contractId) {
         if (nodes.size() > 0) {
             Set<Long> ids = nodes.stream().map(WbsTreeContractVO8::getId).collect(Collectors.toSet());
             if (ids.size() > 0) {

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

@@ -24,6 +24,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * Mapper 接口
@@ -33,7 +34,7 @@ import java.util.List;
  */
 public interface ContractLogWbsMapper extends BaseMapper<ContractLogWbs> {
 
-    ContractLog queryContractLogNewOrOldDataBySelectPrimaryKeyIdAndClassify(@Param("selectPrimaryKeyId") String selectPrimaryKeyId, @Param("classify") Integer classify, @Param("newOrOld") String newOrOld);
+    List<ContractLog> queryContractLogNewOrOldDataBySelectPrimaryKeyIdAndClassify(@Param("param") List<Long> param, @Param("classify") Integer classify, @Param("newOrOld") String newOrOld);
 
     Integer countContractLogBySelectPrimaryKeyIdsAndClassify(@Param("primaryKeyIds") List<String> primaryKeyIds, @Param("classify") Integer classify);
 

+ 8 - 5
blade-service/blade-business/src/main/java/org/springblade/business/mapper/ContractLogWbsMapper.xml

@@ -42,13 +42,16 @@
 
     <select id="queryContractLogNewOrOldDataBySelectPrimaryKeyIdAndClassify" resultMap="contractLogResultMap">
         select
-        *
+            id,record_time
         from
-        u_contract_log
+            u_contract_log
         where
-        id in(
-        select contract_log_id from u_contract_log_wbs where is_deleted = 0 and tree_primary_key_id =
-        #{selectPrimaryKeyId}
+        id in (
+            select contract_log_id from u_contract_log_wbs
+            where is_deleted = 0 and tree_primary_key_id in
+            <foreach collection="param" item="id" open="(" separator="," close=")">
+                #{id}
+            </foreach>
         )
         and wbs_node_type = #{classify} and is_deleted = 0
         <choose>

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

@@ -16,12 +16,15 @@
  */
 package org.springblade.business.service;
 
+import org.springblade.business.controller.ConstructionLedgerController;
 import org.springblade.business.entity.ContractLog;
 import org.springblade.business.entity.ContractLogWbs;
 import org.springblade.business.vo.ContractLogVO;
 import org.springblade.core.mp.base.BaseService;
+import org.springframework.web.bind.annotation.RequestBody;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * 服务类
@@ -31,7 +34,7 @@ import java.util.List;
  */
 public interface IContractLogWbsService extends BaseService<ContractLogWbs> {
 
-    ContractLog queryContractLogNewOrOldDataBySelectPrimaryKeyIdAndClassify(String selectPrimaryKeyId, Integer classify, String newOrOld);
+    List<ContractLog> queryContractLogNewOrOldDataBySelectPrimaryKeyIdAndClassify(ConstructionLedgerController.ListDTO dto) throws NoSuchFieldException, IllegalAccessException;
 
     Integer countContractLogBySelectPrimaryKeyIdsAndClassify(List<String> selectPrimaryKeyIds, Integer classify);
 

+ 5 - 2
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/ContractLogWbsServiceImpl.java

@@ -19,6 +19,7 @@ package org.springblade.business.service.impl;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import org.springblade.business.controller.ConstructionLedgerController;
 import org.springblade.business.entity.ContractLog;
 import org.springblade.business.entity.ContractLogWbs;
 import org.springblade.business.vo.ContractLogVO;
@@ -27,8 +28,10 @@ import org.springblade.business.service.IContractLogWbsService;
 import org.springblade.core.mp.base.BaseServiceImpl;
 import org.springframework.stereotype.Service;
 
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
@@ -41,8 +44,8 @@ import java.util.stream.Collectors;
 public class ContractLogWbsServiceImpl extends BaseServiceImpl<ContractLogWbsMapper, ContractLogWbs> implements IContractLogWbsService {
 
     @Override
-    public ContractLog queryContractLogNewOrOldDataBySelectPrimaryKeyIdAndClassify(String selectPrimaryKeyId, Integer classify, String newOrOld) {
-        return this.baseMapper.queryContractLogNewOrOldDataBySelectPrimaryKeyIdAndClassify(selectPrimaryKeyId, classify, newOrOld);
+    public List<ContractLog> queryContractLogNewOrOldDataBySelectPrimaryKeyIdAndClassify(ConstructionLedgerController.ListDTO obj){
+        return this.baseMapper.queryContractLogNewOrOldDataBySelectPrimaryKeyIdAndClassify(obj.getPKeyIds(), obj.getClassify(), obj.getNewOrOld());
     }
 
     @Override

+ 12 - 3
blade-service/blade-manager/src/main/java/org/springblade/manager/feign/WbsTreeContractClientImpl.java

@@ -156,6 +156,14 @@ public class WbsTreeContractClientImpl implements WbsTreeContractClient {
         return this.wbsTreeContractService.getOne(Wrappers.<WbsTreeContract>lambdaQuery().eq(WbsTreeContract::getPKeyId, primaryKeyId));
     }
 
+    @Override
+    public List<WbsTreeContract> getContractNodeByPrimaryKeyIds(List<String> supplementPKeyIds) {
+        return wbsTreeContractService.getBaseMapper().selectList(Wrappers.<WbsTreeContract>lambdaQuery()
+                .select(WbsTreeContract::getIsConcrete, WbsTreeContract::getNodeName, WbsTreeContract::getFullName, WbsTreeContract::getPKeyId)
+                .eq(WbsTreeContract::getNodeType, 6)
+                .in(WbsTreeContract::getPKeyId, supplementPKeyIds));
+    }
+
     @Override
     public Boolean removeContractTreeNode(List<String> ids) {
         if (ids.size() > 0) {
@@ -395,6 +403,7 @@ public class WbsTreeContractClientImpl implements WbsTreeContractClient {
 
     /**
      * 根据pkid,找符合nodetype的祖先节点
+     *
      * @param pkeyId
      * @param nodeType
      * @return
@@ -409,7 +418,7 @@ public class WbsTreeContractClientImpl implements WbsTreeContractClient {
             String parentId = one.getParentId().toString();
             while (loop < max && StringUtils.isNotEquals(0, parentId)) {
                 WbsTreeContract next = this.wbsTreeContractService.getOne(Wrappers.<WbsTreeContract>lambdaQuery().eq(WbsTreeContract::getContractId, one.getContractId()).eq(WbsTreeContract::getId, parentId));
-                if(next.getNodeType() <= nodeType){
+                if (next.getNodeType() <= nodeType) {
                     return next.getPKeyId();
                 }
                 parentId = next.getParentId().toString();
@@ -420,8 +429,8 @@ public class WbsTreeContractClientImpl implements WbsTreeContractClient {
     }
 
     @Override
-    public List<AppWbsTreeContractVO> searchNodeAllTableInfo(String primaryKeyId, String type, String contractId, String projectId,Long userId) {
-        List<AppWbsTreeContractVO> list = wbsTreeContractService.searchNodeAllTable(primaryKeyId+":"+userId, type, contractId, projectId,null);
+    public List<AppWbsTreeContractVO> searchNodeAllTableInfo(String primaryKeyId, String type, String contractId, String projectId, Long userId) {
+        List<AppWbsTreeContractVO> list = wbsTreeContractService.searchNodeAllTable(primaryKeyId + ":" + userId, type, contractId, projectId, null);
         return list;
     }
 

+ 30 - 4
blade-service/blade-meter/src/main/java/org/springblade/meter/controller/MeterTreeController.java

@@ -166,6 +166,10 @@ public class MeterTreeController extends BladeController {
         Integer maxSort = meterTreeSystemService.selectMaxSort(obj.getParentId());
         obj.setSort(ObjectUtils.defaultIfNull(maxSort, 0) + 1);
 
+        if (parentNode.getNodeType() != null && obj.getNodeType() < parentNode.getNodeType()){
+            throw new ServiceException("节点类型不能大于父节点");
+        }
+
         return R.data(meterTreeSystemService.save(obj));
     }
 
@@ -206,7 +210,8 @@ public class MeterTreeController extends BladeController {
     @ApiOperationSupport(order = 7)
     @ApiOperation(value = "系统树节点修改", notes = "传入MeterTreeSystem")
     public R<Object> systemUpdate(@RequestBody MeterTreeSystem obj) {
-        return R.data(meterTreeSystemService.updateById(obj));
+        meterTreeSystemService.systemUpdate(obj);
+        return R.success("修改成功");
     }
 
     @GetMapping("/system/remove")
@@ -373,6 +378,10 @@ public class MeterTreeController extends BladeController {
         }
         obj.setAncestor(parentNode.getAncestor() + "," + parentNode.getId());
 
+        if (parentNode.getNodeType() != null && obj.getNodeType() < parentNode.getNodeType()){
+            throw new ServiceException("节点类型不能大于父节点");
+        }
+
         /*获取最大sort*/
         Integer maxSort = meterTreeProjectService.selectMaxSort(obj.getParentId());
         obj.setSort(ObjectUtils.defaultIfNull(maxSort, 0) + 1);
@@ -426,7 +435,8 @@ public class MeterTreeController extends BladeController {
     @ApiOperation(value = "项目树节点修改", notes = "传入MeterTreeProject")
     public R<Object> projectUpdate(@RequestBody MeterTreeProject obj) {
         obj.setUpdateStatus(1); //编辑
-        return R.data(meterTreeProjectService.updateById(obj));
+        meterTreeProjectService.projectUpdate(obj);
+        return R.success("修改成功");
     }
 
     @GetMapping("/project/remove")
@@ -643,6 +653,14 @@ public class MeterTreeController extends BladeController {
         } else if (ObjectUtil.isEmpty(dto.getDecompositionList()) || dto.getDecompositionList().size() == 0) {
             /*非最底层节点修改*/
             dto.setUpdateStatus(1); //编辑
+            //校验是否大于父节点类型
+            MeterTreeContract treeContract = meterTreeContractService.getById(dto.getParentId());
+            if (treeContract == null){
+                throw new ServiceException("未找到父节点信息");
+            }
+            if (treeContract.getNodeType() != null && dto.getNodeType() < treeContract.getNodeType()){
+                throw new ServiceException("节点类型不能大于父节点");
+            }
             if (meterTreeContractService.updateById(dto)) {
                 return R.success("操作成功");
             }
@@ -696,6 +714,12 @@ public class MeterTreeController extends BladeController {
                     vo.setStakeTypeName(dict.getDictValue());
                 }
             }
+            if (basicInfo.getNodeType() != null){
+                Dict dict = jdbcTemplate.query("SELECT dict_value FROM blade_dict_biz WHERE is_deleted = 0 AND code = 'meter_unit_type' AND dict_key = " + basicInfo.getNodeType(), new BeanPropertyRowMapper<>(Dict.class)).stream().findAny().orElse(null);
+                if (dict != null) {
+                    vo.setNodeTypeName(dict.getDictValue());
+                }
+            }
             //判断是否为最底层节点,如果为最底层节点则直接查询清单,不为最底层节点则汇总子节点总和
             long count = meterTreeContractService.count(new LambdaQueryWrapper<MeterTreeContract>()
                     .eq(MeterTreeContract::getContractId, basicInfo.getContractId())
@@ -871,9 +895,11 @@ public class MeterTreeController extends BladeController {
     public R<String> contractTreeNodeImport(@RequestParam String id,Integer type, MultipartFile file) {
         if (ObjectUtil.isNotEmpty(id) && type != null) {
             if (type == 1){
-               return meterTreeContractService.contractTreeNodeImport1(id, file);
+                return meterTreeContractService.contractTreeNodeImport1(id, file);
             }else if (type == 2) {
-               return meterTreeContractService.contractTreeNodeImport2(id, file);
+                return meterTreeContractService.contractTreeNodeImport2(id, file);
+            }else if (type == 3){
+                return meterTreeContractService.contractTreeNodeImport3(id, file);
             }
         }
         return R.fail("操作失败");

+ 11 - 4
blade-service/blade-meter/src/main/java/org/springblade/meter/mapper/MeterTreeContractMapper.java

@@ -5,11 +5,11 @@ import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.springblade.meter.dto.MeterTreeContractDTO;
 import org.springblade.meter.entity.*;
-import org.springblade.meter.vo.MeterFullTreeVO;
-import org.springblade.meter.vo.MeterTreeLinkWbsTreeVO;
-import org.springblade.meter.vo.NodePartVO;
+import org.springblade.meter.vo.*;
 
+import java.io.Serializable;
 import java.math.BigDecimal;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -21,9 +21,12 @@ public interface MeterTreeContractMapper extends BaseMapper<MeterTreeContract> {
 
     MeterTreeContract getAllChildNodeMoney(@Param("contractId") Long contractId,@Param("id") Long id);
 
+    //批量修改带施工图
     void batchUpdateById(@Param("list") List<MeterTreeContract> list);
+    //批量修改不带施工图
+    void batchUpdateById2(@Param("list") List<MeterTreeContract> list);
 
-    List<InventoryFormMeter> getNodeAllForm(@Param("ids") Set<Long> ids);
+    List<InventoryFormMeter> getNodeAllForm(@Param("ids") Collection<? extends Serializable> ids);
 
     List<String> getAllEqualsNumber(@Param("contractId") Long contractId,@Param("numbers") List<String> collect);
 
@@ -44,4 +47,8 @@ public interface MeterTreeContractMapper extends BaseMapper<MeterTreeContract> {
     List<NodePartVO> getAllWbsNode(@Param("projectId") Long projectId,@Param("contractId") Long contractId);
 
     List<MiddleMeterApply> getMiddleMeter(@Param("contractId") Long contractId, @Param("ids") List<Long> meterIds);
+
+    List<MeterImport3VO> getALLNodeByContractId(@Param("contractId") Long contractId);
+
+    List<InventoryFormMeterVO2> getAllFormMeter(@Param("contractId") Long contractId);
 }

+ 22 - 1
blade-service/blade-meter/src/main/java/org/springblade/meter/mapper/MeterTreeContractMapper.xml

@@ -11,6 +11,16 @@
             where id = #{item.id}
         </foreach>
     </update>
+    <update id="batchUpdateById2">
+        <foreach item="item" collection="list" separator=";">
+            UPDATE s_meter_tree_contract
+            <set>
+                build_picture_money = #{item.buildPictureMoney},
+                change_money = #{item.changeMoney}
+            </set>
+            where id = #{item.id}
+        </foreach>
+    </update>
     <update id="batchUpdateFormByNumber">
         <foreach item="value" collection="map" index="key" separator=";">
             UPDATE s_contract_inventory_form
@@ -32,7 +42,7 @@
         where contract_id = #{contractId} and is_deleted = 0 and  FIND_IN_SET(#{id}, ancestor)
     </select>
     <select id="getNodeAllForm" resultType="org.springblade.meter.entity.InventoryFormMeter">
-        select contract_meter_id,change_build_picture_money
+        select contract_meter_id,build_picture_money,change_build_picture_money
         from s_inventory_form_meter where is_deleted = 0 and contract_meter_id in
         <foreach collection="ids" item="id" open="(" close=")" separator=",">
             #{id}
@@ -90,6 +100,17 @@
             #{id}
         </foreach>
     </select>
+    <select id="getALLNodeByContractId" resultType="org.springblade.meter.vo.MeterImport3VO">
+        select id ,parent_id,node_name,node_type,ancestor,0 as isNew
+        from s_meter_tree_contract where contract_id = #{contractId} and is_deleted = 0
+    </select>
+    <select id="getAllFormMeter" resultType="org.springblade.meter.vo.InventoryFormMeterVO2">
+        select *,
+               if((select count(1) from s_inventory_form_apply ifa where ifa.contract_id = #{contractId} and ifa.is_deleted = 0
+                    and ifa.contract_meter_id = ifm.contract_meter_id and ifa.contract_form_id = ifm.contract_form_id) = 0,0,1) as isMeter
+        from s_inventory_form_meter ifm
+        where contract_id = #{contractId} and is_deleted = 0
+    </select>
 
 
 </mapper>

+ 6 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/service/MeterTreeContractService.java

@@ -12,6 +12,8 @@ import org.springblade.meter.vo.MeterTreeContractVO;
 import org.springblade.meter.vo.MeterTreeAndWbsTreeVO;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.io.Serializable;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
@@ -29,6 +31,8 @@ public interface MeterTreeContractService extends BaseService<MeterTreeContract>
 
     //异步重新计算节点金额,和修改施工图号
     void asyncCalculateNodeMoney(List<ChangeNodeVO> vos);
+    //通过合同计量单元id,重新计算节点金额
+    void asyncCalculateNodeMoney2(Collection<? extends Serializable> ids);
 
     boolean contractTreeNodeImport(String id, MultipartFile file);
 
@@ -36,6 +40,8 @@ public interface MeterTreeContractService extends BaseService<MeterTreeContract>
     R<String> contractTreeNodeImport2(String id, MultipartFile file);
     //只导入一层
     R<String> contractTreeNodeImport1(String id, MultipartFile file);
+    //按层级导入
+    R<String> contractTreeNodeImport3(String id, MultipartFile file);
 
     boolean contractUpdate(MeterTreeContractDTO dto);
 

+ 1 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/service/MeterTreeProjectService.java

@@ -10,4 +10,5 @@ public interface MeterTreeProjectService extends BaseService<MeterTreeProject> {
 
     R<Object> projectTreeInitOrSync(Long meterTemplateId, Long projectId);
 
+    void projectUpdate(MeterTreeProject obj);
 }

+ 1 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/service/MeterTreeSystemService.java

@@ -7,4 +7,5 @@ public interface MeterTreeSystemService extends BaseService<MeterTreeSystem> {
 
     Integer selectMaxSort(Long parentId);
 
+    void systemUpdate(MeterTreeSystem obj);
 }

+ 364 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/service/impl/MeterTreeContractServiceImpl.java

@@ -39,6 +39,7 @@ import org.springframework.web.multipart.MultipartFile;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.Serializable;
 import java.math.BigDecimal;
 import java.util.*;
 import java.util.function.Function;
@@ -447,6 +448,11 @@ public class MeterTreeContractServiceImpl extends BaseServiceImpl<MeterTreeContr
                         cObj.setParentId(dto.getContractNodeId());
                         /*ancestor*/
                         cObj.setAncestor(meterTreeContractNode.getAncestor() + "," + cObj.getParentId());
+                        if (meterTreeContractNode.getNodeType() != null) {
+                            cObj.setNodeType(meterTreeContractNode.getNodeType()+1);
+                        }
+
+                        cObj.setNodeCode(null);
 
                         baseMapper.insert(cObj);
                     }
@@ -504,6 +510,11 @@ public class MeterTreeContractServiceImpl extends BaseServiceImpl<MeterTreeContr
                             cObj.setParentId(parentId);
                             cObj.setAncestor(null); //后面重新计算子级ancestor
                         }
+                        if (meterTreeContractNode.getNodeType() != null) {
+                            cObj.setNodeType(meterTreeContractNode.getNodeType()+1);
+                        }
+
+                        cObj.setNodeCode(null);
 
                         meterTreeContractResultData.add(cObj);
                     }
@@ -579,6 +590,36 @@ public class MeterTreeContractServiceImpl extends BaseServiceImpl<MeterTreeContr
         baseMapper.batchUpdateById(list);
     }
 
+    /**
+     * 统计节点的的施工图金额,变更后金额,根据节点id
+     * @param ids
+     */
+    @Override
+    public void asyncCalculateNodeMoney2(Collection<? extends Serializable> ids) {
+        //获取所有要重新计算的节点的最新数据
+        List<MeterTreeContract> list = this.listByIds(ids);
+        //获取节点下所有分解的表单
+        List<InventoryFormMeter> formMeters = baseMapper.getNodeAllForm(ids);
+        //聚合施工图金额,按照合同计量单元分组
+        Map<Long, BigDecimal> decimalMap = formMeters.stream()
+                .collect(Collectors.groupingBy(l -> l.getContractMeterId(),
+                        Collectors.mapping(InventoryFormMeter::getBuildPictureMoney,
+                                Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
+        //聚合变更后施工图金额,按照合同计量单元分组
+        Map<Long, BigDecimal> decimalMap2 = formMeters.stream()
+                .collect(Collectors.groupingBy(l -> l.getContractMeterId(),
+                        Collectors.mapping(InventoryFormMeter::getChangeBuildPictureMoney,
+                                Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
+        list.stream().forEach(l -> {
+            //为节点设置施工图金额
+            l.setBuildPictureMoney(decimalMap.get(l.getId()) == null ? BigDecimal.ZERO : decimalMap.get(l.getId()));
+            //为节点设置变更后施工图金额
+            l.setChangeMoney(decimalMap2.get(l.getId()) == null ? BigDecimal.ZERO : decimalMap2.get(l.getId()));
+        });
+        //拼接SQL修改合同图号和重新计算的金额
+        baseMapper.batchUpdateById2(list);
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public boolean contractTreeNodeImport(String id, MultipartFile file) {
@@ -1782,9 +1823,332 @@ public class MeterTreeContractServiceImpl extends BaseServiceImpl<MeterTreeContr
         return R.success("成功导入:节点("+addNode+")个,"+"新增清单("+addForm+")条,"+"修改清单("+updateForm+")条.");
     }
 
+    @Override
+    @Transactional
+    public R<String> contractTreeNodeImport3(String id, MultipartFile file) {
+        try {
+            //获取当前节点
+            MeterTreeContract meterTreeContract = baseMapper.selectById(id);
+            if (meterTreeContract == null){
+                throw new ServiceException("未找到当前导入节点信息");
+            }
+            Long projectId = meterTreeContract.getProjectId();
+            Long contractId = meterTreeContract.getContractId();
+            /*解析excel*/
+            List<Map<String, String>> parseExcelFileToList;
+            try {
+                parseExcelFileToList = this.parseExcelFile(file);
+            } catch (Exception e) {
+                throw new ServiceException("请检查格式:" + e.getMessage());
+            }
+            if (parseExcelFileToList.size() == 0) {
+                throw new ServiceException("excel中未发现数据,请检查后再导入");
+            }
+            //过滤掉单位工程为空的
+            parseExcelFileToList = parseExcelFileToList.stream()
+                    .filter(l -> StringUtils.isNotBlank(l.get("单位工程"))).collect(Collectors.toList());
+            if (parseExcelFileToList.size() == 0) {
+                throw new ServiceException("excel中未发现单位工程数据,请检查后再导入");
+            }
+            //获取合同段所有的清单
+            List<ContractInventoryForm> formList = contractInventoryFormMapper.selectList(new LambdaQueryWrapper<ContractInventoryForm>()
+                    .eq(ContractInventoryForm::getContractId, meterTreeContract.getContractId())
+                    .eq(ContractInventoryForm::getIsFormNode, 1));
+            if (formList.size() == 0){
+                throw new ServiceException("导入失败,当前合同段没有合同工程清单");
+            }
+            //清单转换为编号集合,用于校验是否存在
+            List<String> numberList = formList.stream().map(l -> l.getFormNumber()).collect(Collectors.toList());
+            //清单按照编号转换为map,用于设置中间表信息
+            Map<String, ContractInventoryForm> inventoryFormMap = formList.stream().collect(Collectors.toMap(l -> l.getFormNumber(), l -> l));
+            //校验数据,开始桩号和结束桩号必须同时存在,清单编号必须存在数据,有清单编号必须填写分解量
+            parseExcelFileToList.stream().forEach(l->{
+                if ((StringUtils.isBlank(l.get("开始桩号")) && StringUtils.isNotBlank(l.get("结束桩号")))
+                        || (StringUtils.isNotBlank("开始桩号") && StringUtils.isBlank(l.get("结束桩号")))){
+                    throw new ServiceException("开始桩号和结束桩号必须同时存在,请修改后重新导入");
+                }
+                if (StringUtils.isNotBlank(l.get("清单编号"))){
+                    if (numberList.indexOf(l.get("清单编号")) == -1){
+                        throw new ServiceException("合同段中不存在清单编号:"+l.get("清单编号")+"请检查后重新导入");
+                    }
+                    if (StringUtils.isBlank(l.get("分解核实量"))){
+                        throw new ServiceException("清单编号:"+l.get("清单编号")+",没有填写分解核实量");
+                    }
+                }
+            });
+            //获取清单与计量单元中间表的所有数据,并且携带是否被计量的信息
+            List<InventoryFormMeterVO2> formMeters = baseMapper.getAllFormMeter(meterTreeContract.getContractId());
+            Boolean isLink = false; // 是否存在中间表数据
+            Map<MeterImport3VO2, InventoryFormMeterVO2> meterMap = new HashMap<>();
+            //按照计量单元id分组,用于判断是否存在
+            if (formMeters.size() > 0){
+                isLink = true;
+                try {
+                    meterMap = formMeters.stream().collect(Collectors.toMap(l -> new MeterImport3VO2(l.getContractMeterId(), l.getContractFormId()), l -> l));
+                }catch (Exception e){
+                    throw new ServiceException("清单与计量单元中间表中存在错误重复数据,请联系管理员");
+                }
+            }
+            /*节点新增*/
+            List<MeterImport3VO> resultNodeAdd = new LinkedList<>();
+            List<MeterTreeContract> resultNodeListAdd = new LinkedList<>();
+            /*节点修改*/
+            List<MeterTreeContract> resultNodeListUpdate = new ArrayList<>();
+            /*节点金额修改Ids*/
+            Set<Long> updateNodeSet = new HashSet<>();
+            /*清单中间新增*/
+            List<InventoryFormMeter> resultFormListAdd = new LinkedList<>();
+            /*清单中间数量修改*/
+            List<InventoryFormMeter> resultFormListUpdate = new LinkedList<>();
+            /*合同清单变更后数量修改*/
+            List<ContractInventoryForm> InventoryFormListUpdate = new LinkedList<>();
+
+            //获取出所有的合同计量单元节点,并转化为树,用VO标识字段是新增节点,还是原生节点
+            List<MeterImport3VO> vos = baseMapper.getALLNodeByContractId(meterTreeContract.getContractId());
+            List<MeterImport3VO> list = ForestNodeMerger.merge(vos);
+            if (list.size() != 1){
+                throw new ServiceException("当前合同计量单元结构错误,请联系管理员");
+            }
+
+            //层级数组
+            String[] nodeType = {"单位工程","子单位工程","分部工程","子分部工程","分项工程","子分项工程"};
+            //循环Excel每一行
+            for (Map<String, String> map : parseExcelFileToList) {
+                //上一个节点(必定存在)
+                MeterImport3VO lastNode = list.get(0);
+                //当前层节点(不存在就新增绑定到上一个节点的children下)
+                List<MeterImport3VO> thisNode = lastNode.getChildren();
+                Map<String, MeterImport3VO> thisMap = new HashMap<>();
+                if (thisNode != null && thisNode.size() > 0) {
+                    //当前层节点map,key为节点名称(同一层,不能有节点名称相同)
+                    thisMap = thisNode.stream().collect(Collectors.toMap(l -> l.getNodeName(), l -> l));
+                }
+                //标识上一层节点是否为新增,默认为否
+                Boolean isNew = false;
+                //循环处理节点
+                for (int i = 0; i <= 6; i++) {
+                    int j = i==0?1:i;
+                    //处理前面6个节点,如果等于6则处理工序节点
+                    String nodeName = null;
+                    if (i != 6) {
+                        nodeName = map.get(nodeType[i]);
+                    }else {
+                        if (StringUtils.isNotBlank(map.get("开始桩号")) && StringUtils.isNotBlank(map.get("结束桩号"))){
+                            nodeName = map.get("开始桩号") + "~" +map.get("结束桩号");
+                        }
+                    }
+                    //Excel存在节点名称则执行,不存在则跳过
+                    if (StringUtils.isNotBlank(nodeName)){
+                        //上一层节点为新增 或者 当前层不存在数据,都去创建当前层数据
+                        if (isNew || (thisNode == null || thisNode.size() == 0)){
+                            //创建当前层数据,添加到上一层的children下,并且修改isNew为true
+                            isNew = true;
+                            List<MeterImport3VO> childList = new ArrayList<>();
+                            MeterImport3VO vo1 = new MeterImport3VO();
+                            vo1.setId(SnowFlakeUtil.getId());
+                            vo1.setParentId(lastNode.getId());
+                            vo1.setProjectId(projectId);
+                            vo1.setContractId(contractId);
+                            vo1.setAncestor(lastNode.getAncestor()+","+lastNode.getId());
+                            vo1.setNodeName(nodeName);
+                            vo1.setIsNew(1);
+                            vo1.setNodeType(j);
+                            if (i == 6 && (StringUtils.isNotBlank(map.get("图册")) || StringUtils.isNotBlank(map.get("图号")))){
+                                vo1.setRemarks(map.get("图册"));
+                                vo1.setContractPicture(map.get("图号"));
+                            }
+                            childList.add(vo1);
+                            //则新增到上一层的children下
+                            lastNode.setChildren(childList);
+                            //设置上一层为当前层
+                            lastNode = vo1;
+                            //添加到新增节点中
+                            resultNodeAdd.add(vo1);
+                        }else {
+                            //当前层存在数据,则是否存在集合中
+                            MeterImport3VO vo2 = thisMap.get(nodeName);
+                            if (vo2 == null) {
+                                //不存在集合中,则新增,然后添加进当前集合
+                                isNew = true;
+                                MeterImport3VO vo1 = new MeterImport3VO();
+                                vo1.setId(SnowFlakeUtil.getId());
+                                vo1.setParentId(lastNode.getId());
+                                vo1.setProjectId(projectId);
+                                vo1.setContractId(contractId);
+                                vo1.setAncestor(lastNode.getAncestor()+","+lastNode.getId());
+                                vo1.setNodeName(nodeName);
+                                vo1.setIsNew(1);
+                                vo1.setNodeType(j);
+                                if (i == 6 && (StringUtils.isNotBlank(map.get("图册")) || StringUtils.isNotBlank(map.get("图号")))){
+                                    vo1.setRemarks(map.get("图册"));
+                                    vo1.setContractPicture(map.get("图号"));
+                                }
+                                thisNode.add(vo1);
+                                //设置上一层为当前层
+                                lastNode = vo1;
+                                //添加到新增节点中
+                                resultNodeAdd.add(vo1);
+                            }else {
+                                //查看当前节点层级是否匹配
+                                if (vo2.getNodeType() == null){
+                                    MeterTreeContract tree = new MeterTreeContract();
+                                    tree.setId(vo2.getId());
+                                    tree.setNodeType(j);
+                                    resultNodeListUpdate.add(tree);
+                                }else {
+                                    if (vo2.getNodeType() != j){
+                                        throw new ServiceException("节点:"+nodeName+"存在于合同中,但类型和当前Excel不匹配");
+                                    }
+                                }
+                                //工序节点涉及到修改备注和图号
+                                if (i == 6 && (StringUtils.isNotBlank(map.get("图册")) || StringUtils.isNotBlank(map.get("图号")))){
+                                    MeterTreeContract tree = new MeterTreeContract();
+                                    tree.setId(vo2.getId());
+                                    tree.setRemarks(map.get("图册"));
+                                    tree.setContractPicture(map.get("图号"));
+                                    resultNodeListUpdate.add(tree);
+                                }
+                                //把当前节点设置为上一层,并且依次重置thisNode和thisMap
+                                lastNode = vo2;
+                                thisNode = lastNode.getChildren();
+                                if (thisNode != null && thisNode.size() > 0) {
+                                    //当前层节点map,key为节点名称(同一层,不能有节点名称相同)
+                                    thisMap = thisNode.stream().collect(Collectors.toMap(l -> l.getNodeName(), l -> l));
+                                }
+
+                            }
+                        }
+                    }
+                }
+                // 处理完成节点,处理清单,如果清单不存在则直接跳过
+                String formNumber = map.get("清单编号");
+                if (StringUtils.isBlank(formNumber)){
+                    continue;
+                }
+                //获取清单基础信息
+                ContractInventoryForm form = inventoryFormMap.get(formNumber);
+                InventoryFormMeterVO2 meter2 = meterMap.get(new MeterImport3VO2(lastNode.getId(), form.getId()));
+                BigDecimal total = BigDecimal.ZERO;
+                try {
+                    total = new BigDecimal(map.get("分解核实量"));
+                }catch (Exception e){
+                    throw new ServiceException("清单编号:"+map.get("清单编号")+",分解核实量包含字符,请修改后重新导入");
+                }
+                if(lastNode.getIsNew() == 1 || !isLink || meter2 == null){
+                    //上一层节点为新增,直接挂载
+                    //新增中间表数据
+                    InventoryFormMeter meter = new InventoryFormMeter();
+                    meter.setProjectId(meterTreeContract.getProjectId());
+                    meter.setContractId(meterTreeContract.getContractId());
+                    meter.setContractMeterId(lastNode.getId());
+                    meter.setContractFormId(form.getId());
+                    meter.setBuildPictureTotal(total);
+                    meter.setChangeBuildPictureTotal(total);
+                    meter.setBuildPictureMoney(total.multiply(form.getCurrentPrice()));
+                    meter.setChangeBuildPictureMoney(meter.getBuildPictureMoney());
+                    resultFormListAdd.add(meter);
+                    //设置清单增量
+                    ContractInventoryForm form2 = new ContractInventoryForm();
+                    form2.setFormNumber(form.getFormNumber());
+                    form2.setChangeTotal(total);
+                    InventoryFormListUpdate.add(form2);
+                }else {
+                    //当前节点下存在当前表单,则判断是否被计量过,被计量过则跳过,没被计量过则做增量,没被计量时,施工图金额和变更后施工图金额相等
+                    if (meter2.getIsMeter() == 0){
+                        InventoryFormMeter meter = new InventoryFormMeter();
+                        meter.setId(meter2.getId());
+                        meter.setBuildPictureTotal(meter2.getBuildPictureTotal().add(total));
+                        meter.setChangeBuildPictureTotal(meter.getBuildPictureTotal());
+                        meter.setBuildPictureMoney(meter.getBuildPictureTotal().multiply(form.getCurrentPrice()));
+                        meter.setChangeBuildPictureMoney(meter.getBuildPictureMoney());
+                        resultFormListUpdate.add(meter);
+                        //设置清单增量
+                        ContractInventoryForm form2 = new ContractInventoryForm();
+                        form2.setFormNumber(form.getFormNumber());
+                        form2.setChangeTotal(total);
+                        InventoryFormListUpdate.add(form2);
+                    }
+                }
+                //把上层节点id添加进修改集合,重新计算金额
+                updateNodeSet.add(lastNode.getId());
+
+            }
+            int addNode = 0;
+            int addForm = 0;
+            int updateForm = 0;
+            //新增节点
+            if (resultNodeAdd.size() > 0) {
+                resultNodeListAdd = resultNodeAdd.stream().map(l->{
+                    MeterTreeContract contract = new MeterTreeContract();
+                    BeanUtil.copyProperties(l,contract);
+                    return contract;
+                }).collect(Collectors.toList());
+                this.saveBatch(resultNodeListAdd, 1000);
+                addNode = resultNodeListAdd.size();
+            }
+            //修改节点 图号或者备注
+            if (resultNodeListUpdate.size() > 0){
+                this.updateBatchById(resultNodeListUpdate);
+            }
+            /*清单中间新增*/
+            if (resultFormListAdd.size() > 0) {
+                //校验数据
+                try {
+                    resultFormListAdd.stream().collect(Collectors.toMap(l -> new MeterImport3VO2(l.getContractMeterId(), l.getContractFormId()), l -> l));
+                }catch (Exception e){
+                    throw new ServiceException("导入模板中存在同一个节点下清单重复,请直接合并分解量后再导入");
+                }
+                inventoryFormMeterMapper.batchInsert(resultFormListAdd);
+                addForm = resultFormListAdd.size();
+            }
+
+            /*清单中间数量修改*/
+            if (resultFormListUpdate.size() > 0) {
+                for (InventoryFormMeter inventoryFormMeter : resultFormListUpdate) {
+                    String sql = "UPDATE s_inventory_form_meter " +
+                            "SET build_picture_total = ? ," +
+                            "change_build_picture_total = ? ," +
+                            "build_picture_money = ? ," +
+                            "change_build_picture_money = ? WHERE id = ?";
+                    jdbcTemplate.update(sql,
+                            inventoryFormMeter.getBuildPictureTotal(),
+                            inventoryFormMeter.getChangeBuildPictureTotal(),
+                            inventoryFormMeter.getBuildPictureMoney(),
+                            inventoryFormMeter.getChangeBuildPictureMoney(),
+                            inventoryFormMeter.getId());
+                }
+                updateForm = resultFormListUpdate.size();
+            }
+            //修改合同工程清单的变更后数量
+            if (InventoryFormListUpdate.size() > 0) {
+                Map<String, BigDecimal> map = InventoryFormListUpdate.stream()
+                        .collect(Collectors.groupingBy(l -> l.getFormNumber(),
+                                Collectors.mapping(ContractInventoryForm::getChangeTotal, Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
+                baseMapper.batchUpdateFormByNumber(meterTreeContract.getContractId(), map);
+            }
+
+
+            //修改节点金额放最后,等中间表数据保存完成之后,再去统计
+            if (updateNodeSet.size() > 0){
+                this.asyncCalculateNodeMoney2(updateNodeSet);
+            }
+            return R.success("成功导入:节点("+addNode+")个,"+"新增清单("+addForm+")条,"+"修改清单("+updateForm+")条.");
+        }catch (Exception e){
+            throw new ServiceException("导入失败:"+e.getMessage());
+        }
+    }
+
     @Override
     @Transactional
     public boolean contractUpdate(MeterTreeContractDTO dto) {
+        //校验是否大于父节点类型
+        MeterTreeContract treeContract = this.getById(dto.getParentId());
+        if (treeContract == null){
+            throw new ServiceException("未找到父节点信息");
+        }
+        if (treeContract.getNodeType() != null && dto.getNodeType() < treeContract.getNodeType()){
+            throw new ServiceException("节点类型不能大于父节点");
+        }
         //先校验节点编号是否唯一
         if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotBlank(dto.getNodeCode())){
             long count = this.count(new LambdaUpdateWrapper<MeterTreeContract>()

+ 13 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/service/impl/MeterTreeProjectServiceImpl.java

@@ -275,6 +275,19 @@ public class MeterTreeProjectServiceImpl extends BaseServiceImpl<MeterTreeProjec
         }
     }
 
+    @Override
+    public void projectUpdate(MeterTreeProject obj) {
+        //校验是否大于父节点类型
+        MeterTreeProject treeProject = this.getById(obj.getParentId());
+        if (treeProject == null){
+            throw new ServiceException("未找到父节点信息");
+        }
+        if (treeProject.getNodeType() != null && obj.getNodeType() < treeProject.getNodeType()){
+            throw new ServiceException("节点类型不能大于父节点");
+        }
+        this.updateById(obj);
+    }
+
     /**
      * 获取对应的父级的ancestor字段
      *

+ 15 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/service/impl/MeterTreeSystemServiceImpl.java

@@ -1,5 +1,7 @@
 package org.springblade.meter.service.impl;
 
+import org.apache.commons.lang.StringUtils;
+import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.mp.base.BaseServiceImpl;
 import org.springblade.meter.entity.MeterTreeSystem;
 import org.springblade.meter.mapper.MeterTreeSystemMapper;
@@ -14,4 +16,17 @@ public class MeterTreeSystemServiceImpl extends BaseServiceImpl<MeterTreeSystemM
         return baseMapper.selectMaxSort(parentId);
     }
 
+    @Override
+    public void systemUpdate(MeterTreeSystem obj) {
+        //校验是否大于父节点类型
+        MeterTreeSystem system = this.getById(obj.getParentId());
+        if (system == null){
+            throw new ServiceException("未找到父节点信息");
+        }
+        if (system.getNodeType() != null && obj.getNodeType() < system.getNodeType()){
+            throw new ServiceException("节点类型不能大于父节点");
+        }
+        this.updateById(obj);
+    }
+
 }