From ec180c2ecc3b86ceb285cc6a765d1ae0bf74144d Mon Sep 17 00:00:00 2001 From: qinoy Date: Fri, 12 May 2023 17:34:43 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AB=AF=E5=88=B0=E7=AB=AF=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=20=E5=9B=BE=E5=BD=A2=E8=8A=82=E7=82=B9=E5=88=86=E5=B8=83?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...oft.apps.coe.method.process.subprocess.jar | Bin 10311 -> 25204 bytes .../subprocess/SubProcessController.java | 7 +- .../subprocess/constant/SubProcessConst.java | 3 + .../graph/ForceDirectedGraphLayout.java | 131 ++++++++++++++++++ .../subprocess/graph/GraphAdjMatrix.java | 63 ++++++++- .../process/subprocess/graph/GraphRender.java | 55 ++++++++ .../subprocess/graph/VertexPreHandle.java | 65 +++++++++ .../method/process/subprocess/mode/Node.java | 27 +++- .../{model => mode}/vo/SubProcessTagVo.java | 2 +- .../process/subprocess/web/SubProcessWeb.java | 78 ++++++++--- .../action.xml | 6 + 11 files changed, 407 insertions(+), 30 deletions(-) create mode 100644 com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/ForceDirectedGraphLayout.java create mode 100644 com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/GraphRender.java create mode 100644 com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/VertexPreHandle.java rename com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/{model => mode}/vo/SubProcessTagVo.java (91%) diff --git a/com.actionsoft.apps.coe.method.process.subprocess/lib/com.actionsoft.apps.coe.method.process.subprocess.jar b/com.actionsoft.apps.coe.method.process.subprocess/lib/com.actionsoft.apps.coe.method.process.subprocess.jar index 4b5db017b5bbfa5132bcc270682c8b252870bd68..f19625b6c6bc96a3e3bfcae5fbbdfd078d61b452 100644 GIT binary patch literal 25204 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 QEG!z-AF{keS|9c6f1M&Y@c;k- delta 7423 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 DNOyG< diff --git a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/SubProcessController.java b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/SubProcessController.java index 6377716c..7e6bc0fc 100644 --- a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/SubProcessController.java +++ b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/SubProcessController.java @@ -90,6 +90,11 @@ public class SubProcessController { } } - + @Mapping("com.actionsoft.apps.coe.method.process.subprocess.generator_end_to_end_model") + public String generatorEndToEndModel(UserContext uc, String processIdJsonArr, String locationId, String direction, String modelName){ + SubProcessWeb processWeb = new SubProcessWeb(uc); + processWeb.generatorEndToEndModel(processIdJsonArr, locationId, direction, modelName); + return ResponseObject.newOkResponse().toString(); + } } diff --git a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/constant/SubProcessConst.java b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/constant/SubProcessConst.java index 7093a8ad..8e3b5288 100644 --- a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/constant/SubProcessConst.java +++ b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/constant/SubProcessConst.java @@ -9,6 +9,9 @@ public interface SubProcessConst { // 应用ID String APP_ID = "com.actionsoft.apps.coe.method.process.subprocess"; + String SUB_PROCESS_CATEGORY = "process"; + String SUB_PROCESS_METHOD_ID = "process.subprocess"; + // 端到端流程存放父节点 参数名 String SUB_PROCESS_MODEL_LOCATION = "SUB_PROCESS_MODEL_LOCATION"; diff --git a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/ForceDirectedGraphLayout.java b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/ForceDirectedGraphLayout.java new file mode 100644 index 00000000..f4150842 --- /dev/null +++ b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/ForceDirectedGraphLayout.java @@ -0,0 +1,131 @@ +package com.actionsoft.apps.coe.method.process.subprocess.graph; + +import java.util.Random; + +/** + * 图模型节点布局 + * 采用力导向算法 + * @author oYang + * @create 2023-05-12 14:58 + */ +public class ForceDirectedGraphLayout { + + private final int n; // 节点数 + private final int[][] adjacency; // 邻接矩阵 + private final double[][] position; // 节点位置 + private final double[] charge; // 节点电荷 + private final double[] forceX; // 节点受到的x方向力 + private final double[] forceY; // 节点受到的y方向力 + private final double[] displacementX; // 节点位移的x方向补偿 + private final double[] displacementY; // 节点位移的y方向补偿 + private double temperature = 100.0; // 温度 + private double temperatureDecay = 0.1; // 温度衰减率 + private final double maxDisplacement = 50.0; // 最大位移量 + private final Random random = new Random(); + private final double width; // 画布宽度 + private final double height; // 画布高度 + private final double shapeInterval = 80.0; // 图形节点在画布上的间隔 + private final double nodeW = 100.0; // 图形节点默认宽度 + private final double nodeH = 70.0; // 图形节点默认高度 + + public ForceDirectedGraphLayout(int[][] adjacency) { + this.n = adjacency.length; + this.adjacency = adjacency; + this.position = new double[n][2]; + this.charge = new double[n]; + this.forceX = new double[n]; + this.forceY = new double[n]; + this.displacementX = new double[n]; + this.displacementY = new double[n]; + this.width = n * (shapeInterval + nodeW); + this.height = n * (shapeInterval + nodeH); + + // 初始化节点位置,随机分布在一个2000x2000的矩形内 + for (int i = 0; i < n; i++) { + position[i][0] = random.nextDouble() * width; + position[i][1] = random.nextDouble() * height; + charge[i] = 1.0; // 电荷为1 + } + } + + public void run() { + for (int i = 0; i < 1000; i++) { // 迭代1000次 + calculateForces(); + moveNodes(); + cool(); // 降温 + } + } + + private void calculateForces() { + // 清空所有节点受到的力 + for (int i = 0; i < n; i++) { + forceX[i] = 0; + forceY[i] = 0; + } + + // 计算节点间的斥力 + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (i != j) { + double dx = position[j][0] - position[i][0]; + double dy = position[j][1] - position[i][1]; + double distance = Math.sqrt(dx * dx + dy * dy); + double repulsiveForce = charge[i] * charge[j] / distance * distance; + forceX[i] -= repulsiveForce * dx / distance; + forceY[i] -= repulsiveForce * dy / distance; + } + } + } + + // 计算节点所在边的吸引力 + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (adjacency[i][j] != 0) { // 代表节点i和节点j之间存在一条边 + double dx = position[j][0] - position[i][0]; + double dy = position[j][1] - position[i][1]; + double distance = Math.sqrt(dx * dx + dy * dy); + double attractiveForce = distance * distance / charge[i]; + forceX[i] += attractiveForce * dx / distance; + forceY[i] += attractiveForce * dy / distance; + } + } + } + } + + private void moveNodes() { + for (int i = 0; i < n; i++) { + double displacement = Math.sqrt(forceX[i] * forceX[i] + forceY[i] * forceY[i]); + if (displacement == 0) { // 如果节点受到的力为0,就加一点随机扰动,防止节点过于静止 + displacementX[i] = random.nextDouble() * maxDisplacement * 2 - maxDisplacement; + displacementY[i] = random.nextDouble() * maxDisplacement * 2 - maxDisplacement; + } else { + displacementX[i] = forceX[i] / displacement * Math.min(displacement, maxDisplacement); // 获得x方向的位移补偿 + displacementY[i] = forceY[i] / displacement * Math.min(displacement, maxDisplacement); // 获得y方向的位移补偿 + } + } + for (int i = 0; i < n; i++) { + position[i][0] += displacementX[i]; // 更新节点的x坐标 + position[i][1] += displacementY[i]; // 更新节点的y坐标 + } + } + + private void cool() { + temperature *= 1 - temperatureDecay; // 温度指数级下降,达到类似于“退火”的贪心优化效果 + } + + public double[][] getPosition() { + return position; + } + + public static void main(String[] args) { + int[][] adjacency = new int[][]{{0, 1, 1, 0}, {0, 0, 1, 1}, {1, 0, 0, 1}, {1, 1, 0, 0}}; // 代表四个节点的有向图 + + ForceDirectedGraphLayout fdl = new ForceDirectedGraphLayout(adjacency); + fdl.run(); + + double[][] position = fdl.getPosition(); + for (int i = 0; i < position.length; i++) { + System.out.println("Node " + i + ": (" + position[i][0] + ", " + position[i][1] + ")"); + } + } +} diff --git a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/GraphAdjMatrix.java b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/GraphAdjMatrix.java index 2a96ccbc..88709782 100644 --- a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/GraphAdjMatrix.java +++ b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/GraphAdjMatrix.java @@ -1,9 +1,12 @@ package com.actionsoft.apps.coe.method.process.subprocess.graph; import com.actionsoft.apps.coe.method.process.subprocess.mode.Node; +import com.actionsoft.apps.coe.pal.pal.repository.designer.relation.model.DesignerShapeRelationModel; +import com.actionsoft.bpms.util.ConsolePrinter; import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * 用邻接矩阵表示图模型 并实现相关的操作 @@ -18,11 +21,11 @@ public class GraphAdjMatrix { /** * 构造函数 初始化邻接矩阵 - * @param numVertices + * @param nodeList */ - public GraphAdjMatrix(int numVertices) { - adjMatrix = new int[numVertices][numVertices]; - vertexList = new ArrayList<>(numVertices); + public GraphAdjMatrix(List nodeList) { + adjMatrix = new int[nodeList.size()][nodeList.size()]; + vertexList = nodeList; numEdges = 0; } @@ -53,4 +56,56 @@ public class GraphAdjMatrix { public boolean hasEdge(int u, int v) { return adjMatrix[u][v] == 1; } + + /** + * 获取边的树目 + * @return + */ + public int getNumEdges(){ + return numEdges; + } + + /** + * 获取邻接矩阵 + * @return + */ + public int[][] getAdjMatrix(){ + return adjMatrix; + } + + /** + * 构建邻接矩阵 + * @param nodeIndexMap 索引映射 节点ID与节点在列表中索引的映射关系 + */ + public void buildAdjMatrix(Map nodeIndexMap){ + for (int i = 0; i < vertexList.size(); i++) { + Node currentNode = vertexList.get(i); + // 处理当前节点到后置节点的边 + if (currentNode.getRearModeList() != null && currentNode.getRearModeList().size() > 0){ + List rearModeList = currentNode.getRearModeList(); + for (DesignerShapeRelationModel rearModel : rearModeList) { + addEdge(i, nodeIndexMap.get(rearModel.getRelationFileId()).intValue()); + } + } + // 处理当前节点与前置节点的边 + if (currentNode.getLearModeList() != null && currentNode.getLearModeList().size() > 0){ + List learModeList = currentNode.getLearModeList(); + for (DesignerShapeRelationModel learModel : learModeList) { + addEdge(nodeIndexMap.get(learModel.getRelationFileId()).intValue(), i); + } + } + } + } + + // 输出邻接矩阵 + public void printAdjMatrix() { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < vertexList.size(); i++) { + for (int j = 0; j < vertexList.size(); j++) { + sb.append(adjMatrix[i][j]).append(" "); + } + sb.append("\n"); + } + System.out.println(sb.toString()); + } } diff --git a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/GraphRender.java b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/GraphRender.java new file mode 100644 index 00000000..216d5495 --- /dev/null +++ b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/GraphRender.java @@ -0,0 +1,55 @@ +package com.actionsoft.apps.coe.method.process.subprocess.graph; + +import com.actionsoft.apps.coe.method.process.subprocess.constant.SubProcessConst; +import com.actionsoft.apps.coe.pal.pal.repository.designer.manage.CoeDesignerAPIManager; +import com.actionsoft.apps.coe.pal.pal.repository.designer.model.BaseModel; +import com.actionsoft.apps.coe.pal.pal.repository.designer.util.CoeDesignerUtil; +import com.actionsoft.apps.coe.pal.pal.repository.designer.util.ShapeUtil; +import com.actionsoft.bpms.util.UUIDGener; +import com.alibaba.fastjson.JSONObject; + +public class GraphRender { + + private final int numVertex; + private final double width; // 画布宽度 + private final double height; // 画布高度 + private final double shapeInterval = 80.0; // 图形节点在画布上的间隔 + private final double nodeW = 100.0; // 图形节点默认宽度 + private final double nodeH = 70.0; // 图形节点默认高度 + private final String definition; + private final String modelId; + + + public GraphRender(int numVertex, String modelId, String definition) { + this.numVertex = numVertex; + this.width = numVertex * (shapeInterval + nodeW); + this.height = numVertex * (shapeInterval + nodeH); + + this.definition = definition; + this.modelId = modelId; + } + + public void handleShapeNodeRender(double[][] position) { + JSONObject defineJsonObj = JSONObject.parseObject(definition); + JSONObject page = defineJsonObj.getJSONObject("page"); + page.put("width", width); + page.put("height", height); + JSONObject elements = defineJsonObj.getJSONObject("elements"); + for (int i = 0; i < numVertex; i++) { + JSONObject subProcessNode = ShapeUtil.getProcessShapeDefinition(SubProcessConst.SUB_PROCESS_METHOD_ID, "子流程"); + String nodeId = UUIDGener.getObjectId(); + subProcessNode.put("id", nodeId); + JSONObject subProcessNodeProps = subProcessNode.getJSONObject("props"); + subProcessNodeProps.put("x", position[i][0]); + subProcessNodeProps.put("y", position[i][1]); + elements.put(nodeId, subProcessNode); + } + defineJsonObj.put("elements",elements); + BaseModel model = CoeDesignerAPIManager.getInstance().getDefinition(modelId, 0); + if (model == null) { + model = CoeDesignerUtil.createModel(modelId, 0); + } + model.setDefinition(JSONObject.toJSONString(defineJsonObj)); + CoeDesignerAPIManager.getInstance().storeDefinition(model); + } +} diff --git a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/VertexPreHandle.java b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/VertexPreHandle.java new file mode 100644 index 00000000..47ce10a5 --- /dev/null +++ b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/VertexPreHandle.java @@ -0,0 +1,65 @@ +package com.actionsoft.apps.coe.method.process.subprocess.graph; + +import com.actionsoft.apps.coe.method.process.subprocess.constant.SubProcessConst; +import com.actionsoft.apps.coe.method.process.subprocess.mode.Node; +import com.actionsoft.apps.coe.pal.pal.repository.designer.relation.cache.DesignerShapeRelationCache; +import com.actionsoft.apps.coe.pal.pal.repository.designer.relation.model.DesignerShapeRelationModel; +import com.actionsoft.exception.AWSException; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 图模型节点预处理 + * 选择的若干子流程 其中某些子流程配置的上下游流程并不在所选的若干子流程中 + * 那么这些配置上的上下游流程怎么归属 + * 是包含进总图中还是排除掉 + * @author oYang + * @create 2023-05-12 15:30 + */ +public class VertexPreHandle { + + /** + * 包含进总图中 + * @param processIdList 选择的若干子流程ID + * @param nodeIndexMap 存放子流程在集合中的索引 + * @return + * @throws AWSException + */ + public List includeLearAndRearNode(List processIdList, Map nodeIndexMap) throws AWSException { + List nodeList = new ArrayList<>(); + + for (int i = 0; i < processIdList.size(); i++) { + Node node = new Node(processIdList.get(i)); + // 前置流程 + List learProcessList = DesignerShapeRelationCache.getByFileId(processIdList.get(i), SubProcessConst.LEAD_PROCESS_ATTR_ID); + learProcessList.stream().forEach(model -> { + if (!processIdList.contains(model.getRelationFileId())){ + Node learNode = new Node(model.getRelationFileId()); + nodeList.add(learNode); + nodeIndexMap.put(model.getRelationFileId(), nodeList.size() - 1); + } + }); + node.setLearModeList(learProcessList); + // 后置流程 + List rearProcessList = DesignerShapeRelationCache.getByFileId(processIdList.get(i), SubProcessConst.REAR_PROCESS_ATTR_ID); + rearProcessList.stream().forEach(model -> { + if (!processIdList.contains(model.getRelationFileId())){ + Node rearNode = new Node(model.getRelationFileId()); + nodeList.add(rearNode); + nodeIndexMap.put(model.getRelationFileId(), nodeList.size() - 1); + } + }); + node.setRearModeList(rearProcessList); + nodeList.add(node); + nodeIndexMap.put(node.getId(), nodeList.size() - 1); + } + return nodeList; + } + + @Deprecated + public void excludeLearAndRearNode(List processIdList) throws AWSException { + + } +} diff --git a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/mode/Node.java b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/mode/Node.java index aae7675a..31820ea4 100644 --- a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/mode/Node.java +++ b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/mode/Node.java @@ -1,5 +1,9 @@ package com.actionsoft.apps.coe.method.process.subprocess.mode; +import com.actionsoft.apps.coe.pal.pal.repository.designer.relation.model.DesignerShapeRelationModel; + +import java.util.List; + /** * @author oYang * @create 2023-05-11 17:21 @@ -9,8 +13,10 @@ public class Node { private String id; private double x; private double y; - public double displaceX; // x方向移动位移 - public double displaceY; // y方向移动位移 + + private List learModeList; + private List rearModeList; + public Node(String id) { this.id = id; @@ -46,6 +52,23 @@ public class Node { this.y = y; } + public List getLearModeList() { + return learModeList; + } + + public void setLearModeList(List learModeList) { + this.learModeList = learModeList; + } + + public List getRearModeList() { + return rearModeList; + } + + public void setRearModeList(List rearModeList) { + this.rearModeList = rearModeList; + } + + @Override public String toString() { return "Node{" + diff --git a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/model/vo/SubProcessTagVo.java b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/mode/vo/SubProcessTagVo.java similarity index 91% rename from com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/model/vo/SubProcessTagVo.java rename to com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/mode/vo/SubProcessTagVo.java index e2373791..cd8ca501 100644 --- a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/model/vo/SubProcessTagVo.java +++ b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/mode/vo/SubProcessTagVo.java @@ -1,4 +1,4 @@ -package com.actionsoft.apps.coe.method.process.subprocess.model.vo; +package com.actionsoft.apps.coe.method.process.subprocess.mode.vo; /** * @author oYang diff --git a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/web/SubProcessWeb.java b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/web/SubProcessWeb.java index 5166f571..471c79b1 100644 --- a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/web/SubProcessWeb.java +++ b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/web/SubProcessWeb.java @@ -1,19 +1,31 @@ package com.actionsoft.apps.coe.method.process.subprocess.web; import com.actionsoft.apps.coe.method.process.subprocess.constant.SubProcessConst; +import com.actionsoft.apps.coe.method.process.subprocess.graph.ForceDirectedGraphLayout; import com.actionsoft.apps.coe.method.process.subprocess.graph.GraphAdjMatrix; +import com.actionsoft.apps.coe.method.process.subprocess.graph.GraphRender; +import com.actionsoft.apps.coe.method.process.subprocess.graph.VertexPreHandle; import com.actionsoft.apps.coe.method.process.subprocess.mode.Node; -import com.actionsoft.apps.coe.method.process.subprocess.model.vo.SubProcessTagVo; +import com.actionsoft.apps.coe.method.process.subprocess.mode.vo.SubProcessTagVo; import com.actionsoft.apps.coe.pal.constant.CoEConstant; import com.actionsoft.apps.coe.pal.pal.repository.PALRepositoryQueryAPIManager; import com.actionsoft.apps.coe.pal.pal.repository.cache.PALRepositoryCache; +import com.actionsoft.apps.coe.pal.pal.repository.dao.CoeProcessLevelDaoFacotory; +import com.actionsoft.apps.coe.pal.pal.repository.dao.PALRepository; +import com.actionsoft.apps.coe.pal.pal.repository.designer.CoeDesignerShapeAPIManager; +import com.actionsoft.apps.coe.pal.pal.repository.designer.manage.CoeDesignerAPIManager; +import com.actionsoft.apps.coe.pal.pal.repository.designer.model.BaseModel; import com.actionsoft.apps.coe.pal.pal.repository.designer.relation.cache.DesignerShapeRelationCache; import com.actionsoft.apps.coe.pal.pal.repository.designer.relation.model.DesignerShapeRelationModel; +import com.actionsoft.apps.coe.pal.pal.repository.designer.util.CoeDesignerUtil; import com.actionsoft.apps.coe.pal.pal.repository.model.PALRepositoryModel; +import com.actionsoft.apps.coe.pal.pal.repository.model.impl.PALRepositoryModelImpl; +import com.actionsoft.apps.coe.pal.pal.repository.util.CoeProcessLevelUtil; import com.actionsoft.apps.coe.pal.pal.repository.web.CoeProcessLevelWeb; import com.actionsoft.bpms.commons.mvc.view.ActionWeb; import com.actionsoft.bpms.commons.mvc.view.ResponseObject; import com.actionsoft.bpms.server.UserContext; +import com.actionsoft.bpms.util.UUIDGener; import com.actionsoft.bpms.util.UtilString; import com.actionsoft.exception.AWSException; import com.actionsoft.i18n.I18nRes; @@ -22,6 +34,7 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import org.apache.commons.collections4.IteratorUtils; +import java.sql.Timestamp; import java.util.*; import java.util.stream.Collectors; @@ -46,11 +59,10 @@ public class SubProcessWeb extends ActionWeb { String[] locationIds = property.split("/"); StringBuffer dirName = new StringBuffer(I18nRes.findValue(CoEConstant.APP_ID, locationIds[0]) + "/"); - for (int i = 1; i < locationIds.length; i++) { - PALRepositoryModel model = PALRepositoryCache.getCache().get(locationIds[i]); - dirName.append(model.getName()).append("/"); - } - + PALRepositoryModel model = PALRepositoryCache.getCache().get(locationIds[1]); + if (model == null) + throw new AWSException("应用参数【" + SubProcessConst.SUB_PROCESS_MODEL_LOCATION + "】中配置的一级目录在当前资产库中不存在"); + dirName.append(model.getName()).append("/"); ResponseObject ro = ResponseObject.newOkResponse(); ro.put("dirRootName", dirName.toString()); ro.put("dirRootPath", property); @@ -198,35 +210,57 @@ public class SubProcessWeb extends ActionWeb { .filter(item -> { boolean flag = false; JSONObject model = (JSONObject) item; - return flag = "default".equals(model.getString("plMethodId")) || "".equals(model.getString("plMethodId")); + return flag = "default".equals(model.getString("plMethodId")) || "process.framework".equals(model.getString("plMethodId")); }).collect(Collectors.toCollection(JSONArray :: new)); return result; } - public void generatorEndToEndModel(String processIdJsonArr){ + public void generatorEndToEndModel(String processIdJsonArr, String locationId, String direction, String modelName) throws AWSException{ + if (UtilString.isEmpty(processIdJsonArr)) + throw new AWSException("参数异常"); List processIdList = JSONArray.parseArray(processIdJsonArr, String.class); - // 1.校验 - // 2.根据文件中前游流程与后游流程来确定关联关系 - GraphAdjMatrix graphAdjMatrix = new GraphAdjMatrix(processIdList.size()); - List nodeList = new ArrayList<>(); - for (String processId : processIdList) { - Node node = new Node(processId); - // 前置流程 - List learProcessList = DesignerShapeRelationCache.getByFileId(processId, SubProcessConst.LEAD_PROCESS_ATTR_ID); - // 后置流程 - List rearProcessList = DesignerShapeRelationCache.getByFileId(processId, SubProcessConst.REAR_PROCESS_ATTR_ID); + // 节点预处理 + Map nodeIndexMap = new HashMap<>(); + VertexPreHandle vertexPreHandle = new VertexPreHandle(); + List nodeList = vertexPreHandle.includeLearAndRearNode(processIdList, nodeIndexMap); - } + // 构建有向图邻接矩阵 + GraphAdjMatrix graphAdjMatrix = new GraphAdjMatrix(nodeList); + graphAdjMatrix.buildAdjMatrix(nodeIndexMap); + // graphAdjMatrix.printAdjMatrix(); - // 3.根据关联关系数据模型来决定分布位置 + // 获取节点分布 + ForceDirectedGraphLayout graphLayout = new ForceDirectedGraphLayout(graphAdjMatrix.getAdjMatrix()); + graphLayout.run(); + double[][] position = graphLayout.getPosition(); - // 3.1 每个子流程模型有一个 【子流程模型】的图形属性处理 + // 新建模型 + PALRepositoryModel parentModel = PALRepositoryCache.getCache().get(locationId); + PALRepository coeProcessLevel = CoeProcessLevelDaoFacotory.createCoeProcessLevel(); + Timestamp nowTime = new Timestamp(System.currentTimeMillis()); + String plRid = UUIDGener.getUUID(); + String id = UUIDGener.getUUID(); + int orderIndex = coeProcessLevel.getChildrenMaxOrderIndexByPidAndWsId(parentModel.getId(), parentModel.getWsId()) + 1; + PALRepositoryModelImpl model = CoeProcessLevelUtil.createPALRepositoryModel(id, plRid, parentModel.getWsId(), modelName, "", orderIndex, parentModel.getVersionId(), + SubProcessConst.SUB_PROCESS_CATEGORY, true, 1, id, false, SubProcessConst.SUB_PROCESS_METHOD_ID, "0", parentModel.getLevel() + 1, null, null, + uc.getUID(), uc.getUID(), nowTime, null, null, null, null, null, null, null, null, null,0); - // 4.在分布好的位置上根据关联关系数据模型连线 + CoeProcessLevelDaoFacotory.createCoeProcessLevel().insert(model); + BaseModel baseModel = CoeDesignerAPIManager.getInstance().getDefinition(model.getId(), 0); + if (baseModel == null) baseModel = CoeDesignerUtil.createModel(model.getId(), 0); + //获取流程定义和排序 + CoeDesignerShapeAPIManager manager = CoeDesignerShapeAPIManager.getInstance(); + JSONObject object = manager.getCoeDefinitionAndSort(baseModel.getDefinition(), parentModel.getWsId(), SubProcessConst.SUB_PROCESS_METHOD_ID); + //处理流程节点形状的通用配置 + JSONObject obj = manager.getCoeProcessShapeConfig(object.getString("define"), parentModel.getWsId(), SubProcessConst.SUB_PROCESS_METHOD_ID, model.getId()); + baseModel.setDefinition(obj.getString("define")); + // 节点渲染 + GraphRender graphRender = new GraphRender(nodeList.size(), model.getId(), baseModel.getDefinition()); + graphRender.handleShapeNodeRender(position); } } diff --git a/com.actionsoft.apps.coe.method.process.subprocess/web/com.actionsoft.apps.coe.method.process.subprocess/action.xml b/com.actionsoft.apps.coe.method.process.subprocess/web/com.actionsoft.apps.coe.method.process.subprocess/action.xml index 46184d28..61d310ce 100644 --- a/com.actionsoft.apps.coe.method.process.subprocess/web/com.actionsoft.apps.coe.method.process.subprocess/action.xml +++ b/com.actionsoft.apps.coe.method.process.subprocess/web/com.actionsoft.apps.coe.method.process.subprocess/action.xml @@ -17,4 +17,10 @@ + + + + + + \ No newline at end of file