Bladeren bron

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

# Conflicts:
#	adm-business/adm-middleware/src/main/java/com/persagy/proxy/dictionary/service/impl/AbstractAdmDictBaseServiceImpl.java
#	adm-business/adm-middleware/src/main/java/com/persagy/proxy/dictionary/service/impl/AdmDictServiceImpl.java
lijie 3 jaren geleden
bovenliggende
commit
76af247cf2
29 gewijzigde bestanden met toevoegingen van 1267 en 458 verwijderingen
  1. 54 7
      adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/controller/DiagramController.java
  2. 148 5
      adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/DataStrategy.java
  3. 28 53
      adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/DiagramBuilder.java
  4. 125 125
      adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/DiagramDataLoader.java
  5. 26 4
      adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/impl/DataStrategyImpl.java
  6. 14 4
      adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/line/Block.java
  7. 44 1
      adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/line/LineEnd.java
  8. 33 13
      adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/line/LineLayoutManager.java
  9. 590 0
      adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/line/PathBuilder.java
  10. 1 0
      adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/model/ConnectPoint.java
  11. 1 10
      adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/model/Diagram.java
  12. 5 11
      adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/model/Line.java
  13. 4 0
      adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/model/base/XY.java
  14. 11 187
      adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/util/GeomUtil.java
  15. 36 3
      adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/dao/DiagramMapper.java
  16. 27 19
      adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/demo/DemoDataStrategy.java
  17. 1 1
      adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/entity/ModelAdapter.java
  18. 4 0
      adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/manage/DemoDiagramManager.java
  19. 3 0
      adm-business/adm-diagram/src/main/resources/mapper/Diagram.xml
  20. 23 0
      adm-business/adm-middleware/src/main/java/com/persagy/proxy/common/client/DmpRwdClient.java
  21. 11 0
      adm-business/adm-middleware/src/main/java/com/persagy/proxy/common/constant/DmpUrlConstant.java
  22. 1 1
      adm-business/adm-middleware/src/main/java/com/persagy/proxy/dictionary/controller/AdmDictController.java
  23. 2 0
      adm-business/adm-middleware/src/main/java/com/persagy/proxy/dictionary/model/AdmDict.java
  24. 5 0
      adm-business/adm-middleware/src/main/java/com/persagy/proxy/dictionary/model/AdmObjectType.java
  25. 5 0
      adm-business/adm-middleware/src/main/java/com/persagy/proxy/dictionary/service/IAdmDictBaseService.java
  26. 42 2
      adm-business/adm-middleware/src/main/java/com/persagy/proxy/dictionary/service/impl/AbstractAdmDictBaseServiceImpl.java
  27. 20 9
      adm-business/adm-middleware/src/main/java/com/persagy/proxy/dictionary/service/impl/AdmDictServiceImpl.java
  28. 2 2
      adm-business/adm-middleware/src/main/java/com/persagy/proxy/migration/service/Impl/MigrationAbstractServiceImpl.java
  29. 1 1
      adm-business/adm-middleware/src/main/java/com/persagy/proxy/migration/service/Impl/ObjectDigitalMigration.java

+ 54 - 7
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/controller/DiagramController.java

@@ -1,10 +1,16 @@
 package com.persagy.adm.diagram.controller;
 
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.StrUtil;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.persagy.adm.diagram.core.ContentParser;
 import com.persagy.adm.diagram.core.DataStrategy;
 import com.persagy.adm.diagram.core.model.Diagram;
 import com.persagy.adm.diagram.core.model.DiagramNode;
+import com.persagy.adm.diagram.core.model.EquipmentNode;
+import com.persagy.adm.diagram.core.model.Line;
+import com.persagy.adm.diagram.core.model.base.Container;
+import com.persagy.adm.diagram.core.model.base.IComponent;
 import com.persagy.adm.diagram.core.model.template.DiagramTemplate;
 import com.persagy.adm.diagram.frame.BdtpRequest;
 import com.persagy.adm.diagram.manage.DemoDiagramManager;
@@ -23,6 +29,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
@@ -55,13 +62,13 @@ public class DiagramController {
      */
     @ApiOperation("系统图列表接口")
     @PostMapping("/getDiagrams")
-    public CommonResult<List<Diagram>> getDiagrams(@RequestBody Diagram diagram) {
+    public CommonResult<List<Diagram>> getDiagrams(@RequestBody Map<String, Object> diagram) {
         BdtpRequest current = BdtpRequest.getCurrent();
         String groupCode = current.getGroupCode();
         String projectId = current.getProjectId();
 
         List<Diagram> diagramList = dataStrategy.getDiagrams(null, projectId,
-                diagram.getSystemId(), groupCode, diagram.getName());
+                (String) diagram.get("systemId"), groupCode, (String) diagram.get("name"), (Boolean) diagram.get("flag"));
 
         return ResultHelper.multi(diagramList);
     }
@@ -100,17 +107,46 @@ public class DiagramController {
                 Map<String, Object> m = parser.parseContent(parser.toJson(s), Map.class);
                 diagram.setExtraProp("state", m.get("state"));
             });
-            Optional.ofNullable(map.get("lines")).ifPresent(lines ->
-                    diagram.setLines(parser.parseContent(parser.toJson(lines), List.class)));
-            Optional.ofNullable(map.get("nodes")).ifPresent(nodes -> {
-                diagram.setNodes(Arrays.asList(parser.parseContent(parser.toJson(nodes), DiagramNode[].class)));
-            });
+            buildLinesAndNodes(diagram, map);
         });
 
         return ResultHelper.single(dataStrategy.saveDiagram(diagram));
     }
 
     /**
+     * 构建lines modes 数据
+     *
+     * @param diagram 系统图对象
+     * @param map     输入参数集合
+     */
+    private void buildLinesAndNodes(Diagram diagram, Map<String, Object> map) {
+        Optional.ofNullable(map.get("lines")).ifPresent(lines ->
+                diagram.setLines(Arrays.asList(parser.parseContent(parser.toJson(lines), Line[].class))));
+        List<DiagramNode> nodes = new ArrayList<>();
+        Optional.ofNullable(map.get("template")).flatMap(template ->
+                Optional.ofNullable(parser.parseContent(parser.toJson(template), DiagramTemplate.class)))
+                .ifPresent(diagramTemplate -> {
+                    List<Container> containers = diagramTemplate.getContainers();
+                    if (CollectionUtil.isNotEmpty(containers)) {
+                        containers.forEach(container -> {
+                            if (container.isEquipmentBox()) {
+                                List<IComponent> children = container.getChildren();
+                                if (CollectionUtil.isNotEmpty(children)) {
+                                    children.forEach(iComponent -> {
+                                        if (StrUtil.equalsIgnoreCase(iComponent.getCompType(), EquipmentNode.TYPE)) {
+                                            DiagramNode node = parser.parseContent(parser.toJson(iComponent), DiagramNode.class);
+                                            nodes.add(node);
+                                        }
+                                    });
+                                }
+                            }
+                        });
+                    }
+                });
+        diagram.setNodes(nodes);
+    }
+
+    /**
      * 系统图删除功能
      *
      * @param diagramId 系统图id
@@ -229,4 +265,15 @@ public class DiagramController {
     public CommonResult<Boolean> updateState(@RequestBody Map<String, String> params) {
         return ResultHelper.single(dataStrategy.updateState(params.get("state"), params.get("id")));
     }
+
+    /**
+     * 查看系统实例是否有发布状态的系统图
+     *
+     * @return 是否成功
+     */
+    @ApiOperation("查看系统实例是否有发布状态的系统图")
+    @PostMapping("/system/instance/diagram/list")
+    public CommonResult<Map<String, Boolean>> querySystemInstanceDiagramList() {
+        return ResultHelper.single(dataStrategy.querySystemInstanceDiagramList());
+    }
 }

+ 148 - 5
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/DataStrategy.java

@@ -7,6 +7,7 @@ import com.persagy.adm.diagram.core.model.template.DiagramTemplate;
 import com.persagy.adm.diagram.entity.DiagramType;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * IO策略接口
@@ -17,51 +18,186 @@ public interface DataStrategy {
 
     String IMPL_QUALIFIER = "dataStrategyImpl";
 
+    /**
+     * 获取或有系统类型
+     *
+     * @return
+     */
     List<DiagramType> getDiagramTypes();
 
-    //模板
+    /**
+     * 获取所有模板
+     *
+     * @return 列表
+     */
     List<DiagramTemplate> getTemplates();
 
+    /**
+     * 根据系统图类型获取所有模板
+     *
+     * @param diagramType 系统图类型
+     * @return 列表
+     */
     List<DiagramTemplate> getTemplates(String diagramType);
 
+    /**
+     * 保存模板
+     *
+     * @param template 模板信息
+     * @return 列表
+     */
     DiagramTemplate saveTemplate(DiagramTemplate template);
 
+    /**
+     * 删除模板
+     *
+     * @param templateId 模板id
+     * @return
+     */
     boolean deleteTemplate(String templateId);
 
+    /**
+     * 根据模板id获取信息
+     *
+     * @param templateId 模板id
+     * @return 模板信息
+     */
     DiagramTemplate getTemplate(String templateId);
 
 
-    //图例
+    /**
+     * 根据系统code获取图例列表
+     *
+     * @param systemCode 系统code
+     * @return 图例列表
+     */
     List<Legend> getLegends(String systemCode);
 
+    /**
+     * 保存图例
+     *
+     * @param legend     图例信息
+     * @param systemCode 系统code
+     * @return 图例信息
+     */
     Legend saveLegend(Legend legend, String systemCode);
 
+    /**
+     * 删除图例
+     *
+     * @param legendId   图例id
+     * @param systemCode 系统code
+     * @return 是否成功
+     */
     boolean deleteLegend(String legendId, String systemCode);
 
+    /**
+     * 根据图例id 系统code 获取图例信息
+     *
+     * @param legendId   图例id
+     * @param systemCode 系统code
+     * @return 图例信息
+     */
     Legend getLegend(String legendId, String systemCode);
 
+    /**
+     * 根据设备类型获取图例信息
+     *
+     * @param equipmentType 设备类型
+     * @return
+     */
     List<Legend> getLegendsForEquipment(String equipmentType);
 
 
-    //系统图
+    /**
+     * 根据项目id 系统实例id 集团code 获取系统图列表
+     *
+     * @param projectId 项目id
+     * @param systemId  系统实例id
+     * @param groupCode 集团code
+     * @return 列表数据
+     */
     List<Diagram> getDiagrams(String projectId, String systemId, String groupCode);
 
-    List<Diagram> getDiagrams(String diagramType, String projectId, String systemId, String groupCode, String name); //按系统图类型查询
+    /**
+     * 按系统图类型查询
+     *
+     * @param diagramType 系统图类型
+     * @param projectId   项目id
+     * @param systemId    系统实例id
+     * @param groupCode   集团code
+     * @param name        名称
+     * @param flag        标识
+     * @return 列表数据
+     */
+    List<Diagram> getDiagrams(String diagramType, String projectId, String systemId,
+                              String groupCode, String name, Boolean flag);
 
+    /**
+     * 保存系统图
+     *
+     * @param diagram 系统图信息
+     * @return 系统图信息
+     */
     Diagram saveDiagram(Diagram diagram);
 
+    /**
+     * 删除系统图
+     *
+     * @param diagramId 系统图id
+     * @return 是否成功
+     */
     boolean deleteDiagram(String diagramId);
 
+    /**
+     * 根据系统id获取系统图信息
+     *
+     * @param diagramId 系统图id
+     * @return 系统图数据
+     */
     Diagram getDiagram(String diagramId);
 
 
-    //系统图数据
+    /**
+     * 系统图数据
+     *
+     * @param equipmentTypes 设备类型列表
+     * @param projectId      项目id
+     * @param systemId       系统实例id
+     * @param groupCode      集团code
+     * @return 列表数据
+     */
     List<ObjectNode> loadObjectsByType(List<String> equipmentTypes, String projectId, String systemId, String groupCode);
 
+    /**
+     * 根据关联类型、节点id列表、项目id 集团code获取信息
+     *
+     * @param relationTypes 关联类型列表
+     * @param objectIds     节点id列表
+     * @param projectId     项目id
+     * @param groupCode     集团code
+     * @return 列表数据
+     */
     List<ObjectNode> loadRelationsByType(List<String[]> relationTypes, List<String> objectIds, String projectId, String groupCode);
 
+    /**
+     * 根据节点id列表、项目id、集团code获取列表数据
+     *
+     * @param objectIds 节点id列表
+     * @param projectId 项目id
+     * @param groupCode 集团code
+     * @return 列表数据
+     */
     List<ObjectNode> loadObjectsById(List<String> objectIds, String projectId, String groupCode);
 
+    /**
+     * 根据关联id列表 项目id 集团code获取关联数据
+     *
+     * @param relationIds 关联关系id列表
+     * @param projectId   项目id
+     * @param groupCode   集团code
+     * @return 列表数据
+     */
     List<ObjectNode> loadRelationsById(List<String> relationIds, String projectId, String groupCode);
 
     /**
@@ -96,4 +232,11 @@ public interface DataStrategy {
      * @return
      */
     boolean updateState(String state, String id);
+
+    /**
+     * 获取系统实例下是否有系统图
+     *
+     * @return 例如: {"系统图实例id1":true,"系统图实例id2":false}
+     */
+    Map<String, Boolean> querySystemInstanceDiagramList();
 }

