端到端功能 节点展开与关闭 阶段性代码提交

This commit is contained in:
qinoy 2023-06-06 17:48:01 +08:00
parent 3c9f5a8a84
commit db77c8892d
6 changed files with 677 additions and 1 deletions

View File

@ -129,10 +129,30 @@ public class SubProcessController {
return ResponseObject.newOkResponse().toString();
}
/**
* 节点展开
* @param uc
* @param repositoryId
* @param shapeId
* @return define
*/
@Mapping("com.actionsoft.apps.coe.method.process.subprocess.shape_expand")
public String shapeExpand(UserContext uc, String repositoryId, String shapeId){
SubProcessWeb processWeb = new SubProcessWeb(uc);
return processWeb.shapeNodeExpand(repositoryId, shapeId);
}
/**
* 节点关闭
* @param uc
* @param repositoryId
* @param shapeId
* @return define
*/
@Mapping("com.actionsoft.apps.coe.method.process.subprocess.shape_close")
public String shapeClose(UserContext uc, String repositoryId, String shapeId, String endToEndProcessDefineStr){
SubProcessWeb processWeb = new SubProcessWeb(uc);
return processWeb.shapeNodeClose(repositoryId, shapeId, endToEndProcessDefineStr);
}
}

View File

@ -0,0 +1,617 @@
package com.actionsoft.apps.coe.method.process.subprocess.graph;
import com.actionsoft.apps.coe.method.process.subprocess.constant.LinkerDefConstant;
import com.actionsoft.apps.coe.method.process.subprocess.constant.SubProcessConst;
import com.actionsoft.apps.coe.pal.pal.repository.cache.PALRepositoryCache;
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.ShapeUtil;
import com.actionsoft.bpms.util.ConsolePrinter;
import com.actionsoft.bpms.util.UUIDGener;
import com.actionsoft.bpms.util.UtilString;
import com.actionsoft.exception.AWSException;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
/**
* 图节点关闭处理
*/
public class GraphNodeCloseHandle {
private String repositoryId; // 总图模型ID
private String shapeId; // 总图中当前要关闭的子流程图形ID
private CoeDesignerAPIManager apiManager;
private String relationFileId; // 当前要关闭的子流程图形所标识模型文件ID
private JSONObject childProcessDefine; // 要关闭的子流程模型信息
private JSONObject endToEndProcessDefine; // 总图的模型信息
private JSONObject scopeLimitationShape; // 范围标注框
private final ReentrantLock lock = new ReentrantLock();
public GraphNodeCloseHandle(String repositoryId, String shapeId, String endToEndProcessDefineStr) {
this.repositoryId = repositoryId;
this.shapeId = shapeId;
apiManager = CoeDesignerAPIManager.getInstance();
try {
readChildProcessDefine();
readCurrentProcessDefine(endToEndProcessDefineStr);
} catch (AWSException e) {
throw new AWSException(e);
}
}
/**
* 读取子流程节点的存储信息
* @throws AWSException
*/
private void readChildProcessDefine() throws AWSException{
List<DesignerShapeRelationModel> childProcessModelList = DesignerShapeRelationCache.getListByAttrId(repositoryId, shapeId, SubProcessConst.CHILD_PROCESS);
DesignerShapeRelationModel relationModel = childProcessModelList.stream().findFirst().orElse(null);
if (relationModel == null)
throw new AWSException("未找到当前节点所标识的子流程文件信息");
relationFileId = relationModel.getRelationFileId();
// 先去与总图存储的同级目录下读取 如果为空说明是初次读取
String childProcessDefineStr = apiManager.getChildProcessDefine(repositoryId, 0, relationFileId);
if (UtilString.isEmpty(childProcessDefineStr)){ // 初次读取 去源文件目录读取
BaseModel childProcessBaseModel = apiManager.getDefinition(relationFileId, 0);
if (childProcessBaseModel == null)
throw new AWSException("当前子流程节点内部可能没有图形元素,可以去添加后展开");
childProcessDefineStr = childProcessBaseModel.getDefinition();
}
childProcessDefine = JSONObject.parseObject(childProcessDefineStr);
}
/**
* 读取当前总图的存储信息
* @throws AWSException
*/
private void readCurrentProcessDefine(String endToEndProcessDefineStr) throws AWSException{
if (UtilString.isEmpty(endToEndProcessDefineStr))
throw new AWSException("参数异常,模型存储信息未传");
endToEndProcessDefine = JSONObject.parseObject(endToEndProcessDefineStr);
scopeLimitationShape= endToEndProcessDefine.getJSONObject("elements").getJSONObject(shapeId);
}
/**
* 处理节点关闭
* @return
* @throws AWSException
*/
public String handleNodeClose() throws AWSException {
// 1处理范围选择框及其内部节点
handleRelationModelNodePosition();
// 2处理总图中的节点与连线
handleEndToEndGraphNodeAndLinker();
return endToEndProcessDefine.toJSONString();
}
private void handleEndToEndGraphNodeAndLinker(){
// 1创建对应子流程节点
JSONObject subProcessNode = buildSubProcessNode(shapeId, scopeLimitationShape);
addEndToEndGraphElements(subProcessNode);
// 2根据现有连线关系创建邻接矩阵
NodeCloseAdjMatrix closeAdjMatrix = buildEndToEndGraphAdjMatrix();
closeAdjMatrix.buildAdjMatrix();
// 3收集现有元素坐标
JSONObject elements = readEndToEndGraphElements();
double[][] vertexPosition = closeAdjMatrix.getVertexPosition(elements);
// 4删除现有连线
removeEndToEndGraphOldLinker();
// 5构建新的连线
JSONObject processProperties = endToEndProcessDefine.getJSONObject("processProperties");
String direction = processProperties.getString("direction");
NodeCloseLinkerRender linkerRender = new NodeCloseLinkerRender(vertexPosition, closeAdjMatrix, scopeLimitationShape);
JSONArray linkers = linkerRender.toAssembleLinker(direction, shapeId);
for (Object o : linkers) {
JSONObject linker = (JSONObject) o;
addEndToEndGraphElements(linker);
}
// 6更新画布的大小
// 确定画布的宽度与高度
double w = Arrays.stream(vertexPosition).mapToDouble(position -> position[0]).max().orElse(0.0);
double h = Arrays.stream(vertexPosition).mapToDouble(position -> position[1]).max().orElse(0.0);
JSONObject page = endToEndProcessDefine.getJSONObject("page");
page.put("width", w + 300);
page.put("height", h + 300);
}
private void handleRelationModelNodePosition(){
removeScopeShapeAndInRangeEle();
removeEndToEndGraphElements(shapeId);
}
/**
* 删除总图中节点展开前的连线
*/
private void removeEndToEndGraphOldLinker(){
JSONObject elements = endToEndProcessDefine.getJSONObject("elements");
Set<String> eleKeys = new HashSet<>();
for (String key : elements.keySet()) {
JSONObject ele = elements.getJSONObject(key);
if ("linker".equals(ele.getString("name"))){
eleKeys.add(key);
}
}
for (String eleKey : eleKeys) {
removeEndToEndGraphElements(eleKey);
}
}
/**
* 构建节点展开前 端到端总图的邻接矩阵
* 方便后续节点展开或者闭合进行重新连线
*/
private NodeCloseAdjMatrix buildEndToEndGraphAdjMatrix(){
List<String> nodeIdList = new ArrayList<>();
List<JSONObject> linkerList = new ArrayList<>();
JSONObject endToEndProcessElements = endToEndProcessDefine.getJSONObject("elements");
for (String key : endToEndProcessElements.keySet()) {
JSONObject ele = endToEndProcessElements.getJSONObject(key);
if ("linker".equals(ele.getString("name"))) {
linkerList.add(ele);
}else {
nodeIdList.add(key);
}
}
NodeCloseAdjMatrix closeAdjMatrix = new NodeCloseAdjMatrix(nodeIdList, linkerList);
return closeAdjMatrix;
}
/**
* 构建子流程节点
* @param shapeId
* @param scopeLimitationShape
* @return
*/
private JSONObject buildSubProcessNode(String shapeId, JSONObject scopeLimitationShape){
JSONObject subProcessNode = ShapeUtil.getProcessShapeDefinition(SubProcessConst.SUB_PROCESS_METHOD_ID, "子流程");
subProcessNode.put("id", shapeId);
JSONObject subProcessNodeProps = subProcessNode.getJSONObject("props");
subProcessNodeProps.put("x", scopeLimitationShape.getJSONObject("props").getDoubleValue("x"));
subProcessNodeProps.put("y", scopeLimitationShape.getJSONObject("props").getDoubleValue("y"));
subProcessNodeProps.put("zindex", scopeLimitationShape.getJSONObject("props").getIntValue("zindex"));
subProcessNode.put("text", PALRepositoryCache.getCache().get(relationFileId).getName());
return subProcessNode;
}
/**
* 删除总图中范围选择框以及 框内元素
*/
private void removeScopeShapeAndInRangeEle(){
JSONObject childProcessElements = childProcessDefine.getJSONObject("elements");
for (String key : childProcessElements.keySet()) {
removeEndToEndGraphElements(key);
}
removeEndToEndGraphElements(shapeId);
}
/**
* 读取总图中的elements
* @return elements
*/
private JSONObject readEndToEndGraphElements(){
lock.lock();
try {
JSONObject elements = endToEndProcessDefine.getJSONObject("elements");
return elements;
}finally {
lock.unlock();
}
}
/**
* 总图中添加元素
* @param ele
*/
private void addEndToEndGraphElements(JSONObject ele){
lock.lock();
try{
JSONObject elements = readEndToEndGraphElements();
String id = ele.getString("id");
elements.put(id, ele);
}finally {
lock.unlock();
}
}
/**
* 总图中删除元素
* @param key
*/
private void removeEndToEndGraphElements(String key){
lock.lock();
try{
JSONObject elements = readEndToEndGraphElements();
elements.remove(key);
}finally {
lock.unlock();
}
}
}
/**
* 节点展开的邻接矩阵
*/
class NodeCloseAdjMatrix{
private int[][] adjMatrix;
private List<String> nodeIds;
private List<JSONObject> linkerList;
public NodeCloseAdjMatrix(List<String> nodeIds, List<JSONObject> linkerList) {
this.adjMatrix = new int[nodeIds.size()][nodeIds.size()];
this.nodeIds = nodeIds;
this.linkerList = linkerList;
}
/**
* 添加一条从顶点 u 到顶点 v 的有向边
*/
public void addEdge(int u, int v) {
adjMatrix[u][v] = 1; // 设置邻接矩阵中相应的位置为 1
}
/**
* 获取从顶点 u 出发可以到达的所有顶点
*/
public List<Integer> getNeighbors(int u) {
List<Integer> neighbors = new ArrayList<>();
for (int i = 0; i < nodeIds.size(); i++) {
if (adjMatrix[u][i] == 1) {
neighbors.add(i);
}
}
return neighbors;
}
/**
* 判断从顶点 u 是否可以到达顶点 v
*/
public boolean hasEdge(int u, int v) {
return adjMatrix[u][v] == 1;
}
/**
* 获取邻接矩阵
* @return
*/
public int[][] getAdjMatrix(){
return adjMatrix;
}
public List<String> getNodeIds() {
return nodeIds;
}
public List<JSONObject> getLinkerList() {
return linkerList;
}
/**
* 构建邻接矩阵
*/
public void buildAdjMatrix(){
for (JSONObject linker : linkerList) {
JSONObject from = linker.getJSONObject("from");
JSONObject to = linker.getJSONObject("to");
int fromIndex = nodeIds.indexOf(from.getString("id"));
int toIndex = nodeIds.indexOf(to.getString("id"));
addEdge(fromIndex, toIndex);
}
}
// 输出邻接矩阵
public void printAdjMatrix() {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < nodeIds.size(); i++) {
for (int j = 0; j < nodeIds.size(); j++) {
sb.append(adjMatrix[i][j]).append(" ");
}
sb.append("\n");
}
System.out.println(sb.toString());
}
/**
* 获取总图中节点展开前的所有节点坐标
* @param elements
* @return
*/
public double[][] getVertexPosition(JSONObject elements){
double[][] position = new double[nodeIds.size()][2];
for (int i = 0; i < nodeIds.size(); i++) {
JSONObject shape = elements.getJSONObject(nodeIds.get(i));
JSONObject props = shape.getJSONObject("props");
double x = props.getDoubleValue("x");
double y = props.getDoubleValue("y");
position[i][0] = x;
position[i][1] = y;
}
return position;
}
}
/**
* 节点展开后连线重构
*/
class NodeCloseLinkerRender{
private List<String> nodeIds; // 图形节点ID集合
private double[][] vertexPosition; // 所有节点的坐标
private NodeCloseAdjMatrix closeAdjMatrix; // 节点矩阵
private JSONObject scopeLimitationShape; // 范围标注框
public NodeCloseLinkerRender(double[][] vertexPosition, NodeCloseAdjMatrix closeAdjMatrix, JSONObject scopeLimitationShape) {
this.nodeIds = closeAdjMatrix.getNodeIds();
this.vertexPosition = vertexPosition;
this.closeAdjMatrix = closeAdjMatrix;
this.scopeLimitationShape = scopeLimitationShape;
}
/**
* 根据连线方向 组装连线
* @param direction 连线方向
* @param shapeId 当前待展开节点ID
* @return
*/
public JSONArray toAssembleLinker(String direction, String shapeId){
JSONArray linkers = new JSONArray();
int index = nodeIds.indexOf(shapeId);
for (int i = 0; i < vertexPosition.length; i++) {
boolean currentExpandNodeIsStart = false;
if (i == index){
// currentExpandNodeIsStart = true; // 当前待展开的节点此处应是范围选择框为连线的出发点
}
double[] fromPoi = vertexPosition[i];
List<Integer> nextNodeIndex = closeAdjMatrix.getNeighbors(i);
if (nextNodeIndex.size() > 0){ // 说明当前节点有连线
for (Integer nodeIndex : nextNodeIndex) {
boolean currentExpandNodeIsEnd = false;
if (nodeIndex.intValue() == index){
// currentExpandNodeIsEnd = true; // 当前待展开的节点 此处应是范围选择框为连线的终点
}
double[] toPoi = vertexPosition[nodeIndex];
double[][] turnPoi = "horizontal".equals(direction)
? calculationLinkerPointInHorizLayOut(fromPoi, toPoi, currentExpandNodeIsStart, currentExpandNodeIsEnd)
: calculationLinkerPointInVertLayOut(fromPoi, toPoi, currentExpandNodeIsStart, currentExpandNodeIsEnd);
double[] angleArr = calculationLinkerAngle(fromPoi, toPoi, turnPoi[1], turnPoi[turnPoi.length - 2]);
// 构建连线
JSONObject linkerObj = JSONObject.parseObject(LinkerDefConstant.linker);
linkerObj.put("id", UUIDGener.getObjectId());
// 折点
JSONArray points = new JSONArray();
for (int j = 0; j < turnPoi.length; j++) {
if (j > 0 && j < turnPoi.length - 1){
JSONObject pointObj = new JSONObject();
pointObj.put("x", turnPoi[j][0]);
pointObj.put("y", turnPoi[j][1]);
points.add(pointObj);
}
}
linkerObj.put("points", points);
// 起点与终点
JSONObject fromObj = new JSONObject();
fromObj.put("x", turnPoi[0][0]);
fromObj.put("y", turnPoi[0][1]);
fromObj.put("angle", angleArr[0]);
fromObj.put("id", nodeIds.get(i));
linkerObj.put("from", fromObj);
JSONObject toObj = new JSONObject();
toObj.put("x", turnPoi[turnPoi.length - 1][0]);
toObj.put("y", turnPoi[turnPoi.length - 1][1]);
toObj.put("angle", angleArr[1]);
toObj.put("id", nodeIds.get(nodeIndex.intValue()));
linkerObj.put("to", toObj);
linkers.add(linkerObj);
}
}
}
return linkers;
}
private double[][] calculationLinkerPointInVertLayOut(double[] fromPoi, double[] toPoi, boolean currentExpandNodeIsStart, boolean currentExpandNodeIsEnd) {
double fromX = fromPoi[0],fromY = fromPoi[1],toX = toPoi[0],toY = toPoi[1];
double scopeShapeW = scopeLimitationShape.getJSONObject("props").getDoubleValue("w"), scopeShapeH = scopeLimitationShape.getJSONObject("props").getDoubleValue("h");
if (fromY == toY){ // 水平 分析可知 水平方向上不会出现 从左到右直连的情况 只有 右边节点右侧锚点出 向上走 左折 连到左侧节点上方锚点
double[] startPoi = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
double[] turnPoi1 = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
double[] turnPoi2 = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2};
double[] turnPoi3 = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2};
double[] endPoi = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY};
return new double[][]{startPoi, turnPoi1, turnPoi2, turnPoi3, endPoi};
}else if (fromX == toX){ // 垂直 分析可知 垂直方向上应该不会有 toY < fromY 的情况 鉴于数据不确定性 先写上
double[] startPoi = fromY < toY
? new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H)}
: new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
double[] endPoi = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY};
return fromY < toY
? new double[][]{
startPoi,
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) + SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
endPoi}
: new double[][]{
startPoi,
{fromX + ((currentExpandNodeIsStart || currentExpandNodeIsEnd) ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{fromX + ((currentExpandNodeIsStart || currentExpandNodeIsEnd) ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
endPoi};
}else { // 分布在四个象限内
if (fromX > toX && fromY > toY){ // 目标节点在第二象限
return new double[][]{
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY}
};
}else if (fromX > toX && fromY < toY){ // 目标节点在第三象限
return toY - fromY == SubProcessConst.SHAPE_VERT_INTERVAL
? new double[][]
{
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H)},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) + SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY}
}
: new double[][]
{
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H)},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) + SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) + SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY}
};
}else if (fromX < toX && fromY < toY){ // 目标节点在第四象限
return new double[][]{
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H)},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) + SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY}
};
}else {
// fromX < toX && fromY > toY 目标节点在第一象限 分析可知 纵向排布的情况下 应该不会出现目标节点在第一象限的情况
}
}
return new double[2][2];
}
private double[][] calculationLinkerPointInHorizLayOut(double[] fromPoi, double[] toPoi, boolean currentExpandNodeIsStart, boolean currentExpandNodeIsEnd) {
double fromX = fromPoi[0],fromY = fromPoi[1],toX = toPoi[0],toY = toPoi[1];
double scopeShapeW = scopeLimitationShape.getJSONObject("props").getDoubleValue("w"), scopeShapeH = scopeLimitationShape.getJSONObject("props").getDoubleValue("h");
if (fromY == toY) { // 水平 方向上 存在从左向右直连的情况 但不存在从右向左直连的情况 水平方向上 从左向右 应是 右出 向上 左折 向下
return fromX < toX
? new double[][]
{
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{toX - SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY + (currentExpandNodeIsEnd ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{toX, toY + (currentExpandNodeIsEnd ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2}
}
: new double[][]
{
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY}
};
}else if (fromX == toX) { // 垂直
// 节点横向分布 连线按照大原则 垂直 不存在 fromY < toY 的情况 也就是不存在 连线从上到下直连的情况
double[] startPoint = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
double[] endPoint = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY};
return new double[][]{startPoint,
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
endPoint};
}else {
if (fromX < toX && fromY > toY){ // 目标节点在第一象限
double[] startPoint = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
double turnPointX = fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2;
if (fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL == toX){ // 相邻节点 存在两个折点
double[] endPoint = new double[]{toX, toY + (currentExpandNodeIsEnd ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
return new double[][]{startPoint,{turnPointX, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},{turnPointX, toY + (currentExpandNodeIsEnd ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2}, endPoint};
}else { // 不相邻节点 存在三个折点
double[] endPoint = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY};
return new double[][]{
startPoint,
{turnPointX, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{turnPointX, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
endPoint
};
}
}else if (fromX > toX && fromY > toY) { // 目标节点在第二象限 无论节点是否相邻 都按照三个折点走
double[] startPoint = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
double[] endPoint = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY};
return new double[][]{
startPoint,
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
endPoint
};
}else if (fromX < toX && fromY < toY){ // 目标节点在第四象限
double[] startPoint = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
if (fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL == toX){ // 相邻节点 存在两个折点
double turnPointX = fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2;
double[] endPoint = new double[]{toX, toY + (currentExpandNodeIsEnd ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
return new double[][]{
startPoint,
{turnPointX, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{turnPointX, toY + (currentExpandNodeIsEnd ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
endPoint
};
}else { // 不相邻节点 存在三个折点
double[] endPoint = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY};
return new double[][]{
startPoint,
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
endPoint
};
}
}else if (fromX > toX && fromY < toY){ // 目标节点在第三象限 横向布局的情况下 应该不会出现目标节点在第三象限的情况
ConsolePrinter.warn("[端到端功能][节点展开模块]处理连线时目标节点在[横向布局]的情况下出现在了第三象限");
}
}
return new double[2][2];
}
/**
* 计算angle值
* @param fromPoi 起始节点坐标
* @param toPoi 结束节点坐标
* @param firstTurnPoi 连线第一个折点坐标
* @param lastTurnPoi 连线最后一个折点坐标
* @return [0]: from的angle [1]: to的angle
*/
private double[] calculationLinkerAngle(double[] fromPoi, double[] toPoi, double[] firstTurnPoi, double[] lastTurnPoi){
double fromX = fromPoi[0], fromY = fromPoi[1];
double toX = toPoi[0], toY = toPoi[1];
double firstTurnX = firstTurnPoi[0], firstTurnY = firstTurnPoi[1];
double lastTurnX = lastTurnPoi[0], lastTurnY = lastTurnPoi[1];
if (fromY == toY){ // 水平
return fromX < toX ? new double[]{LinkerDefConstant.ANGLE_LEFT, LinkerDefConstant.ANGLE_RIGHT} : new double[]{LinkerDefConstant.ANGLE_RIGHT, LinkerDefConstant.ANGLE_LEFT};
}else if (fromX == toX){ // 垂直
return fromY < toY ? new double[]{LinkerDefConstant.ANGLE_UP, LinkerDefConstant.ANGLE_DOWN} : new double[]{LinkerDefConstant.ANGLE_DOWN, LinkerDefConstant.ANGLE_UP};
}else {
double fromAngle = 0.0;
if (fromY == firstTurnY){ // 水平
fromAngle = fromX < firstTurnX ? LinkerDefConstant.ANGLE_LEFT : LinkerDefConstant.ANGLE_RIGHT;
}else if (fromX == firstTurnX){ // 垂直
fromAngle = fromY < firstTurnY ? LinkerDefConstant.ANGLE_UP : LinkerDefConstant.ANGLE_DOWN;
}
double toAngle = 0.0;
if (toY == lastTurnY){ // 水平
toAngle = toX < lastTurnX ? LinkerDefConstant.ANGLE_LEFT : LinkerDefConstant.ANGLE_RIGHT;
}else if (toX == lastTurnX){ // 垂直
toAngle = toY < lastTurnY ? LinkerDefConstant.ANGLE_UP : LinkerDefConstant.ANGLE_DOWN;
}
return new double[]{fromAngle, toAngle};
}
}
}

View File

@ -316,7 +316,7 @@ public class SubProcessWeb extends ActionWeb {
try {
GraphNodeExpandHandle nodeExpandHandle = new GraphNodeExpandHandle(repositoryId, shapeId);
String define = nodeExpandHandle.handleNodeExpand();
ResponseObject ro = ResponseObject.newOkResponse("展开成功");
ResponseObject ro = ResponseObject.newOkResponse("节点展开成功");
ro.setData(define);
return ro.toString();
} catch (Exception e) {
@ -324,4 +324,16 @@ public class SubProcessWeb extends ActionWeb {
}
}
public String shapeNodeClose(String repositoryId, String shapeId, String endToEndProcessDefineStr){
try {
GraphNodeCloseHandle closeHandle = new GraphNodeCloseHandle(repositoryId, shapeId, endToEndProcessDefineStr);
String define = closeHandle.handleNodeClose();
ResponseObject ro = ResponseObject.newOkResponse("节点关闭成功");
ro.setData(define);
return ro.toString();
} catch (AWSException e) {
return ResponseObject.newErrResponse(e.getMessage()).toString();
}
}
}

View File

@ -31,4 +31,9 @@
<param name="repositoryId"/>
<param name="shapeId"/>
</cmd-bean>
<cmd-bean name="com.actionsoft.apps.coe.method.process.subprocess.shape_close">
<param name="repositoryId"/>
<param name="shapeId"/>
<param name="endToEndProcessDefineStr"/>
</cmd-bean>
</aws-actions>

View File

@ -165,7 +165,29 @@ class SubProcess {
shapeClose(event){
console.log('sss');
let param = event.data;
awsui.ajax.request({
url: './jd',
method: 'POST',
data: {
cmd: 'com.actionsoft.apps.coe.method.process.subprocess.shape_close',
sid: param.sid,
repositoryId: param.repositoryId,
shapeId: param.shapeId,
endToEndProcessDefineStr: definition
},
ok: function (r) {
definition = JSON.stringify(r.data);
Designer.open(definition); // 节点重新渲染
// 针对范围标识框渲染 节点关闭按钮
window.subProcess.shapeIconRender();
// 提示用户文件已修改
window.subProcess.fileModifiedTip();
},
err: function (r) {
}
});
}
fileModifiedTip(){