+ 28 - 53
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/DiagramBuilder.java

@@ -44,6 +44,11 @@ public class DiagramBuilder {
 	 */
 	private HashMap<String, Object> equipMap = new HashMap<>();
 
+	/**
+	 * 记录已经使用的关系id和对应的连线
+	 */
+	private HashMap<String, Line> lineMap = new HashMap<>();
+
 	public DiagramBuilder(Diagram diagram, DataStrategy dataStrategy) {
 		this.diagram = diagram;
 		this.template = diagram.getTemplate();
@@ -67,13 +72,15 @@ public class DiagramBuilder {
 				}
 			});
 		}
+
+		diagram.getLines().forEach(line -> {
+			if (StrUtil.isNotBlank(line.getDataObjectId())){
+				lineMap.put(line.getDataObjectId(), line);
+			}
+		});
 	}
 
-	/**
-	 * 加载设备数据,并进行计算处理
-	 * @param containers 容器列表
-	 * @param optionalObjs 节点列表
-	 */
+	//加载设备数据,并进行计算处理
 	public void buildEquipNodeAndContainer(List<Container> containers, List<ObjectNode> optionalObjs){
 		for(Container con : containers) {
 			if(con.isEquipmentBox()) {
@@ -307,21 +314,18 @@ public class DiagramBuilder {
 	
 	public void buildLines(List<ObjectNode> optionalRels){
 		for(ObjectNode rel : optionalRels) {
-			String from = rel.get(ObjectRelation.OBJ_FROM_HUM).asText();
-			String to = rel.get(ObjectRelation.OBJ_TO_HUM).asText();
-
-			Object fromObj = equipMap.get(from);
-			Object toObj = equipMap.get(to);
+			Object fromObj = equipMap.get(rel.get(ObjectRelation.OBJ_FROM_HUM).asText());
+			Object toObj = equipMap.get(rel.get(ObjectRelation.OBJ_TO_HUM).asText());
 
 			if(fromObj != null && toObj != null) {
 				String relType = rel.get(ObjectRelation.GRAPH_CODE_HUM).asText() + '/' + rel.get(ObjectRelation.REL_CODE_HUM).asText();
-				ConnectPoint p1 = getConnectPoint(fromObj, relType, toObj);
-				if(p1 != null) {
-					ConnectPoint p2 = getConnectPoint(toObj, relType, fromObj);
-					if(p2 != null) {
+				ConnectPoint from = getConnectPoint(fromObj, relType, toObj);
+				if(from != null) {
+					ConnectPoint to = getConnectPoint(toObj, relType, fromObj);
+					if(to != null) {
 						Line line = new Line();
-						line.setFrom(p1);
-						line.setTo(p2);
+						line.setFrom(from);
+						line.setTo(to);
 						line.setRelType(relType);
 						line.setDataObject(rel);
 
@@ -331,35 +335,6 @@ public class DiagramBuilder {
 			}
 		}
 
-		//test code TODO
-		EquipmentNode n1 = null;
-		EquipmentNode n2 = null;
-		for(Object o : equipMap.values()) {
-			if(o instanceof EquipmentNode){
-				String txt = ((EquipmentNode) o).getLabel().getContent();
-				if("1#进线柜".equals(txt)) {
-					n1 = (EquipmentNode) o;
-				} else if("1#计量柜".equals(txt)) {
-					n2 = (EquipmentNode) o;
-				}
-			}
-		}
-		if(n1 != null && n2 != null) {
-			ConnectPoint p1 = new ConnectPoint();
-			p1.setHostType(EquipmentNode.TYPE);
-			p1.setHostId(n1.getId());
-			p1.setAnchorCode("T3");
-			p1.setHostObj(n1);
-			ConnectPoint p2 = new ConnectPoint();
-			p2.setHostType(EquipmentNode.TYPE);
-			p2.setHostId(n2.getId());
-			p2.setAnchorCode("B3");
-			p2.setHostObj(n2);
-			Line line = new Line();
-			line.setFrom(p1);
-			line.setTo(p2);
-			addLine(line);
-		}
 	}
 
 	private ConnectPoint getConnectPoint(Object obj, String  relType, Object theOtherEnd){
@@ -376,13 +351,10 @@ public class DiagramBuilder {
 			Anchor anchor = null;
 			List<Anchor> anchors = en.getLegend().getAnchors();
 			if(CollUtil.isNotEmpty(anchors)) {
-				//部分匹配
-				Anchor anchor1 = null;
+				Anchor anchor1 = null; //部分匹配
 				for (Anchor a : anchors) {
-					//关系匹配
-					Boolean relMatch = null;
-					//另一端设备匹配
-					Boolean equipMatch = null;
+					Boolean relMatch = null; //关系匹配
+					Boolean equipMatch = null; //另一端设备匹配
 
 					if(CollUtil.isNotEmpty(a.getAcceptRelations())) {
 						relMatch = a.getAcceptRelations().contains(relType);
@@ -407,8 +379,7 @@ public class DiagramBuilder {
 							}
 						} else {
 							//完全匹配
-							//优先每个锚点只有一条连线
-							if(CollUtil.isEmpty(a.getLines())) {
+							if(CollUtil.isEmpty(a.getLines())) { //优先每个锚点只有一条连线
 								anchor = a;
 								break;
 							} else if(anchor == null) {
@@ -461,6 +432,10 @@ public class DiagramBuilder {
 		return equipMap;
 	}
 
+	public HashMap<String, Line> getLineMap() {
+		return lineMap;
+	}
+
 	public HashSet<String> getRefRelTypes() {
 		return refRelTypes;
 	}

+ 125 - 125
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/DiagramDataLoader.java

@@ -1,6 +1,5 @@
 package com.persagy.adm.diagram.core;
 
-import cn.hutool.core.collection.CollUtil;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.persagy.adm.diagram.core.model.Diagram;
 import com.persagy.adm.diagram.core.model.DiagramNode;
@@ -9,153 +8,154 @@ import com.persagy.adm.diagram.core.model.Line;
 import com.persagy.adm.diagram.core.model.base.Container;
 import com.persagy.adm.diagram.core.model.template.MainPipe;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
 import java.util.stream.Collectors;
 
 /**
  * 系统图数据加载
- *
  * @author zhaoyk
  */
 public class DiagramDataLoader {
 
-    private Diagram diagram;
-
-    private DataStrategy dataStrategy;
-
-    private List<ObjectNode> rels;
-
-    private List<ObjectNode> optionalObjs;
-
-    private List<ObjectNode> optionalRels;
-
-    public DiagramDataLoader(Diagram diagram, DataStrategy dataStrategy) {
-        this.diagram = diagram;
-        this.dataStrategy = dataStrategy;
-    }
-
-    /**
-     * 加载已经保存的数据
-     */
-    public void initLoad() {
-        List<String> objIds = diagram.getObjIds();
-        if (objIds.size() > 0) {
-            List<ObjectNode> objs = dataStrategy.loadObjectsById(objIds, diagram.getProjectId(), diagram.getGroupCode());
-            if (CollUtil.isNotEmpty(objs)) {
-                initNodes(objs);
-            } else {
-                throw new DiagramException("对象数据加载失败");
-            }
-        }
-
-        List<String> relIds = diagram.getRelIds();
-        if (relIds.size() > 0) {
-            List<ObjectNode> rels = dataStrategy.loadRelationsById(relIds, diagram.getProjectId(), diagram.getGroupCode());
-            if (CollUtil.isNotEmpty(rels)) {
-                initLines(rels);
-            } else {
-                throw new DiagramException("关系数据加载失败");
-            }
-        }
-    }
-
-    private void initNodes(List<ObjectNode> objs) {
-        HashMap<String, ObjectNode> objMap = new HashMap<>();
-        objs.forEach(obj -> objMap.put(obj.get("id").asText(), obj));
-
-        for (DiagramNode node : diagram.getNodes()) {
-            ObjectNode obj = null;
-            //设备节点
-            if (EquipmentNode.TYPE.equals(node.getCompType())) {
-                EquipmentNode en = (EquipmentNode) node;
-                obj = objMap.get(en.getObjId());
-
-                if (en.getLegendId() != null) {
-                    en.setLegend(dataStrategy.getLegend(en.getLegendId(), en.getObjSystemCode()));
-                } else {
-                    en.setLegend(DiagramBuilder.emptyLegend());
-                }
-            }
-
-            if (obj != null) {
-                node.setDataObject(obj);
-            }
-        }
-
-        //设备类干管
-        if (diagram.getTemplate().getMainPipes() != null) {
-            for (MainPipe mainPipe : diagram.getTemplate().getMainPipes()) {
-                if (mainPipe.isBindEquipment()) {
-                    ObjectNode obj = objMap.get(mainPipe.getDataObjectId());
-                    if (obj != null) {
-                        mainPipe.setDataObject(obj);
-                    }
-                }
-            }
-        }
-    }
-
-    private void initLines(List<ObjectNode> rels) {
-        HashMap<String, ObjectNode> relMap = new HashMap<>();
-        rels.forEach(obj -> relMap.put(obj.get("id").asText(), obj));
-
-        for (Line line : diagram.getLines()) {
-            if (line.getDataObjectId() != null) {
-                ObjectNode rel = relMap.get(line.getDataObjectId());
-                if (rel != null) {
+	private Diagram diagram;
+
+	private DataStrategy dataStrategy;
+
+	private List<ObjectNode> optionalObjs;
+
+	private List<ObjectNode> optionalRels;
+
+	public DiagramDataLoader(Diagram diagram, DataStrategy dataStrategy) {
+		this.diagram = diagram;
+		this.dataStrategy = dataStrategy;
+	}
+
+	/**
+	 * 加载已经保存的数据
+	 */
+	public void initLoad(){
+		List<String> objIds = diagram.getObjIds();
+		if(objIds.size() > 0) {
+			List<ObjectNode> objs = dataStrategy.loadObjectsById(objIds, diagram.getProjectId(), diagram.getGroupCode());
+			initNodes(objs);
+		}
+
+		List<String> relIds = diagram.getRelIds();
+		if(relIds.size() > 0) {
+			List<ObjectNode> rels = dataStrategy.loadRelationsById(relIds, diagram.getProjectId(), diagram.getGroupCode());
+			initLines(rels);
+		}
+	}
+
+	private void initNodes(List<ObjectNode> objs) {
+		HashMap<String, ObjectNode> objMap = new HashMap<>();
+		if(objs != null) {
+			objs.forEach(obj -> objMap.put(obj.get("id").asText(), obj));
+		}
+
+		for (DiagramNode node : diagram.getNodes()) {
+			ObjectNode obj = null;
+
+			if(EquipmentNode.TYPE.equals(node.getCompType())) { //设备节点
+				EquipmentNode en = (EquipmentNode) node;
+				obj = objMap.get(en.getObjId());
+
+				if(en.getLegendId() != null) {
+					en.setLegend(dataStrategy.getLegend(en.getLegendId(), en.getObjSystemCode())); //TODO 批量查询优化
+				} else {
+					en.setLegend(DiagramBuilder.emptyLegend());
+				}
+			}
+
+			if(obj != null) {
+				node.setDataObject(obj);
+			}
+		}
+
+		//设备类干管
+		if(diagram.getTemplate().getMainPipes() != null) {
+			for(MainPipe mainPipe : diagram.getTemplate().getMainPipes()) {
+				if(mainPipe.isBindEquipment()){
+					ObjectNode obj = objMap.get(mainPipe.getDataObjectId());
+					if(obj != null) {
+						mainPipe.setDataObject(obj);
+					}
+				}
+			}
+		}
+	}
+
+	private void initLines(List<ObjectNode> rels){
+		HashMap<String, ObjectNode> relMap = new HashMap<>();
+		if(rels != null) {
+			rels.forEach(obj -> relMap.put(obj.get("id").asText(), obj));
+		}
+
+		for(Line line : diagram.getLines()) {
+			if(line.getDataObjectId() != null){
+				ObjectNode rel = relMap.get(line.getDataObjectId());
+				if(rel != null) {
 					line.setDataObject(rel);
 				}
-            }
-        }
-    }
-
-    /**
-     * 搜索数据并自动加载
-     */
-    public void autoLoad(DiagramBuilder builder) {
-        //查询备选数据
-        HashSet<String> equipTypes = new HashSet<>();
-        List<Container> containers = diagram.getTemplate().getContainers();
-        for (Container con : containers) {
-            if (con.getEquipmentTypes() != null) {
-                equipTypes.addAll(con.getEquipmentTypes());
-            }
-        }
-        if (diagram.getTemplate().getMainPipes() != null) {
-            for (MainPipe mainPipe : diagram.getTemplate().getMainPipes()) {
-                //TODO 过滤已经初始化加载数据的干管
-                if (mainPipe.getEquipmentTypes() != null) {
-                    equipTypes.addAll(mainPipe.getEquipmentTypes());
-                }
-            }
-        }
-
-        //TODO 打包设备查询性能优化
-        if (equipTypes.size() > 0) {
+			}
+		}
+	}
+
+	/**
+	 * 搜索数据并自动加载
+	 */
+	public void autoLoad(DiagramBuilder builder) {
+		//查询备选数据
+		HashSet<String> equipTypes = new HashSet<>();
+		List<Container> containers = diagram.getTemplate().getContainers();
+		for(Container con : containers) {
+			if(con.getEquipmentTypes() != null) {
+				equipTypes.addAll(con.getEquipmentTypes());
+			}
+		}
+		if(diagram.getTemplate().getMainPipes() != null) {
+			for(MainPipe mainPipe : diagram.getTemplate().getMainPipes()) {
+				if(mainPipe.getEquipmentTypes() != null) { //TODO 过滤已经初始化加载数据的干管
+					equipTypes.addAll(mainPipe.getEquipmentTypes());
+				}
+			}
+		}
+
+		//TODO 打包设备查询性能优化
+		if(equipTypes.size() > 0) {
 			optionalObjs = dataStrategy.loadObjectsByType(new ArrayList<>(equipTypes), diagram.getProjectId(), diagram.getSystemId(), diagram.getGroupCode());
 		} else {
 			optionalObjs = new ArrayList<>();
 		}
-        //记录备选对象id列表
-        List<String> objIds = optionalObjs.stream().map(obj -> obj.get("id").asText()).collect(Collectors.toList());
+		//记录备选对象id列表
+		List<String> objIds = optionalObjs.stream().map(obj -> obj.get("id").asText()).collect(Collectors.toList());
 
-        //去掉已经使用的数据项
-        HashMap<String, Object> equipMap = builder.getEquipMap();
-        if (equipMap.size() > 0) {
+		//去掉已经使用的数据项
+		HashMap<String, Object> equipMap = builder.getEquipMap();
+		if(equipMap.size() > 0) {
 			optionalObjs = optionalObjs.stream().filter(obj -> !equipMap.containsKey(obj.get("id").asText())).collect(Collectors.toList());
 		}
 
-        builder.buildEquipNodeAndContainer(containers, optionalObjs);
-        List<String[]> relTypes = builder.getRefRelTypes().stream().map(type -> type.split("/")).collect(Collectors.toList());
+		builder.buildEquipNodeAndContainer(containers, optionalObjs);
+		List<String[]> relTypes = builder.getRefRelTypes().stream().map(type -> type.split("/")).collect(Collectors.toList());
 
-        //TODO 关系查询,需要区分打包设备
-        if (objIds.size() > 0 && relTypes.size() > 0) {
+		//TODO 关系查询,需要区分打包设备
+		if(objIds.size() > 0 && relTypes.size() > 0) {
 			optionalRels = dataStrategy.loadRelationsByType(relTypes, objIds, diagram.getProjectId(), diagram.getGroupCode());
 		} else {
 			optionalRels = new ArrayList<>();
 		}
 
-        builder.buildLines(optionalRels);
-    }
+		//去掉已经使用的关系项
+		HashMap<String, Line> lineMap = builder.getLineMap();
+		if(lineMap.size() > 0) {
+			optionalRels = optionalRels.stream().filter(obj -> !lineMap.containsKey(obj.get("id").asText())).collect(Collectors.toList());
+		}
+
+		builder.buildLines(optionalRels);
+	}
 
 }

+ 26 - 4
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/impl/DataStrategyImpl.java

@@ -41,6 +41,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -261,7 +262,8 @@ public class DataStrategyImpl implements DataStrategy {
      */
     @Override
     public List<Diagram> getDiagrams(String projectId, String systemId, String groupCode) {
-        List<DiagramEntity> diagrams = diagramMapper.getDiagrams(null, projectId, systemId, groupCode, null);
+        List<DiagramEntity> diagrams = diagramMapper.getDiagrams(null, projectId,
+                systemId, groupCode, null, true);
         if (CollectionUtil.isNotEmpty(diagrams)) {
             return diagrams.stream().map(diagramEntity ->
                     modelAdapter.toDiagram(diagramEntity)).collect(Collectors.toList());
@@ -281,7 +283,7 @@ public class DataStrategyImpl implements DataStrategy {
      */
     @Override
     public List<Diagram> getDiagrams(String diagramType, String projectId,
-                                     String systemId, String groupCode, String name) {
+                                     String systemId, String groupCode, String name,Boolean flag) {
 
         Set<DiagramEntity> result = new HashSet<>();
         //所有系统实例
@@ -303,7 +305,7 @@ public class DataStrategyImpl implements DataStrategy {
         }
         //直接去系统图表根据名称模糊查询查出来的数据
         List<DiagramEntity> diagrams = diagramMapper.getDiagrams(diagramType,
-                projectId, systemId, groupCode, name);
+                projectId, systemId, groupCode, name, flag);
         //合并
         result.addAll(diagrams);
 
@@ -338,7 +340,7 @@ public class DataStrategyImpl implements DataStrategy {
             }
         }
         diagram.setId(IdUtil.simpleUUID());
-        diagram.setExtraProp("state","Draft");
+        diagram.setExtraProp("state", "Draft");
         diagramMapper.saveDiagram(modelAdapter.toDiagramEntity(diagram));
         return diagram;
     }
@@ -665,4 +667,24 @@ public class DataStrategyImpl implements DataStrategy {
         diagramMapper.updateById(entity);
         return true;
     }
+
+    /**
+     * 获取系统实例下是否有系统图
+     *
+     * @return 例如: {"系统图实例id1":true,"系统图实例id2":false}
+     */
+    @Override
+    public Map<String, Boolean> querySystemInstanceDiagramList() {
+        BdtpRequest req = BdtpRequest.getCurrent();
+        String groupCode = req.getGroupCode();
+        String projectId = req.getProjectId();
+        HashMap<String, Boolean> result = new HashMap<>();
+        List<DiagramEntity> diagrams = diagramMapper.getDiagrams(null, projectId,
+                null, groupCode, null, false);
+        if (CollectionUtil.isNotEmpty(diagrams)) {
+            diagrams.stream().collect(Collectors.groupingBy(DiagramEntity::getSystemId))
+                    .forEach((s, diagramEntities) -> result.put(s, CollectionUtil.isNotEmpty(diagramEntities)));
+        }
+        return result;
+    }
 }

+ 14 - 4
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/line/Block.java

@@ -5,6 +5,10 @@ import com.persagy.adm.diagram.core.model.base.XY;
 import com.persagy.adm.diagram.core.util.GeomUtil;
 import org.locationtech.jts.geom.Polygon;
 
+/**
+ * 块区域
+ * @author zhaoyk
+ */
 public class Block {
 
 	private DiagramNode node;
@@ -13,13 +17,19 @@ public class Block {
 
 	private XY size;
 
-	private Polygon polygon;
+	private Polygon rect;
 
 	public Block(DiagramNode node) {
 		this.node = node;
 		this.location = node.locationToRoot();
 		this.size = node.getSize();
-		this.polygon = GeomUtil.getPolygon(location, size);
+		this.rect = GeomUtil.getRect(location, size);
+	}
+
+	public Block(XY location, XY size) {
+		this.location = location;
+		this.size = size;
+		this.rect = GeomUtil.getRect(location, size);
 	}
 
 	public XY getLocation() {
@@ -30,8 +40,8 @@ public class Block {
 		return size;
 	}
 
-	public Polygon getPolygon() {
-		return polygon;
+	public Polygon getRect() {
+		return rect;
 	}
 
 }

+ 44 - 1
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/line/LineEnd.java

@@ -4,13 +4,14 @@ import com.persagy.adm.diagram.core.model.base.XY;
 
 /**
  * 连线的终点
+ * @author zhaoyk
  */
 public class LineEnd {
 
 	/**
 	 * 与真正连接点的偏移量
 	 */
-	public static int offset = 5;
+	public static int offset = 8;
 
 	/**
 	 * 模式1,点(锚点)
@@ -38,4 +39,46 @@ public class LineEnd {
 		this.line = line;
 	}
 
+	public boolean isLineHorizontal(){
+		return isHorizontal(line);
+	}
+
+	public int getLineTrackPos(){
+		return isHorizontal(line) ? line[0].y : line[0].x;
+	}
+
+	public int getLineFromPos(){
+		return isHorizontal(line) ? line[0].x : line[0].y;
+	}
+
+	public int getLineToPos(){
+		return isHorizontal(line) ? line[1].x : line[1].y;
+	}
+
+	public int[] getLineScope(){
+		return isHorizontal(line) ? new int[]{line[0].x, line[1].x} : new int[]{line[0].y, line[1].y};
+	}
+
+	public static void orderLine(XY[] line) {
+		boolean needOrder = false;
+		if(isHorizontal(line)) {
+			if(line[0].x > line[1].x) {
+				needOrder = true;
+			}
+		} else {
+			if(line[0].y > line[1].y) {
+				needOrder = true;
+			}
+		}
+		if(needOrder) {
+			XY tmp = line[0];
+			line[0] = line[1];
+			line[1] = tmp;
+		}
+	}
+
+	public static boolean isHorizontal(XY[] line){
+		return line[0].y == line[1].y;
+	}
+
 }

+ 33 - 13
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/line/LineLayoutManager.java

@@ -7,6 +7,8 @@ import com.persagy.adm.diagram.core.model.EquipmentNode;
 import com.persagy.adm.diagram.core.model.Line;
 import com.persagy.adm.diagram.core.model.base.XY;
 import com.persagy.adm.diagram.core.model.template.MainPipe;
+import com.persagy.adm.diagram.core.util.GeomUtil;
+import org.locationtech.jts.geom.Point;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -14,7 +16,6 @@ import java.util.List;
 /**
  * 连线布局计算
  * @author zhaoyk
- * @date 2022-01-12
  */
 public class LineLayoutManager {
 
@@ -35,7 +36,7 @@ public class LineLayoutManager {
 		}
 	}
 
-	public void layout(Line line){
+	public List<XY> layout(Line line){
 		ConnectPoint p1 = line.getFrom();
 		ConnectPoint p2 = line.getTo();
 
@@ -54,7 +55,8 @@ public class LineLayoutManager {
 		}
 
 		LineEnd[] arr = buildLineEnd(p1, p2);
-
+		PathBuilder pb = new PathBuilder(line, arr[0], arr[1], exchange);
+		return pb.calcPath(blocks);
 	}
 
 	private LineEnd[] buildLineEnd(ConnectPoint p1, ConnectPoint p2) {
@@ -67,6 +69,7 @@ public class LineLayoutManager {
 			arr[1] = new LineEnd();
 			arr[1].setPoint(anchorEmerge(p2));
 		} else if (p2.getHostObj() instanceof MainPipe) {
+			Point point1 = GeomUtil.getPoint(p1.getLocation());
 			MainPipe mp = (MainPipe) p2.getHostObj();
 			XY[] nearLine = null;
 			double min = Double.MAX_VALUE;
@@ -74,8 +77,25 @@ public class LineLayoutManager {
 				XY pre = null;
 				for(XY xy : list) {
 					if(pre != null) {
-						XY[] line = new XY[]{pre, xy};
-						double distance = distance(line, p1.getLocation());
+						//复制坐标
+						XY[] line = new XY[]{pre.copy(), xy.copy()};
+						//起点终点排序
+						LineEnd.orderLine(line);
+
+						//线需要留头
+						if(LineEnd.isHorizontal(line)){
+							if(line[1].x - line[0].x > LineEnd.offset * 2){
+								line[0].x += LineEnd.offset;
+								line[1].x -= LineEnd.offset;
+							}
+						} else {
+							if(line[1].y - line[0].y > LineEnd.offset * 2){
+								line[0].y += LineEnd.offset;
+								line[1].y -= LineEnd.offset;
+							}
+						}
+						//计算点和线段的最短距离
+						double distance = point1.distance(GeomUtil.getLine(line));
 						if(distance < min){
 							min = distance;
 							nearLine = line;
@@ -92,14 +112,6 @@ public class LineLayoutManager {
 	}
 
 	/**
-	 * 就算点和线段的最短距离
-	 */
-	private double distance(XY[] line, XY xy){
-		//TODO
-		return 0;
-	}
-
-	/**
 	 * 锚点出线
 	 */
 	private XY anchorEmerge(ConnectPoint point){
@@ -126,4 +138,12 @@ public class LineLayoutManager {
 		return xy;
 	}
 
+	public List<Block> getBlocks() {
+		return blocks;
+	}
+
+	public DiagramBuilder getDiagramBuilder() {
+		return diagramBuilder;
+	}
+
 }

+ 590 - 0
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/line/PathBuilder.java

@@ -1,7 +1,597 @@
 package com.persagy.adm.diagram.core.line;
 
+import cn.hutool.core.util.ArrayUtil;
+import com.persagy.adm.diagram.core.model.Line;
+import com.persagy.adm.diagram.core.model.base.XY;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Collectors;
+
+/**
+ * 连线路径计算
+ *
+ * @author zhaoyk
+ */
 public class PathBuilder {
 
+    private static final int D_RIGHT = 1;
+
+    private static final int D_DOWN = 2;
+
+    private static final int D_LEFT = 3;
+
+    private static final int D_UP = 4;
+
+    private static int edge = 10;
+
+    private Line line;
+
+    private LineEnd end1;
+
+    private LineEnd end2;
+
+    private boolean exchange;
+
+    private List<XY> points = new ArrayList<>();
+
+    private XY currentPoint;
+
+    private int fromDirection;
+
+    private Random random = new Random();
+
+    public PathBuilder(Line line, LineEnd end1, LineEnd end2, boolean exchange) {
+        this.line = line;
+        this.end1 = end1;
+        this.end2 = end2;
+        this.exchange = exchange;
+
+        setCurrentPoint(end1.getPoint());
+        String fromAnchor = (!exchange ? line.getFrom() : line.getTo()).getAnchorCode();
+        switch (fromAnchor.charAt(0)) {
+            case 'T':
+                fromDirection = D_DOWN;
+                break;
+            case 'B':
+                fromDirection = D_UP;
+                break;
+            case 'L':
+                fromDirection = D_RIGHT;
+                break;
+            case 'R':
+                fromDirection = D_LEFT;
+                break;
+            default:
+        }
+    }
+
+    private void setCurrentPoint(XY point) {
+        currentPoint = point;
+        points.add(currentPoint);
+    }
+
+    public List<XY> calcPath(List<Block> blocks) {
+        findPath(blocks);
+
+        if (exchange) {
+            Collections.reverse(points);
+        }
+
+        if (line.getFrom().getLocation() != null) {
+            points.add(0, line.getFrom().getLocation());
+        }
+        if (line.getTo().getLocation() != null) {
+            points.add(line.getTo().getLocation());
+        }
+
+        return points;
+    }
+
+    private void findPath(List<Block> blocks) {
+        Block rectArea = buildRectArea();
+        List<Block> currentBlocks = blocks.stream().filter(block -> block.getRect().intersects(rectArea.getRect())).collect(Collectors.toList());
+
+        int[] directions = findDirection();
+
+        for (int direction : directions) {
+            if (direction == fromDirection) {
+                continue;
+            }
+
+            boolean vDirection = isVerticalDirection(direction);
+            int trackPos = vDirection ? currentPoint.x : currentPoint.y;
+            int pos = vDirection ? currentPoint.y : currentPoint.x;
+            boolean reverse = direction == D_LEFT || direction == D_UP;
+
+            List<BlockLine> blockLines = buildBlockLines(currentBlocks, direction);
+
+            int stopPos = -1;
+            for (BlockLine bl : blockLines) {
+                boolean valid = !reverse ? bl.base > pos : bl.base < pos;
+                if (valid && bl.begin <= trackPos && bl.end >= trackPos) {
+                    stopPos = bl.base;
+                    break;
+                }
+            }
+
+            if (stopPos != -1) {
+                int move = stopPos - pos;
+                //当前方向被阻挡
+                if (Math.abs(move) <= edge) {
+                    continue;
+                }
+            }
+
+            List<int[]> nonBlockRoads = getNonBlockRoads(blockLines, rectArea, vDirection);
+            int[] nbr = findNonBlockRoad(nonBlockRoads, trackPos);
+
+            if (nbr != null) {
+                //检查终点是否在同一个无阻挡通道中
+                if (checkEnd(nbr, vDirection)) {
+                    connectEnd(direction, nbr, vDirection);
+                    return;
+                }
+            }
+
+            //获取垂直参考方向
+            int crossDirection = 0;
+            for (int i = 0; i < directions.length; i++) {
+                if (isVerticalDirection(directions[i]) != vDirection) {
+                    crossDirection = directions[i];
+                    break;
+                }
+            }
+            boolean crossReverse = crossDirection == D_LEFT || crossDirection == D_UP;
+            List<BlockLine> crossBlockLines = buildBlockLines(currentBlocks, crossDirection);
+            List<int[]> crossNonBlockRoads = getNonBlockRoads(crossBlockLines, rectArea, !vDirection);
+
+            //位于垂直参考方向上的无阻挡通道中
+            int[] crossNbr = findNonBlockRoad(crossNonBlockRoads, pos);
+            if (crossNbr != null) {
+                if (checkEnd(crossNbr, !vDirection)) {
+                    connectEnd(crossDirection, crossNbr, !vDirection);
+                    return;
+                }
+            }
+
+            //折线直达
+            if (nbr != null) {
+                for (int[] crossRoad : crossNonBlockRoads) {
+                    boolean valid = !reverse ? crossRoad[0] > pos : crossRoad[1] < pos;
+                    if (valid && checkEnd(crossRoad, !vDirection)) {
+                        connectEnd(direction, crossRoad, !vDirection);
+                        return;
+                    }
+                }
+            }
+            if (crossNbr != null) {
+                for (int[] road : nonBlockRoads) {
+                    boolean valid = !crossReverse ? road[0] > pos : road[1] < pos;
+                    if (valid && checkEnd(road, vDirection)) {
+                        connectEnd(crossDirection, road, vDirection);
+                        return;
+                    }
+                }
+            }
+
+            //移动到垂直参考方向上的无阻挡通道位置
+            int targetPos = -1;
+            if (!reverse) {
+                for (int i = 0; i < crossNonBlockRoads.size(); i++) {
+                    int[] crossRoad = crossNonBlockRoads.get(i);
+                    if (crossRoad[0] > pos) {
+                        targetPos = crossRoad[0] + (crossRoad[1] - crossRoad[0]) / 2; //TODO 调整&避免重叠
+                        break;
+                    }
+                }
+            } else {
+                for (int i = crossNonBlockRoads.size() - 1; i >= 0; i--) {
+                    int[] crossRoad = crossNonBlockRoads.get(i);
+                    if (crossRoad[1] < pos) {
+                        targetPos = crossRoad[0] + (crossRoad[1] - crossRoad[0]) / 2; //TODO 调整&避免重叠
+                        break;
+                    }
+                }
+            }
+            //垂直参考方向方向上没有通道
+            if (targetPos == -1) {
+                if (stopPos != -1) {    // 移动到stopPos
+                    if (stopPos > pos) {
+                        targetPos = stopPos - edge;
+                    } else {
+                        targetPos = stopPos + edge;
+                    }
+                } else { //移动到垂直参考方向上blockLine变化的位置
+                    for (BlockLine crossBl : crossBlockLines) {
+                        boolean valid = !crossReverse ? crossBl.base > trackPos : crossBl.base < targetPos;
+                        if (valid && crossBl.begin <= pos && crossBl.end >= pos) {
+                            if (!reverse) {
+                                targetPos = crossBl.end;
+                            } else {
+                                targetPos = crossBl.begin;
+                            }
+                            break;
+                        }
+                    }
+                    //计算失败,尝试下一方向
+                    if (targetPos == -1) {
+                        continue;
+                    }
+                }
+            }
+            setCurrentPoint(vDirection ? new XY(trackPos, targetPos) : new XY(targetPos, trackPos));
+            fromDirection = direction > 2 ? direction - 2 : direction + 2; //取反向
+            findPath(blocks); //递归调用路径计算
+        }
+    }
+
+    private Block buildRectArea() {
+        int[] xs;
+        int[] ys;
+        if (end2.getPoint() != null) {
+            xs = new int[]{currentPoint.x, end2.getPoint().x};
+            ys = new int[]{currentPoint.y, end2.getPoint().y};
+        } else {
+            xs = new int[]{currentPoint.x, end2.getLine()[0].x, end2.getLine()[1].x};
+            ys = new int[]{currentPoint.y, end2.getLine()[0].y, end2.getLine()[1].y};
+        }
+
+        XY location = new XY(ArrayUtil.min(xs), ArrayUtil.min(ys));
+        location.x -= edge;
+        location.y -= edge;
+        XY size = new XY(ArrayUtil.max(xs) - location.x, ArrayUtil.max(ys) - location.y);
+        size.x += edge;
+        size.y += edge;
+
+        return new Block(location, size);
+    }
+
+    private int[] findDirection() {
+        int[] rtn = new int[4];
+
+        if (end2.getPoint() != null) {
+            XY endPoint = end2.getPoint();
+            if (endPoint.x == currentPoint.x) {
+                setDirection(rtn, null, endPoint.y > currentPoint.y);
+            } else if (endPoint.y == currentPoint.y) {
+                setDirection(rtn, endPoint.x > currentPoint.x, null);
+            } else {
+                setDirection(rtn, endPoint.x > currentPoint.x, endPoint.y > currentPoint.y);
+            }
+        } else {
+            int trackPos = end2.getLineTrackPos();
+            int[] scope = end2.getLineScope();
+            if (end2.isLineHorizontal()) {
+                boolean xMatch = scope[0] <= currentPoint.x && scope[1] >= currentPoint.x;
+                if (xMatch) {
+                    setDirection(rtn, null, trackPos > currentPoint.y);
+                } else if (trackPos == currentPoint.y) {
+                    //需要垂直交汇
+                    rtn[0] = D_DOWN;
+                    rtn[1] = D_UP;
+
+                    boolean right = scope[0] > currentPoint.x;
+                    rtn[2] = right ? D_RIGHT : D_LEFT;
+                    rtn[3] = right ? D_LEFT : D_RIGHT;
+                }
+            } else {
+                boolean yMatch = scope[0] <= currentPoint.y && scope[0] >= currentPoint.y;
+                if (yMatch) {
+                    setDirection(rtn, trackPos > currentPoint.x, null);
+                } else if (trackPos == currentPoint.x) {
+                    //需要垂直交汇
+                    rtn[0] = D_RIGHT;
+                    rtn[1] = D_LEFT;
+
+                    boolean down = scope[0] > currentPoint.y;
+                    rtn[2] = down ? D_DOWN : D_UP;
+                    rtn[3] = down ? D_UP : D_DOWN;
+                }
+            }
+            if (rtn[0] == 0) {
+                XY p0 = end2.getLine()[0];
+                setDirection(rtn, p0.x > currentPoint.x, p0.y > currentPoint.y);
+            }
+        }
+
+        return rtn;
+    }
+
+    private void setDirection(int[] directions, Boolean right, Boolean down) {
+        if (right != null && down != null) {
+            directions[0] = right ? D_RIGHT : D_LEFT;
+            directions[1] = down ? D_DOWN : D_UP;
+            directions[2] = right ? D_LEFT : D_RIGHT;
+            directions[3] = down ? D_UP : D_DOWN;
+        } else if (right != null) {
+            directions[0] = right ? D_RIGHT : D_LEFT;
+            directions[1] = D_DOWN;
+            directions[2] = D_UP;
+            directions[3] = right ? D_LEFT : D_RIGHT;
+        } else if (down != null) {
+            directions[0] = down ? D_DOWN : D_UP;
+            directions[1] = D_RIGHT;
+            directions[2] = D_LEFT;
+            directions[3] = down ? D_UP : D_DOWN;
+        }
+    }
+
+    private List<BlockLine> buildBlockLines(List<Block> currentBlocks, int direction) {
+        List<BlockLine> blockLines = new ArrayList<>();
+        for (Block block : currentBlocks) {
+            addBlockLine(block, direction, blockLines);
+        }
+
+        //合并相连的blockLine
+        Iterator<BlockLine> iter = blockLines.iterator();
+        BlockLine pre = null;
+        while (iter.hasNext()) {
+            BlockLine bl = iter.next();
+            if (pre != null) {
+                if (pre.end == bl.begin && pre.base == bl.base) {
+                    pre.end = bl.end;
+                    iter.remove();
+                    continue;
+                }
+            }
+            pre = bl;
+        }
+
+        return blockLines;
+    }
+
+    private void addBlockLine(Block block, int direction, List<BlockLine> blockLines) {
+        BlockLine toHandle = new BlockLine();
+        XY loc = block.getLocation();
+        XY size = block.getSize();
+        switch (direction) {
+            case D_UP:
+                if (currentPoint.y <= loc.y) {
+					return;
+				}
+                toHandle.base = loc.y + size.y;
+                toHandle.begin = loc.x;
+                toHandle.end = loc.x + size.x;
+                break;
+            case D_DOWN:
+                if (currentPoint.y >= loc.y + size.y) {
+					return;
+				}
+                toHandle.base = loc.y;
+                toHandle.begin = loc.x;
+                toHandle.end = loc.x + size.x;
+                break;
+            case D_LEFT:
+                if (currentPoint.x <= loc.x) {
+					return;
+				}
+                toHandle.base = loc.x + size.x;
+                toHandle.begin = loc.y;
+                toHandle.end = loc.y + size.y;
+                break;
+            case D_RIGHT:
+                if (currentPoint.x >= loc.x + size.x) {
+					return;
+				}
+                toHandle.base = loc.x;
+                toHandle.begin = loc.y;
+                toHandle.end = loc.y + size.y;
+                break;
+			default:
+        }
+
+        //使用toHandle的端点对blockLines中线段进行切分
+        int pos = toHandle.begin;
+        for (int i = 0; i < blockLines.size(); i++) {
+            BlockLine item = blockLines.get(i);
+            if (pos > item.begin && pos < item.end) {
+                blockLines.add(i + 1, new BlockLine(pos, item.end, item.base));
+                item.end = pos;
+
+                if (pos == toHandle.begin) {
+					pos = toHandle.end;
+				} else {
+					break;
+				}
+            }
+        }
+
+        //使用blockLines中线段端点对toHandle进行切分
+        LinkedList<BlockLine> nls = new LinkedList<>();
+        boolean finish = false;
+        for (BlockLine item : blockLines) {
+            int[] posArr = new int[]{item.begin, item.end};
+            for (int p : posArr) {
+                if (p > toHandle.begin && p < toHandle.end) {
+                    nls.add(new BlockLine(toHandle.begin, p, toHandle.base));
+                    toHandle.begin = p;
+                } else if (p > toHandle.end) {
+                    finish = true;
+                    break;
+                }
+            }
+
+            if (finish) {
+				break;
+			}
+        }
+        nls.add(toHandle);
+
+        //合并blockLines并设置base
+        for (int i = 0; i < blockLines.size(); i++) {
+            if (nls.size() == 0) {
+				break;
+			}
+
+            BlockLine item = blockLines.get(i);
+            BlockLine nl = nls.getFirst();
+            if (nl.begin < item.begin) { //插入
+                blockLines.add(i, nl);
+
+                nls.removeFirst();
+            } else if (nl.begin == item.begin) { //重合
+                item.base = (direction == D_UP || direction == D_LEFT) ? Math.max(nl.base, item.base) : Math.min(nl.base, item.base);
+
+                nls.removeFirst();
+            }
+        }
+        if (nls.size() > 0) {
+            blockLines.addAll(nls);
+        }
+    }
+
+    private List<int[]> getNonBlockRoads(List<BlockLine> blockLines, Block rectArea, boolean vDirection) {
+        int from, to;
+        if (vDirection) {
+            from = rectArea.getLocation().x;
+            to = rectArea.getLocation().x + rectArea.getSize().x;
+        } else {
+            from = rectArea.getLocation().y;
+            to = rectArea.getLocation().y + rectArea.getSize().y;
+        }
+
+        List<int[]> list = new ArrayList<>();
+        int tmp = from;
+        for (BlockLine bl : blockLines) {
+            if (tmp < bl.begin) {
+				list.add(new int[]{tmp, bl.begin});
+			}
+            tmp = bl.end;
+        }
+        if (tmp < to) {
+			list.add(new int[]{tmp, to});
+		}
+
+        return list;
+    }
+
+    private int[] findNonBlockRoad(List<int[]> nonBlockRoads, int pos) {
+        for (int[] road : nonBlockRoads) {
+            if (road[0] <= pos && road[1] >= pos) {
+                return road;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 检查终点是否在某个无阻挡通道上
+     */
+    private boolean checkEnd(int[] nonBlockRoad, boolean vDirection) {
+        if (end2.getPoint() != null) {
+            int pos = vDirection ? end2.getPoint().x : end2.getPoint().y;
+            return nonBlockRoad[0] <= pos && nonBlockRoad[1] >= pos;
+        } else {
+            boolean hLine = end2.isLineHorizontal();
+            if (hLine == vDirection) { //垂直
+                int[] scope = end2.getLineScope();
+                boolean notJoin = scope[0] > nonBlockRoad[1] || nonBlockRoad[0] > scope[1];
+                return !notJoin;
+            } else { //平行
+                int trackPos = end2.getLineTrackPos();
+                return nonBlockRoad[0] <= trackPos && nonBlockRoad[1] >= trackPos;
+            }
+        }
+    }
+
+    private void connectEnd(int direction, int[] endNbr, boolean vEndNbr) {
+        boolean vDirection = isVerticalDirection(direction);
+        if (end2.getPoint() != null) {
+            XY endPoint = end2.getPoint();
+            if (currentPoint.x != endPoint.x && currentPoint.y != endPoint.y) {
+                moveTo(vDirection ? endPoint.y : endPoint.x, vDirection);
+            }
+            points.add(endPoint);
+        } else {
+            //XY[] line = end2.getLine();
+            boolean hLine = end2.isLineHorizontal();
+            int lineTrackPos = end2.getLineTrackPos();
+            int[] lineScope = end2.getLineScope();
+
+            if (vDirection == vEndNbr) { //当前方向与终点通道方向相同
+                if (vEndNbr == hLine) { //垂直相交
+                    moveTo(lineTrackPos, hLine); //线横向时做纵向移动
+                } else {
+                    //TODO 平行连接
+                }
+            } else { //当前方向与终点通道方向垂直,折线连接
+                if (vEndNbr == hLine) { //endLine与通道垂直
+                    int[] targetScope = new int[]{Math.max(lineScope[0], endNbr[0]), Math.min(lineScope[1], endNbr[1])};
+                    int safeOffset = 5;//临时避免和节点边线重合
+                    int target0 = targetScope[0] + safeOffset + random.nextInt(targetScope[1] - targetScope[0] - safeOffset * 2); //TODO 调整&避免重叠
+                    moveTo(target0, vDirection);
+                    moveTo(lineTrackPos, hLine);
+                } else { //endLine与通道平行
+                    //TODO 调整&避免重叠
+                    int target0;
+                    if (endNbr[1] - lineTrackPos > lineTrackPos - endNbr[0]) {
+                        target0 = lineTrackPos + LineEnd.offset;
+                    } else {
+                        target0 = lineTrackPos - LineEnd.offset;
+                    }
+                    if (target0 > endNbr[1]) {
+                        target0 = endNbr[1];
+                    } else if (target0 < endNbr[0]) {
+                        target0 = endNbr[0];
+                    }
+                    XY point0 = moveTo(target0, vDirection);
+
+                    int target1 = hLine ? point0.x : point0.y;
+                    int offset = random.nextInt((lineScope[1] - lineScope[0]) / 2);
+                    if (Math.abs(lineScope[0] - target1) < Math.abs((lineScope[1] - target1))) {
+                        target1 = lineScope[0] + offset;
+                    } else {
+                        target1 = lineScope[1] - offset;
+                    }
+                    moveTo(target1, !vDirection);
+
+                    moveTo(lineTrackPos, vDirection);
+                }
+            }
+        }
+    }
+
+    private XY moveTo(int targetPos, boolean vDirection) {
+        XY point = new XY(currentPoint);
+        if (vDirection) {
+			point.y = targetPos;
+		} else {
+			point.x = targetPos;
+		}
+
+        //TODO 连线检查,处理重叠等
+
+        setCurrentPoint(point);
+        return point;
+    }
+
+    private boolean isVerticalDirection(int direction) {
+        return direction == D_DOWN || direction == D_UP;
+    }
+
+    class BlockLine {
+
+        BlockLine() {
+
+        }
+
+        BlockLine(int begin, int end, int base) {
+            this.begin = begin;
+            this.end = end;
+            this.base = base;
+        }
+
+        int begin;
+
+        int end;
+
+        int base;
 
+    }
 
 }

+ 1 - 0
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/model/ConnectPoint.java

@@ -40,6 +40,7 @@ public class ConnectPoint {
 	/**
 	 * 连接点绝对坐标
 	 */
+	@JsonIgnore
 	private XY location;
 
 	/**

+ 1 - 10
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/model/Diagram.java

@@ -8,7 +8,6 @@ import com.persagy.adm.diagram.core.model.base.Container;
 import com.persagy.adm.diagram.core.model.base.XY;
 import com.persagy.adm.diagram.core.model.template.DiagramTemplate;
 import com.persagy.adm.diagram.core.model.template.MainPipe;
-import com.persagy.dmp.common.lang.PsDateTime;
 
 import java.util.*;
 
@@ -87,8 +86,8 @@ public class Diagram {
 	@Expose
 	private List<Line> lines = new ArrayList();
 
-	private PsDateTime createTime;
 	//运行时
+	@Expose(serialize = false)
 	private DiagramTemplate template;
 
 
@@ -275,14 +274,6 @@ public class Diagram {
 		}
 	}
 
-	public PsDateTime getCreateTime() {
-		return createTime;
-	}
-
-	public void setCreateTime(PsDateTime createTime) {
-		this.createTime = createTime;
-	}
-
 	public DiagramTemplate getTemplate() {
 		return template;
 	}

+ 5 - 11
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/model/Line.java

@@ -1,11 +1,9 @@
 package com.persagy.adm.diagram.core.model;
 
 import com.google.gson.annotations.Expose;
-import com.persagy.adm.diagram.core.DiagramBuilder;
 import com.persagy.adm.diagram.core.line.LineLayoutManager;
 import com.persagy.adm.diagram.core.model.base.XY;
 
-import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -14,8 +12,11 @@ import java.util.List;
  */
 public class Line extends AbstractLine {
 
+	/**
+	 * 连线的方向(1:from->to, 0:无方向, -1:to->from)
+	 */
 	@Expose
-	private int direction; //连线的方向(1:from->to, 0:无方向, -1:to->from)
+	private int direction;
 
 	/**
 	 * 起点
@@ -55,14 +56,7 @@ public class Line extends AbstractLine {
 	@Override
 	public void layout(Object layoutContext) {
 		LineLayoutManager layoutManager = (LineLayoutManager) layoutContext;
-		layoutManager.layout(this);
-
-		//test code TODO
-		locationPath = new ArrayList<>();
-		if(from.getLocation() != null && to.getLocation() != null) {
-			locationPath.add(from.getLocation());
-			locationPath.add(to.getLocation());
-		}
+		locationPath = layoutManager.layout(this);
 	}
 
 	public int getDirection() {

+ 4 - 0
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/model/base/XY.java

@@ -24,4 +24,8 @@ public class XY {
 		this.y = xy.y;
 	}
 
+	public XY copy() {
+		return new XY(x, y);
+	}
+
 }

+ 11 - 187
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/core/util/GeomUtil.java

@@ -1,23 +1,17 @@
 package com.persagy.adm.diagram.core.util;
 
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.map.CaseInsensitiveMap;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.persagy.adm.diagram.core.model.base.XY;
 import org.locationtech.jts.geom.*;
-import org.locationtech.jts.io.ParseException;
-import org.locationtech.jts.io.WKTReader;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
 
+/**
+ * 几何计算工具类
+ * @author zhaoyk
+ */
 public class GeomUtil {
 
 	private static GeometryFactory geometryFactory = new GeometryFactory();
 
-	public static Polygon getPolygon(XY location, XY size) {
+	public static Polygon getRect(XY location, XY size) {
 		Coordinate[] cs = new Coordinate[5];
 		cs[0] = new Coordinate(location.x, location.y);
 		cs[1] = new Coordinate(location.x + size.x, location.y);
@@ -35,185 +29,15 @@ public class GeomUtil {
 		return geometryFactory.createLineString(cs);
 	}
 
-	public Point getPoint(XY xy){
+	public static Point getPoint(XY xy){
 		return geometryFactory.createPoint(new Coordinate(xy.x, xy.y));
 	}
 
-	public static Polygon[] getPolygon(ArrayNode arrayNode){
-		Polygon[] ps = new Polygon[arrayNode.size()];
-		for (int i = 0; i < ps.length; i++) {
-			ArrayNode arr = (ArrayNode) arrayNode.get(i);
-			ArrayNode shellArrNode = (ArrayNode) arr.get(0);
-			LinearRing shell = geometryFactory.createLinearRing(buildCoords(shellArrNode));
-			LinearRing[] holes = null;
-			if(arr.size() > 1) {
-				holes = new LinearRing[arr.size() - 1];
-				for (int n = 1; n < arr.size(); n++) {
-					holes[n - 1] = geometryFactory.createLinearRing(buildCoords((ArrayNode) arr.get(n)));
-				}
-			}
-			ps[i] = geometryFactory.createPolygon(shell, holes);
-		}
-		return ps;
-	}
-
-	private static Coordinate[] buildCoords(ArrayNode arrayNode){
-		Coordinate[] coords = new Coordinate[arrayNode.size()];
-		for (int i = 0; i < arrayNode.size(); i++) {
-			JsonNode pointNode = arrayNode.get(i);
-			coords[i] = new Coordinate(pointNode.get("x").asDouble(), pointNode.get("y").asDouble());
-		}
-		return coords;
-	}
-
-	public static boolean checkPolygon(ArrayList<ArrayList<ArrayList<CaseInsensitiveMap>>> outline){
-		if(CollUtil.isEmpty(outline)) {
-			return false;
-		}
-
-		try {
-			Polygon[] ps = new Polygon[outline.size()];
-			for (int i = 0; i < ps.length; i++) {
-				List space = (List) outline.get(i);
-				if(CollUtil.isEmpty(space)) {
-					return false;
-				}
-
-				List<Map> shellList = (List) space.get(0);
-				LinearRing shell = geometryFactory.createLinearRing(buildCoords(shellList));
-				LinearRing[] holes = null;
-				if(space.size() > 1) {
-					holes = new LinearRing[space.size() - 1];
-					for (int n = 1; n < space.size(); n++) {
-						holes[n - 1] = geometryFactory.createLinearRing(buildCoords((List<Map>) space.get(n)));
-					}
-				}
-				ps[i] = geometryFactory.createPolygon(shell, holes);
-			}
-		} catch (Exception e) {
-			return false;
-		}
-		return true;
-	}
-
-	private static Coordinate[] buildCoords(List<Map> list){
-		Coordinate[] coords = new Coordinate[list.size()];
-		for (int i = 0; i < list.size(); i++) {
-			Map point = list.get(i);
-			coords[i] = new Coordinate((Double) point.get("x"), (Double)point.get("y"));
-		}
-		return coords;
-	}
-
-	public static boolean checkPolygon(ArrayNode outline){
-		if(outline == null || outline.size() == 0) {
-			return false;
-		}
-
-		try {
-			Polygon[] ps = new Polygon[outline.size()];
-			for (int i = 0; i < ps.length; i++) {
-				ArrayNode space = (ArrayNode) outline.get(i);
-				if(space == null || space.size() == 0) {
-					return false;
-				}
-
-				ArrayNode shellList = (ArrayNode) space.get(0);
-				LinearRing shell = geometryFactory.createLinearRing(buildCoords(shellList));
-				LinearRing[] holes = null;
-				if(space.size() > 1) {
-					holes = new LinearRing[space.size() - 1];
-					for (int n = 1; n < space.size(); n++) {
-						holes[n - 1] = geometryFactory.createLinearRing(buildCoords((ArrayNode) space.get(n)));
-					}
-				}
-				ps[i] = geometryFactory.createPolygon(shell, holes);
-			}
-		} catch (Exception e) {
-			return false;
-		}
-		return true;
-	}
-
-
-	/**
-	 *  两个几何对象是否是重叠的
-	 * @return
-	 * @throws ParseException
-	 */
-	public boolean equalsGeo() throws ParseException {
-		WKTReader reader = new WKTReader( geometryFactory );
-		LineString geometry1 = (LineString) reader.read("LINESTRING(0 0, 2 0, 5 0)");
-		LineString geometry2 = (LineString) reader.read("LINESTRING(5 0, 0 0)");
-		//true
-		return geometry1.equals(geometry2);
-	}
-
-	/**
-	 * 几何对象没有交点(相邻)
-	 * @return
-	 * @throws ParseException
-	 */
-	public boolean disjointGeo() throws ParseException{
-		WKTReader reader = new WKTReader( geometryFactory );
-		LineString geometry1 = (LineString) reader.read("LINESTRING(0 0, 2 0, 5 0)");
-		LineString geometry2 = (LineString) reader.read("LINESTRING(0 1, 0 2)");
-		return geometry1.disjoint(geometry2);
-	}
-
-	/**
-	 * 至少一个公共点(相交)
-	 * @return
-	 * @throws ParseException
-	 */
-	public boolean intersectsGeo() throws ParseException{
-		WKTReader reader = new WKTReader( geometryFactory );
-		LineString geometry1 = (LineString) reader.read("LINESTRING(0 0, 2 0, 5 0)");
-		LineString geometry2 = (LineString) reader.read("LINESTRING(0 0, 0 2)");
-		Geometry interPoint = geometry1.intersection(geometry2);//相交点
-		System.out.println(interPoint.toText());//输出 POINT (0 0)
-		return geometry1.intersects(geometry2);
-	}
-
-	/**
-	 * 判断以x,y为坐标的点point(x,y)是否在geometry表示的Polygon中
-	 * @param x
-	 * @param y
-	 * @param geometry wkt格式
-	 * @return
-	 */
-	public boolean withinGeo(double x,double y,String geometry) throws ParseException {
-
-		Coordinate coord = new Coordinate(x,y);
-		Point point = geometryFactory.createPoint( coord );
-
-		WKTReader reader = new WKTReader( geometryFactory );
-		Polygon polygon = (Polygon) reader.read(geometry);
-		return point.within(polygon);
-	}
-
-	public LinearRing createLinearRing(double[]... xys){
-		Coordinate[] coords = new Coordinate[xys.length];
-		for(int i=0;i<xys.length;i++){
-			coords[i] = new Coordinate(xys[i][0], xys[i][1]);
-		}
-		return geometryFactory.createLinearRing(coords);
-	}
-
-	public Polygon createPolygon(double[]... xys){
-		Coordinate[] coords = new Coordinate[xys.length];
-		for(int i=0;i<xys.length;i++){
-			coords[i] = new Coordinate(xys[i][0], xys[i][1]);
-		}
-		return geometryFactory.createPolygon(coords);
-	}
-
-	public LineString createLine(double[]... xys){
-		Coordinate[] coords = new Coordinate[xys.length];
-		for(int i=0;i<xys.length;i++){
-			coords[i] = new Coordinate(xys[i][0], xys[i][1]);
-		}
-		return geometryFactory.createLineString(coords);
+	public static void main(String[] args) {
+		Point p1 = getPoint(new XY(1, 1));
+		LineString line = getLine(new XY[]{new XY(2, 0), new XY(2, 4)});
+		double d = p1.distance(line);
+		System.out.println(d);
 	}
 
 }

+ 36 - 3
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/dao/DiagramMapper.java

@@ -15,20 +15,53 @@ import java.util.List;
 public interface DiagramMapper extends BaseMapper<DiagramEntity> {
 
 
-    //按系统图类型查询
+    /**
+     * 按系统图类型查询
+     *
+     * @param diagramType 系统图类型
+     * @param projectId   项目id
+     * @param systemId    系统实例id
+     * @param groupCode   集团code
+     * @param name        名称
+     * @param flag        根据标识查出特定数据(true:查出所有数据,false:只查发布状态数据)
+     * @return 系统图列表
+     */
     List<DiagramEntity> getDiagrams(@Param("diagramType") String diagramType,
                                     @Param("projectId") String projectId,
                                     @Param("systemId") String systemId,
                                     @Param("groupCode") String groupCode,
-                                    @Param("name") String name);
+                                    @Param("name") String name,
+                                    @Param("flag") Boolean flag);
 
-    //按系统图类型查询
+    /**
+     * 根据系统实例id进行查询
+     *
+     * @param ids 系统实例id列表
+     * @return 系统图列表
+     */
     List<DiagramEntity> getDiagramsBySystemIds(@Param("systemIds") List<String> ids);
 
+    /**
+     * 系统图保存
+     *
+     * @param diagramEntity 系统图信息
+     */
     void saveDiagram(DiagramEntity diagramEntity);
 
+    /**
+     * 删除系统图
+     *
+     * @param diagramId 系统图id
+     * @return 是否成功
+     */
     boolean deleteByDiagramId(String diagramId);
 
+    /**
+     * 获取系统图信息
+     *
+     * @param diagramId 系统图id
+     * @return 系统图信息
+     */
     DiagramEntity getDiagram(String diagramId);
 
 }

+ 27 - 19
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/demo/DemoDataStrategy.java

@@ -4,12 +4,12 @@ import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.StrUtil;
 import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.persagy.adm.diagram.entity.DiagramType;
 import com.persagy.adm.diagram.core.ContentParser;
 import com.persagy.adm.diagram.core.DataStrategy;
 import com.persagy.adm.diagram.core.model.Diagram;
 import com.persagy.adm.diagram.core.model.legend.Legend;
 import com.persagy.adm.diagram.core.model.template.DiagramTemplate;
+import com.persagy.adm.diagram.entity.DiagramType;
 import com.persagy.adm.diagram.frame.BdtpRequest;
 import com.persagy.adm.diagram.service.BdtpDataService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -20,6 +20,7 @@ import java.io.File;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 测试开发使用的io策略实现类
@@ -207,8 +208,8 @@ public class DemoDataStrategy implements DataStrategy {
     public List<Legend> getLegends(String systemCode) {
         File file = new File(DIR_LEGEND, systemCode + ".json");
         if (!file.exists()) {
-			FileUtil.writeUtf8String("[]", file);
-		}
+            FileUtil.writeUtf8String("[]", file);
+        }
 
         Legend[] legends = parser.parseContent(FileUtil.readUtf8String(file), Legend[].class);
         ArrayList<Legend> list = new ArrayList<>();
@@ -264,8 +265,8 @@ public class DemoDataStrategy implements DataStrategy {
         List<Legend> list = getLegends(systemCode);
         for (Legend legend : list) {
             if (legend.getId().equals(legendId)) {
-				return legend;
-			}
+                return legend;
+            }
         }
         return null;
     }
@@ -278,24 +279,26 @@ public class DemoDataStrategy implements DataStrategy {
         List<Legend> list = getLegends(systemCode);
         for (Legend legend : list) {
             if (legend.getEquipmentTypes() != null && legend.getEquipmentTypes().contains(equipmentType)) {
-				rtn.add(legend);
-			}
+                rtn.add(legend);
+            }
         }
 
         return rtn;
     }
 
 
-    /** 系统图部分 */
+    /**
+     * 系统图部分
+     */
     private static final String DIR_DIAGRAM = "store/diagram/";
 
     @Override
     public List<Diagram> getDiagrams(String projectId, String systemId, String groupCode) {
-        return getDiagrams(null, projectId, systemId, groupCode, null);
+        return getDiagrams(null, projectId, systemId, groupCode, null, null);
     }
 
     @Override
-    public List<Diagram> getDiagrams(String diagramType, String projectId, String systemId, String groupCode, String name) {
+    public List<Diagram> getDiagrams(String diagramType, String projectId, String systemId, String groupCode, String name, Boolean flag) {
         ArrayList<Diagram> diagrams = new ArrayList<>();
 
         File dir = new File(DIR_DIAGRAM);
@@ -305,14 +308,14 @@ public class DemoDataStrategy implements DataStrategy {
                 Diagram diagram = parser.parseContent(FileUtil.readUtf8String(f), Diagram.class);
                 if (projectId.equals(diagram.getProjectId())) {
                     if (StrUtil.isNotBlank(groupCode) && !groupCode.equals(diagram.getGroupCode())) {
-						continue;
-					}
+                        continue;
+                    }
                     if (StrUtil.isNotBlank(diagramType) && !diagramType.equals(diagram.getType())) {
-						continue;
-					}
+                        continue;
+                    }
                     if (StrUtil.isNotBlank(systemId) && !systemId.equals(diagram.getSystemId())) {
-						continue;
-					}
+                        continue;
+                    }
 
                     diagrams.add(diagram);
                 }
@@ -351,8 +354,8 @@ public class DemoDataStrategy implements DataStrategy {
     public Diagram getDiagram(String diagramId) {
         File file = new File(DIR_DIAGRAM, diagramId + ".json");
         if (file.exists()) {
-			return parser.parseContent(FileUtil.readUtf8String(file), Diagram.class);
-		}
+            return parser.parseContent(FileUtil.readUtf8String(file), Diagram.class);
+        }
         return null;
     }
 
@@ -406,8 +409,13 @@ public class DemoDataStrategy implements DataStrategy {
         return null;
     }
 
-    // @Override
+    @Override
     public boolean updateState(String state, String id) {
         return false;
     }
+
+    @Override
+    public Map<String, Boolean> querySystemInstanceDiagramList() {
+        return null;
+    }
 }

+ 1 - 1
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/entity/ModelAdapter.java

@@ -71,7 +71,7 @@ public class ModelAdapter {
         diagram.setProjectId(diagramEntity.getProjectId());
         diagram.setSystemId(diagramEntity.getSystemId());
         diagram.setGroupCode(diagramEntity.getGroupCode());
-        diagram.setCreateTime(diagramEntity.getCreationTime());
+        diagram.setExtraProp("createTime", diagramEntity.getCreationTime());
         diagram.setExtraProp("state", diagramEntity.getState());
         return diagram;
     }

+ 4 - 0
adm-business/adm-diagram/src/main/java/com/persagy/adm/diagram/manage/DemoDiagramManager.java

@@ -124,6 +124,10 @@ public class DemoDiagramManager {
 		Diagram diagram = dataStrategy.getDiagram(diagramId);
 		diagram.setTemplateId(templateId);
 
+		//重设模板时,清空节点和连线
+		diagram.getNodes().clear();
+		diagram.getLines().clear();
+
 		dataStrategy.saveDiagram(diagram);
 		buildDiagram(diagram, true);
 

+ 3 - 0
adm-business/adm-diagram/src/main/resources/mapper/Diagram.xml

@@ -70,6 +70,9 @@
         <if test="null != name and name.length > 0">
             AND name LIKE CONCAT('%',#{name},'%')
         </if>
+        <if test="null != flag and (flag == false) ">
+            AND state = 'Publish'
+        </if>
     </select>
 
     <select id="getDiagramsBySystemIds" resultMap="diagramBaseMap">

+ 23 - 0
adm-business/adm-middleware/src/main/java/com/persagy/proxy/common/client/DmpRwdClient.java

@@ -214,4 +214,27 @@ public interface DmpRwdClient {
     @PostMapping(DmpUrlConstant.QUERY_OBJECT_CLASS_CODE)
     DmpResult<List<String>> queryObjectClassCode(@SpringQueryMap InstanceUrlParam objectUrlParam, @RequestBody JSONObject criteria);
 
+
+    /**
+     * @description: 查询交付类型
+     * @param: objectUrlParam 对象请求url通用参数
+     * @param: criteria post请求参数
+     * @return: com.persagy.dmp.common.DmpResult
+     */
+    @PostMapping(DmpUrlConstant.DEF_CLASS_COLLECT)
+    DmpResult<JSONArray> queryObjectClassCollect(@SpringQueryMap InstanceUrlParam objectUrlParam, @RequestBody JSONObject criteria);
+
+
+
+
+    /**
+     * @description: 查询交付关系
+     * @param: objectUrlParam 对象请求url通用参数
+     * @param: criteria post请求参数
+     * @return: com.persagy.dmp.common.DmpResult
+     */
+    @PostMapping(DmpUrlConstant.DEF_REL_COLLECT)
+    DmpResult<JSONArray> queryObjectRelCollect(@SpringQueryMap InstanceUrlParam objectUrlParam, @RequestBody JSONObject criteria);
+
+
 }

+ 11 - 0
adm-business/adm-middleware/src/main/java/com/persagy/proxy/common/constant/DmpUrlConstant.java

@@ -164,4 +164,15 @@ public class DmpUrlConstant {
      */
     public static final String QUERY_OBJECT_CLASS_CODE = "/rwd/instance/object/queryObjectClassCode";
 
+
+    /**
+     * 查询采集信息 类型
+     */
+    public final static String DEF_CLASS_COLLECT = "/rwd/def/class/collect/query";
+
+    /**
+     * 查询采集信息 关系
+     */
+    public final static String DEF_REL_COLLECT = "/rwd/def/rel/collect/query";
+
 }

+ 1 - 1
adm-business/adm-middleware/src/main/java/com/persagy/proxy/dictionary/controller/AdmDictController.java

@@ -269,7 +269,7 @@ public class AdmDictController {
         }
         Map<String, Set<String>> classCodeMap = classCodes.stream().collect(Collectors.groupingBy(item->item.substring(0,4),Collectors.toSet()));
         //查询系统设备类树
-        AdmDict admDict = new AdmDict(AdmDictCategoryEnum.SYSTEM_EQUIP.getValue());
+        AdmDict admDict = new AdmDict(AdmDictCategoryEnum.SYSTEM_EQUIP.getValue(), null);
         AdmResponse categoryResponse = service.queryCategory(context, admDict, clazz);
         List<AdmObjectType> objectTypes = (List<AdmObjectType>) categoryResponse.getContent();
         if(CollUtil.isEmpty(objectTypes)){

+ 2 - 0
adm-business/adm-middleware/src/main/java/com/persagy/proxy/dictionary/model/AdmDict.java

@@ -19,4 +19,6 @@ import lombok.NoArgsConstructor;
 public class AdmDict {
 
   private String type;
+  /** 交付内类型:0 项目交付(web),1 现场交付(app) **/
+  private Integer deliveryType;
 }

+ 5 - 0
adm-business/adm-middleware/src/main/java/com/persagy/proxy/dictionary/model/AdmObjectType.java

@@ -61,4 +61,9 @@ public class AdmObjectType {
 
     /** 更新时间 */
     private String lastUpdate;
+
+    /** 交付类型:0-项目交付 1-现场交付  */
+    private Integer deliveryType = -1;
+    /** 是否交付 0-否 1-是 */
+    private Integer isDelivery = -1;
 }

+ 5 - 0
adm-business/adm-middleware/src/main/java/com/persagy/proxy/dictionary/service/IAdmDictBaseService.java

@@ -1,9 +1,11 @@
 package com.persagy.proxy.dictionary.service;
 
 import com.persagy.dmp.basic.model.QueryCriteria;
+import com.persagy.dmp.delivery.entity.ObjectTypeCollect;
 import com.persagy.proxy.adm.request.AdmQueryCriteria;
 import com.persagy.proxy.adm.request.AdmResponse;
 import com.persagy.proxy.common.entity.InstanceUrlParam;
+import com.persagy.proxy.dictionary.model.AdmObjectType;
 
 import java.util.List;
 
@@ -71,6 +73,8 @@ public interface IAdmDictBaseService<T>{
      */
     AdmResponse doQueryObjectInfoCollect(InstanceUrlParam context, AdmQueryCriteria request, String fieldName, Class<T> clazz);
 
+    AdmResponse doQueryObjectTypeCollect(InstanceUrlParam context, QueryCriteria queryCriteria);
+
     /**
      * 设置采集信息点
      * @param context
@@ -79,6 +83,7 @@ public interface IAdmDictBaseService<T>{
      * @return
      */
     List<T> doSetObjectInfoCollect(InstanceUrlParam context, Class<T> clazz, List<T> voList);
+    List<AdmObjectType> doSetObjectTypeCollect(List<AdmObjectType> typeList, List<ObjectTypeCollect> collectTypeList);
 
 
 }

+ 42 - 2
adm-business/adm-middleware/src/main/java/com/persagy/proxy/dictionary/service/impl/AbstractAdmDictBaseServiceImpl.java

@@ -12,6 +12,7 @@ import com.persagy.dmp.common.constant.ValidEnum;
 import com.persagy.dmp.common.context.AppContext;
 import com.persagy.dmp.common.utils.JsonHelper;
 import com.persagy.dmp.delivery.entity.ObjectInfoCollect;
+import com.persagy.dmp.delivery.entity.ObjectTypeCollect;
 import com.persagy.proxy.adm.constant.AdmCommonConstant;
 import com.persagy.proxy.adm.constant.AdmDictConstant;
 import com.persagy.proxy.adm.request.AdmQueryCriteria;
@@ -30,8 +31,7 @@ import org.apache.commons.lang.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
 
 /**
  * @ClassName AbstractAdmDictBaseServiceImpl
@@ -352,6 +352,26 @@ public class AbstractAdmDictBaseServiceImpl<T> implements IAdmDictBaseService<T>
         return response;
     }
 
+    @Override
+    public AdmResponse doQueryObjectTypeCollect(InstanceUrlParam context, QueryCriteria dmpRequest) {
+        // 转换为数据中台查询条件
+        // 转换参数
+        JSONObject para = null;
+        try {
+            para = JsonHelper.toJsonObject(dmpRequest);
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+            return null;
+        }
+        // 调用中台查询
+        log.info(para.toString());
+        DmpResult<JSONArray> dmpResult = rwdClient.queryObjectClassCollect(context, para);
+        List<ObjectTypeCollect> admVOs = AdmEntityTransferUtil.toAdmMultiEntity(dmpResult.getData(), null, ObjectTypeCollect.class);
+        // 设置返回值
+        AdmResponse response = AdmResponse.success(admVOs);
+        return response;
+    }
+
     /**
      * 设置采集信息
      * @param context
@@ -374,4 +394,24 @@ public class AbstractAdmDictBaseServiceImpl<T> implements IAdmDictBaseService<T>
         return AdmEntityTransferUtil.toAdmMultiEntity(response.getData(), null, clazz);
     }
 
+    @Override
+    public List<AdmObjectType> doSetObjectTypeCollect(List<AdmObjectType> typeList, List<ObjectTypeCollect> collectTypeList) {
+        if(CollUtil.isEmpty(typeList)){
+            return Collections.emptyList();
+        }
+        if(CollUtil.isEmpty(collectTypeList)){
+            return typeList;
+        }
+
+        Map<String, ObjectTypeCollect> collectMap = CollUtil.fieldValueMap(collectTypeList, "defineTypeId");
+        for(AdmObjectType admObjectType : typeList){
+            if(collectMap.containsKey(admObjectType.getId())){
+                ObjectTypeCollect collect = collectMap.get(admObjectType.getId());
+                admObjectType.setDeliveryType(collect.getDeliveryType());
+                admObjectType.setIsDelivery(collect.getIsDelivery());
+            }
+        }
+        return typeList;
+    }
+
 }

+ 20 - 9
adm-business/adm-middleware/src/main/java/com/persagy/proxy/dictionary/service/impl/AdmDictServiceImpl.java

@@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.node.JsonNodeFactory;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.persagy.dmp.basic.model.QueryCriteria;
 import com.persagy.dmp.delivery.entity.ObjectInfoCollect;
+import com.persagy.dmp.delivery.entity.ObjectTypeCollect;
 import com.persagy.proxy.adm.constant.AdmDictConstant;
 import com.persagy.proxy.adm.constant.AdmDictCategoryEnum;
 import com.persagy.proxy.adm.request.AdmCreateRequest;
@@ -20,7 +21,6 @@ import com.persagy.proxy.object.model.*;
 import lombok.EqualsAndHashCode;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.util.*;
@@ -51,13 +51,14 @@ public class AdmDictServiceImpl<T> extends AbstractAdmDictBaseServiceImpl<T> imp
     @Override
     public AdmResponse queryCategory(InstanceUrlParam context , AdmDict request, Class<T> clazz) {
         String type = request.getType();
+        AdmResponse admResponse = new AdmResponse();
         QueryCriteria criteria = new QueryCriteria();
         ObjectNode node = JsonNodeFactory.instance.objectNode();
         if(AdmDictCategoryEnum.MAJOR.getValue().equals(type)){
             //查询专业分类
             node.put("type",AdmDictCategoryEnum.MAJOR.getValue());
             criteria.setCriteria(node);
-            return doQueryDictData(context, criteria, clazz);
+            admResponse = doQueryDictData(context, criteria, clazz);
         }
 
         List<String> baseCategory = getDictBaseCategory();
@@ -65,7 +66,7 @@ public class AdmDictServiceImpl<T> extends AbstractAdmDictBaseServiceImpl<T> imp
             //查询设备类型:equipment,部件类型:component,输入系统类型:system,输入专业类型:major,业务空间类型 space ,资产 property
             node.put("objType",type);
             criteria.setCriteria(node);
-            return doQueryObjectType(context, criteria, clazz);
+            admResponse = doQueryObjectType(context, criteria, clazz);
         }
 
         if(AdmDictCategoryEnum.EQUIPMENT_AND_COMPONENT.getValue().equals(type)){
@@ -74,15 +75,25 @@ public class AdmDictServiceImpl<T> extends AbstractAdmDictBaseServiceImpl<T> imp
             arrayNode.add(AdmDictCategoryEnum.COMPONENT.getValue());
             arrayNode.add(AdmDictCategoryEnum.EQUIPMENT.getValue());
             criteria.setCriteria(node);
-            return doQueryObjectType(context, criteria, clazz);
+            admResponse = doQueryObjectType(context, criteria, clazz);
         }
         List<String> dictTreeCategory = getDictTreeCategory();
         if(dictTreeCategory.contains(type)){
             //查询树形结构:专业和系统:majorSystem(树),设备类型要以及对应的部件equipmentComponent(树),专业下的设备类型 majorEquipment(树),
             //专业下的系统,系统下的设备majorSystemEquip (树),systemEquip 系统下的设备类(树)
-            return queryDictObjectTypeTree(context ,type,clazz);
+            admResponse = queryDictObjectTypeTree(context ,type,clazz);
         }
-        return null;
+
+        QueryCriteria criteriaCollect = new QueryCriteria();
+        ObjectNode nodeCol = JsonNodeFactory.instance.objectNode();
+        nodeCol.put("objType", type);
+        criteriaCollect.setCriteria(nodeCol);
+
+        AdmResponse colType = doQueryObjectTypeCollect(context, criteriaCollect);
+        List<AdmObjectType> admObjectTypes = (List<AdmObjectType>) admResponse.getContent();
+        List<ObjectTypeCollect> collectList = (List<ObjectTypeCollect>) colType.getContent();
+        admResponse.setContent(doSetObjectTypeCollect(admObjectTypes, collectList));
+        return admResponse;
     }
 
 
@@ -301,7 +312,7 @@ public class AdmDictServiceImpl<T> extends AbstractAdmDictBaseServiceImpl<T> imp
             infoCollect.setDefineInfoId(funcIdGather.getId());
             infoCollect.setClassCode(funcIdGather.getClassCode());
             infoCollect.setCode(funcIdGather.getCode());
-            //infoCollect.setVisiable(funcIdGather.getVisible());
+            infoCollect.setIsDelivery(funcIdGather.getVisible());
             infoCollect.setKeyWord(funcIdGather.getKeyWord());
             list.add((T) infoCollect);
         }
@@ -451,7 +462,7 @@ public class AdmDictServiceImpl<T> extends AbstractAdmDictBaseServiceImpl<T> imp
             if(CollUtil.isNotEmpty(objectInfoCollectMap)){
                 ObjectInfoCollect collect = objectInfoCollectMap.get(id);
                 if(collect != null){
-                    //visiable = collect.getVisiable();
+                    visiable = collect.getIsDelivery();
                     admObjectInfo.setKeyWord(collect.getKeyWord());
                 }
             }
@@ -491,7 +502,7 @@ public class AdmDictServiceImpl<T> extends AbstractAdmDictBaseServiceImpl<T> imp
             if(CollUtil.isNotEmpty(objectInfoCollectMap)){
                 ObjectInfoCollect collect = objectInfoCollectMap.get(id);
                 if(collect!=null){
-                    //visiable = collect.getVisiable();
+                    visiable = collect.getIsDelivery();
                     admObjectInfo.setKeyWord(collect.getKeyWord());
                 }
             }

+ 2 - 2
adm-business/adm-middleware/src/main/java/com/persagy/proxy/migration/service/Impl/MigrationAbstractServiceImpl.java

@@ -298,7 +298,7 @@ public class MigrationAbstractServiceImpl<T> implements IMigrationAbstractServic
         }else{
             int count= vos.size() / MigrationConstant.BATCH_SUBMIT_DATA_COUNT;
             for(int k = 0; k< count + 1 ;k++){
-                int end = (k+1)  * MigrationConstant.BATCH_SUBMIT_DATA_COUNT - 1;
+                int end = (k+1)  * MigrationConstant.BATCH_SUBMIT_DATA_COUNT;
                 if(end > vos.size()){
                     end = vos.size();
                 }
@@ -409,7 +409,7 @@ public class MigrationAbstractServiceImpl<T> implements IMigrationAbstractServic
         }else{
             int count= syncDataList.size() / MigrationConstant.BATCH_SUBMIT_DATA_COUNT;
             for(int k = 0; k < count + 1 ;k++){
-                int end = (k+1)  * MigrationConstant.BATCH_SUBMIT_DATA_COUNT - 1;
+                int end = (k+1)  * MigrationConstant.BATCH_SUBMIT_DATA_COUNT;
                 if(end > syncDataList.size()){
                     end = syncDataList.size();
                 }

+ 1 - 1
adm-business/adm-middleware/src/main/java/com/persagy/proxy/migration/service/Impl/ObjectDigitalMigration.java

@@ -203,7 +203,7 @@ public class ObjectDigitalMigration extends MigrationAbstractServiceImpl<ObjectD
         }
 
         //因获取的数据均有主键 使用更新
-        String insertUrl = requestUrl(context, migrationInfo, MigrationType.UPDATE.getCode());
+        String insertUrl = requestUrl(context, migrationInfo, MigrationType.CREATE.getCode());
         if(CollUtil.isEmpty(projObjectNodeList)){
             //调用中台验证待新增的数据
             List<ObjectDigital> digitalList = validateInfoCode(admData, context);