Merge remote-tracking branch 'origin/apps_dev' into apps_dev
This commit is contained in:
commit
73e009d436
Binary file not shown.
@ -546,7 +546,7 @@ path:[
|
||||
{lineStyle:{lineWidth:0}, fillStyle:{type:"none"}, actions:{ref:"roundRectangle"}}
|
||||
]});
|
||||
|
||||
Schema.addShape({name:"scopeLimitation", title:"", text:"", category:"process_subprocess", groupName:"", props:{w:100, h:70},
|
||||
Schema.addShape({name:"scopeLimitation", title:"展开范围标注", text:"", category:"process_subprocess", groupName:"", props:{w:100, h:70},
|
||||
fillStyle:{type:"none"},
|
||||
path:[
|
||||
{lineStyle:{lineWidth:1, lineStyle:"dashed",lineColor:"184,184,184"}, actions:{ref:"roundRectangle"}},
|
||||
|
||||
@ -113,20 +113,6 @@ public class SubProcessController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成图->前置处理
|
||||
* 前置流程或后置流程是否在所选的范围内
|
||||
* @param uc
|
||||
* @param processIdJsonArr
|
||||
* @param excludeProcessIdJsonArr
|
||||
* @return
|
||||
*/
|
||||
@Mapping("com.actionsoft.apps.coe.method.process.subprocess.lead_rear_node_pre_handle")
|
||||
public String vertexPreHandle2(UserContext uc, String processIdJsonArr, String excludeProcessIdJsonArr){
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 功能->生成图
|
||||
* @param uc
|
||||
@ -143,4 +129,10 @@ public class SubProcessController {
|
||||
return ResponseObject.newOkResponse().toString();
|
||||
}
|
||||
|
||||
@Mapping("com.actionsoft.apps.coe.method.process.subprocess.shape_expand")
|
||||
public String shapeExpand(UserContext uc, String repositoryId, String shapeId){
|
||||
|
||||
return ResponseObject.newOkResponse("展开成功").toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,131 +0,0 @@
|
||||
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 = 180.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] + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,125 @@
|
||||
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.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.UtilString;
|
||||
import com.actionsoft.exception.AWSException;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 图节点展开处理
|
||||
*/
|
||||
public class GraphNodeExpandHandle {
|
||||
|
||||
private String repositoryId; // 总图模型ID
|
||||
private String shapeId; // 总图中当前要展开的子流程图形ID
|
||||
private String relationFileId; // 当前要展开的子流程图形所标识模型文件ID
|
||||
private CoeDesignerAPIManager apiManager;
|
||||
private String childProcessDefine; // 要展开的子流程模型信息
|
||||
private String endToEndProcessDefine; // 总图的模型信息
|
||||
|
||||
public GraphNodeExpandHandle(String repositoryId, String shapeId) {
|
||||
this.repositoryId = repositoryId;
|
||||
this.shapeId = shapeId;
|
||||
|
||||
apiManager = CoeDesignerAPIManager.getInstance();
|
||||
|
||||
readChildProcessDefine();
|
||||
readCurrentProcessDefine();
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取子流程节点的存储信息
|
||||
* @throws AWSException
|
||||
*/
|
||||
public 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();
|
||||
childProcessDefine = apiManager.getChildProcessDefine(repositoryId, 0, relationFileId);
|
||||
if (UtilString.isEmpty(childProcessDefine)){ // 初次展开 去源文件目录读取
|
||||
BaseModel childProcessBaseModel = apiManager.getDefinition(relationFileId, 0);
|
||||
childProcessDefine = childProcessBaseModel.getDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取当前总图的存储信息
|
||||
* @throws AWSException
|
||||
*/
|
||||
public void readCurrentProcessDefine() throws AWSException{
|
||||
BaseModel baseModel = apiManager.getDefinition(repositoryId, 0);
|
||||
if (baseModel == null)
|
||||
throw new AWSException("未找到当前总图存储的模型信息");
|
||||
endToEndProcessDefine = baseModel.getDefinition();
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装范围标注框
|
||||
* @return 范围标注框
|
||||
* @throws AWSException
|
||||
*/
|
||||
public JSONObject toAssembleScopeLimitationShape() throws AWSException{
|
||||
JSONObject scopeLimitationShape = ShapeUtil.getProcessShapeDefinition(SubProcessConst.SUB_PROCESS_METHOD_ID, "展开范围标注");
|
||||
JSONObject childProcessDefineObj = JSONObject.parseObject(childProcessDefine);
|
||||
JSONObject childProcessPage = childProcessDefineObj.getJSONObject("page");
|
||||
// 当前节点所标识的子流程文件的 画布宽度与高度 减去边距
|
||||
double childProcessPageWidth = childProcessPage.getDoubleValue("width") - childProcessPage.getDoubleValue("padding") * 2;
|
||||
double childProcessPageHeight = childProcessPage.getDoubleValue("height") - childProcessPage.getDoubleValue("padding") * 2;
|
||||
|
||||
JSONObject endToEndProcessDefineObj = JSONObject.parseObject(endToEndProcessDefine);
|
||||
JSONObject elements = endToEndProcessDefineObj.getJSONObject("elements");
|
||||
// 找到当前要展开的子流程节点
|
||||
JSONObject currentExpandShape = elements.getJSONObject(shapeId);
|
||||
if (currentExpandShape == null)
|
||||
throw new AWSException("未找到当前要展开的子流程节点信息");
|
||||
JSONObject props = currentExpandShape.getJSONObject("props");
|
||||
double x = props.getDoubleValue("x");
|
||||
double y = props.getDoubleValue("y");
|
||||
// 当前要展开的子流程节点的坐标赋给范围标注框
|
||||
JSONObject scopeShapeProps = scopeLimitationShape.getJSONObject("props");
|
||||
scopeShapeProps.put("x", x);
|
||||
scopeShapeProps.put("y", y);
|
||||
scopeShapeProps.put("w", childProcessPageWidth);
|
||||
scopeShapeProps.put("h", childProcessPageHeight);
|
||||
scopeShapeProps.put("zindex", 1);
|
||||
return scopeLimitationShape;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理子流程中所有节点的坐标
|
||||
*/
|
||||
public void handleRelationModelNodePosition(){
|
||||
|
||||
// 范围标注框 坐标
|
||||
JSONObject scopeLimitationShape = toAssembleScopeLimitationShape();
|
||||
JSONObject scopeShapeProps = scopeLimitationShape.getJSONObject("props");
|
||||
double scopeShapeX = scopeShapeProps.getDoubleValue("x");
|
||||
double scopeShapeY = scopeShapeProps.getDoubleValue("y");
|
||||
|
||||
// 根据范围标注框的坐标 调整子流程所有元素的坐标
|
||||
JSONObject childProcessDefineObj = JSONObject.parseObject(childProcessDefine);
|
||||
JSONObject elements = childProcessDefineObj.getJSONObject("elements");
|
||||
for (String key : elements.keySet()) {
|
||||
JSONObject ele = elements.getJSONObject(key);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储子流程模型信息
|
||||
* 在总图存储的同一级目录下
|
||||
*/
|
||||
public void storeChildProcessDefine(){
|
||||
BaseModel baseModel = apiManager.getDefinition(relationFileId, 0);
|
||||
apiManager.storeChildProcessDefine(baseModel, relationFileId, childProcessDefine);
|
||||
}
|
||||
}
|
||||
@ -1,197 +0,0 @@
|
||||
package com.actionsoft.apps.coe.method.process.subprocess.graph;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 图模型节点布局
|
||||
* 采用 PageRank 算法
|
||||
* @author oYang
|
||||
* @create 2023-05-16 11:10
|
||||
*/
|
||||
public class PageRankLayout {
|
||||
|
||||
private int[][] matrix; // 邻接矩阵
|
||||
private double width; // 画布宽度
|
||||
private double height; // 画布高度
|
||||
private int maxIter; // 最大迭代次数
|
||||
private double damp; // 阻尼因子
|
||||
private int nodeSize; // 节点数
|
||||
private double[] pageRankVal; // PageRank数据
|
||||
private final double shapeInterval = 80.0; // 图形节点在画布上的间隔
|
||||
private final double nodeW = 100.0; // 图形节点默认宽度
|
||||
private final double nodeH = 70.0; // 图形节点默认高度
|
||||
|
||||
public PageRankLayout(int[][] matrix, int maxIter) {
|
||||
this.matrix = matrix;
|
||||
this.maxIter = maxIter;
|
||||
this.damp = 0.85;
|
||||
this.nodeSize = matrix.length;
|
||||
this.pageRankVal = new double[nodeSize];
|
||||
|
||||
this.width = matrix.length * (shapeInterval + nodeW);
|
||||
this.height = matrix.length * (shapeInterval + nodeH);
|
||||
|
||||
// 初始化每个节点的 PageRank 值为 1/N
|
||||
Arrays.fill(pageRankVal, 1.0/nodeSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算每个节点的入度加权平均值
|
||||
*/
|
||||
public void calculatePageRankVal(){
|
||||
for (int iter = 0; iter < maxIter; iter++) {
|
||||
double[] nextPR = new double[nodeSize];
|
||||
for (int i = 0; i < nodeSize; i++) {
|
||||
double sum = 0.0;
|
||||
for (int j = 0; j < nodeSize; j++) {
|
||||
if (matrix[j][i] == 1) {
|
||||
sum += pageRankVal[j] / countOutLinks(j);
|
||||
}
|
||||
}
|
||||
nextPR[i] = (1 - damp) / nodeSize + damp * sum;
|
||||
}
|
||||
pageRankVal = nextPR;
|
||||
}
|
||||
// 输出结果
|
||||
for (int i = 0; i < nodeSize; i++) {
|
||||
System.out.printf("Node %d: PageRank = %.3f\n", i, pageRankVal[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据节点邻接矩阵计算节点的出度
|
||||
* @param nodeIndex
|
||||
* @return
|
||||
*/
|
||||
private int countOutLinks(int nodeIndex){
|
||||
int count = 0;
|
||||
for (int i = 0; i < matrix[nodeIndex].length; i++) {
|
||||
if (matrix[nodeIndex][i] == 1) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据节点邻接矩阵计算节点入度
|
||||
* @param nodeIndex
|
||||
* @return
|
||||
*/
|
||||
private int countInputLinks(int nodeIndex){
|
||||
int count = 0;
|
||||
for (int i = 0; i < matrix.length; i++) {
|
||||
if (matrix[i][nodeIndex] == 1){
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private void layOut(){
|
||||
int n = pageRankVal.length;
|
||||
// 计算 PageRank 值最大的节点,将该节点定位在画布的中心
|
||||
int maxIndex = 0;
|
||||
double maxPageRank = pageRankVal[0];
|
||||
for (int i = 1; i < n; i++) {
|
||||
if (pageRankVal[i] > maxPageRank) {
|
||||
maxIndex = i;
|
||||
maxPageRank = pageRankVal[i];
|
||||
}
|
||||
}
|
||||
double centerX = width / 2;
|
||||
double centerY = height / 2;
|
||||
|
||||
// 计算其它节点相对于最大节点的 PageRank 值的比例关系,以及节点数量的平方根
|
||||
double scale = Math.sqrt(n);
|
||||
double[] distX = new double[n];
|
||||
double[] distY = new double[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (i == maxIndex) {
|
||||
distX[i] = 0;
|
||||
distY[i] = 0;
|
||||
} else {
|
||||
double ratio = pageRankVal[i] / pageRankVal[maxIndex];
|
||||
distX[i] = ratio * Math.cos(2 * Math.PI * i / n);
|
||||
distY[i] = ratio * Math.sin(2 * Math.PI * i / n);
|
||||
}
|
||||
}
|
||||
|
||||
// 将节点的 PageRank 值乘以比例关系和节点数量的平方根,得到节点在横向和竖向上的缩放比例
|
||||
double[] scaleX = new double[n];
|
||||
double[] scaleY = new double[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
scaleX[i] = distX[i] * scale;
|
||||
scaleY[i] = distY[i] * scale;
|
||||
}
|
||||
|
||||
// 将横向和竖向上的缩放比例分别乘以画布的宽度和高度,得到节点在画布上的实际坐标
|
||||
double[] x = new double[n];
|
||||
double[] y = new double[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
x[i] = centerX + (int)(scaleX[i] * 200);
|
||||
y[i] = centerY + (int)(scaleY[i] * 200);
|
||||
}
|
||||
|
||||
for (int i = 0; i < nodeSize; i++) {
|
||||
System.out.printf("NodeIndex %d: Position [%f%n,%f%n]", i, x[i], y[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据节点 PageRank 值计算节点坐标
|
||||
*
|
||||
* @param pageRank 节点 PageRank 值
|
||||
* @param canvasWidth 画布宽度
|
||||
* @param canvasHeight 画布高度
|
||||
* @return 节点坐标数组,每个点都是 (x, y) 形式
|
||||
*/
|
||||
public double[][] computeNodeCoordinates() {
|
||||
int n = pageRankVal.length;
|
||||
double[][] nodeCoords = new double[n][2];
|
||||
|
||||
double maxPageRank = Double.NEGATIVE_INFINITY;
|
||||
for (double x : pageRankVal) {
|
||||
maxPageRank = Math.max(maxPageRank, x);
|
||||
}
|
||||
|
||||
double centerX = width / 2.0;
|
||||
double centerY = height / 2.0;
|
||||
double radius = Math.min(centerX, centerY) - 50; // 保留一些边距避免节点被切掉
|
||||
for (int i = 0; i < n; i++) {
|
||||
double angle = 2 * Math.PI * i / n;
|
||||
double x = centerX + (pageRankVal[i] / maxPageRank) * radius * Math.cos(angle);
|
||||
double y = centerY + (pageRankVal[i] / maxPageRank) * radius * Math.sin(angle);
|
||||
nodeCoords[i][0] = x;
|
||||
nodeCoords[i][1] = y;
|
||||
}
|
||||
|
||||
return nodeCoords;
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 生成邻接矩阵
|
||||
int[][] matrix = {
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
PageRankLayout pageRankLayout = new PageRankLayout(matrix, 100);
|
||||
pageRankLayout.calculatePageRankVal();
|
||||
double[][] nodeCoords = pageRankLayout.computeNodeCoordinates();
|
||||
|
||||
// 输出每个节点在直角坐标系中的坐标
|
||||
for (int i = 0; i < nodeCoords.length; i++) {
|
||||
System.out.printf("(%.2f, %.2f)\n", nodeCoords[i][0], nodeCoords[i][1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -243,6 +243,15 @@ public class SubProcessWeb extends ActionWeb {
|
||||
return (JSONObject) JSON.toJSON(vertexPreHandle.collectIndependentNode(processIdList));
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成图
|
||||
* @param processIdJsonArr 选择的子流程
|
||||
* @param locationId 位置
|
||||
* @param direction 排布方向
|
||||
* @param modelName 总图名称
|
||||
* @param excludeProcessIdArr 过滤的子流程
|
||||
* @throws AWSException
|
||||
*/
|
||||
public void generatorEndToEndModel(String processIdJsonArr, String locationId, String direction, String modelName, String excludeProcessIdArr) throws AWSException{
|
||||
|
||||
// 忽略独立的节点
|
||||
@ -285,12 +294,58 @@ public class SubProcessWeb extends ActionWeb {
|
||||
CoeProcessLevelDaoFacotory.createCoeProcessLevel().insert(model);
|
||||
|
||||
GraphRender graphRender = new GraphRender(model, nodeList, graphLayout.getCanvasWidth(), graphLayout.getCanvasHeight());
|
||||
// 连线渲染
|
||||
graphRender.handShapeLinkerRender(linkers);
|
||||
|
||||
// 节点渲染
|
||||
graphRender.handleShapeNodeRender(position);
|
||||
// 连线渲染
|
||||
graphRender.handShapeLinkerRender(linkers);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void shapeNodeExpand(String repositoryId, String shapeId){
|
||||
|
||||
/*
|
||||
* 以当前节点展开涉及到动作拆分:
|
||||
*
|
||||
* 0、判断当前节点是否展开过了,初次展开的话去源文件中找,否则去备份的文件中找
|
||||
*
|
||||
* 1、准备范围限制框元素,该元素坐标与当前被展开的节点坐标一致,宽度与高度与子流程标识的模型画布-边距的宽度、高度一致
|
||||
* 同时,子流程标识的模型内的所有元素 以当前被展开的节点坐标为准,下移、右移 被展开节点坐标距离原点的距离
|
||||
*
|
||||
* 2、找到x大于等于、y大于等于当前被展开节点的所有子流程节点,将这些节点下移、右移到范围框之外
|
||||
*
|
||||
* 3、根据与当前节点的连线,找到总图中所有与当前被展开节点的相连的前置节点与后置节点
|
||||
*
|
||||
* 4、将子流程模型备份一份,为后续对展开后的节点做删除等操作
|
||||
*
|
||||
* */
|
||||
|
||||
// 获取子流程标识的文件存储信息
|
||||
List<DesignerShapeRelationModel> childProcessModelList = DesignerShapeRelationCache.getListByAttrId(repositoryId, shapeId, SubProcessConst.CHILD_PROCESS);
|
||||
DesignerShapeRelationModel relationModel = childProcessModelList.stream().findFirst().orElse(null);
|
||||
if (relationModel == null)
|
||||
throw new AWSException("未找到当前节点所标识的子流程文件信息");
|
||||
String relationFileId = relationModel.getRelationFileId();
|
||||
CoeDesignerAPIManager apiManager = CoeDesignerAPIManager.getInstance();
|
||||
BaseModel childProcessBaseModel = apiManager.getDefinition(relationFileId, 0);
|
||||
String childProcessDefinition = childProcessBaseModel.getDefinition();
|
||||
JSONObject childProcessDefineObj = JSONObject.parseObject(childProcessDefinition);
|
||||
JSONObject childProcessPage = childProcessDefineObj.getJSONObject("page");
|
||||
// 当前节点所标识的子流程文件的 画布宽度与高度 减去边距
|
||||
double childProcessPageWidth = childProcessPage.getDoubleValue("width") - childProcessPage.getDoubleValue("padding") * 2;
|
||||
double childProcessPageHeight = childProcessPage.getDoubleValue("height") - childProcessPage.getDoubleValue("padding") * 2;
|
||||
|
||||
// 获取总图的存储数据
|
||||
BaseModel baseModel = CoeDesignerAPIManager.getInstance().getDefinition(repositoryId, 0);
|
||||
String definition = baseModel.getDefinition();
|
||||
JSONObject defineJsonObj = JSONObject.parseObject(definition);
|
||||
JSONObject elements = defineJsonObj.getJSONObject("elements");
|
||||
JSONObject shapeObj = elements.getJSONObject(shapeId);
|
||||
JSONObject shapeProps = shapeObj.getJSONObject("props");
|
||||
// 当前节点的坐标
|
||||
double x = shapeProps.getDoubleValue("x");
|
||||
double y = shapeProps.getDoubleValue("y");
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -27,4 +27,8 @@
|
||||
<param name="modelName"/>
|
||||
<param name="excludeProcessIdArr"/>
|
||||
</cmd-bean>
|
||||
<cmd-bean name="com.actionsoft.apps.coe.method.process.subprocess.shape_expand">
|
||||
<param name="repositoryId"/>
|
||||
<param name="shapeId"/>
|
||||
</cmd-bean>
|
||||
</aws-actions>
|
||||
@ -47,6 +47,18 @@ public class CoeDesignerDefaultDao {
|
||||
return CoeDesignerConstant.ANSWER_SUCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储子流程文件信息
|
||||
* @param model
|
||||
* @param childProcessId
|
||||
* @param childProcessDefine
|
||||
*/
|
||||
public void storeChildProcess(BaseModel model, String childProcessId, String childProcessDefine){
|
||||
storer = new CoeDesignerFile(model);
|
||||
final CoeDesignerFile storerModel = storer;
|
||||
storerModel.store(childProcessId, childProcessDefine);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将操作记入日志
|
||||
*/
|
||||
@ -148,6 +160,24 @@ public class CoeDesignerDefaultDao {
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* 端到端功能
|
||||
* 获取与总图存放在一起的展开过的子流程模型信息
|
||||
* @param uuid
|
||||
* @param ver
|
||||
* @param childProcessId
|
||||
* @return
|
||||
*/
|
||||
public String get(String uuid, int ver, String childProcessId){
|
||||
BaseModel baseModel = CoeDesignerUtil.createModel(uuid, ver);
|
||||
storer = new CoeDesignerFile(baseModel);
|
||||
String define = storer.readChildProcessDefinition(childProcessId);
|
||||
if (UtilString.isEmpty(define)){
|
||||
return "";
|
||||
}
|
||||
return define;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Deprecated
|
||||
* @param model
|
||||
|
||||
@ -58,6 +58,23 @@ public class CoeDesignerFile {
|
||||
return JSONArray.parseArray(JSON.toJSONString(list));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存子流程文件
|
||||
* @param childProcessId
|
||||
* @param childProcessDefine
|
||||
* @throws AWSException
|
||||
*/
|
||||
public void store(String childProcessId, String childProcessDefine) throws AWSException{
|
||||
checkChildProcessFile(childProcessId);
|
||||
String childProcessPathName = getChildProcessPathName(childProcessId);
|
||||
UtilFile childProcessDefineFile = new UtilFile(childProcessPathName);
|
||||
try {
|
||||
childProcessDefineFile.write(childProcessDefine.getBytes("UTF8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new AWSException("子流程文件保存失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取define
|
||||
*
|
||||
@ -74,6 +91,22 @@ public class CoeDesignerFile {
|
||||
return define;
|
||||
}
|
||||
|
||||
/**
|
||||
* 端到端功能
|
||||
* 读取与总图存放在一起的展开过的子流程模型 define 信息
|
||||
* @param childProcessId
|
||||
* @return
|
||||
*/
|
||||
public String readChildProcessDefinition(String childProcessId){
|
||||
if (!childProcessIsExist(childProcessId)){
|
||||
return "";
|
||||
}
|
||||
String childProcessPath = getChildProcessPathName(childProcessId);
|
||||
UtilFile utilFile = new UtilFile(childProcessPath);
|
||||
String define = utilFile.readStrUTF8();
|
||||
return define;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取draw
|
||||
*
|
||||
@ -154,6 +187,26 @@ public class CoeDesignerFile {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 子流程文件不存在 创建
|
||||
* @param childProcessId
|
||||
* @throws AWSException
|
||||
*/
|
||||
protected void checkChildProcessFile(String childProcessId) throws AWSException{
|
||||
File dir = new File(model.getPath());
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
UtilFile utilFile = new UtilFile(getChildProcessPathName(childProcessId));
|
||||
if (!utilFile.exists()){
|
||||
try {
|
||||
utilFile.createNewFile();
|
||||
} catch (IOException e) {
|
||||
throw new AWSException("子流程文件创建失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件存放路径名
|
||||
*
|
||||
@ -168,6 +221,16 @@ public class CoeDesignerFile {
|
||||
return model.getPath() + model.getUUID() + _ver + type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 端到端功能
|
||||
* 获取与总图存放在一起的展开过的子流程模型信息
|
||||
* @param childProcessId
|
||||
* @return
|
||||
*/
|
||||
public String getChildProcessPathName(String childProcessId){
|
||||
return model.getPath() + childProcessId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件存放路径名
|
||||
*
|
||||
@ -195,6 +258,24 @@ public class CoeDesignerFile {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 端到端功能
|
||||
* 判断与总图存放在一起的展开过的子流程模型文件是否存在
|
||||
* @param childProcessId
|
||||
* @return
|
||||
*/
|
||||
public boolean childProcessIsExist(String childProcessId){
|
||||
File dir = new File(model.getPath());
|
||||
if (!dir.exists()){
|
||||
dir.mkdirs();
|
||||
}
|
||||
UtilFile utilFile = new UtilFile(getChildProcessPathName(childProcessId));
|
||||
if (!utilFile.exists()){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储日志文件
|
||||
*/
|
||||
|
||||
@ -22,6 +22,16 @@ public class CoeDesignerAPIManager {
|
||||
return new CoeDesignerDefaultDao().store(model);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储子流程模型信息
|
||||
* @param model
|
||||
* @param childProcessId
|
||||
* @param childProcessDefine
|
||||
*/
|
||||
public void storeChildProcessDefine(BaseModel model, String childProcessId, String childProcessDefine){
|
||||
new CoeDesignerDefaultDao().storeChildProcess(model, childProcessId, childProcessDefine);
|
||||
}
|
||||
|
||||
public int storeDefinitionOfBpmn(BPMNModel model) {
|
||||
return new BPMNDao().store(model);
|
||||
}
|
||||
@ -37,6 +47,10 @@ public class CoeDesignerAPIManager {
|
||||
|
||||
}
|
||||
|
||||
public String getChildProcessDefine(String uuid, int ver, String childProcessId){
|
||||
return new CoeDesignerDefaultDao().get(uuid, ver, childProcessId);
|
||||
}
|
||||
|
||||
public BPMNModel getDefinitionOfBpmn(String uuid, int ver) {
|
||||
return new BPMNDao().get(uuid, ver);
|
||||
}
|
||||
|
||||
@ -74,6 +74,7 @@
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="../commons/css/awsui.css">
|
||||
<link rel="stylesheet" href="../apps/com.actionsoft.apps.coe.pal/lib/designer/extend/css/subprocess/iconfont.css">
|
||||
<!-- <script src="../apps/com.actionsoft.apps.coe.pal/lib/designer/scripts/jquery.js"></script> -->
|
||||
<script type='text/javascript' src='../commons/js/jquery/scripts/jquery.js'></script>
|
||||
<script type="text/javascript" src="../commons/js/jquery/scripts/jquery-migrate.js"></script>
|
||||
@ -258,6 +259,7 @@
|
||||
<!--测试-->
|
||||
<!--<script type='text/javascript' charset='UTF-8' src='../apps/com.actionsoft.apps.coe.pal/lib/designer/scripts/diagraming/designer.core.debug.js'></script>-->
|
||||
<script type='text/javascript' charset='UTF-8' src='../apps/com.actionsoft.apps.coe.pal/lib/designer/scripts/diagraming/designer.methods.js'></script>
|
||||
<script type='text/javascript' charset='UTF-8' src='../apps/com.actionsoft.apps.coe.pal/lib/designer/scripts/diagraming/designer.method.subprocess.js'></script>
|
||||
<!--测试-->
|
||||
<!--<script type='text/javascript' charset='UTF-8' src='../apps/com.actionsoft.apps.coe.pal/lib/designer/scripts/diagraming/designer.methods.debug.js'></script>-->
|
||||
<script type='text/javascript' charset='UTF-8' src='../apps/com.actionsoft.apps.coe.pal/lib/designer/scripts/diagraming/designer.events.js'></script>
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 3589612 */
|
||||
src: url('iconfont.woff2?t=1684980356184') format('woff2'),
|
||||
url('iconfont.woff?t=1684980356184') format('woff'),
|
||||
url('iconfont.ttf?t=1684980356184') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-zhankaishousuo:before {
|
||||
content: "\e6cb";
|
||||
}
|
||||
|
||||
.icon-ICON-:before {
|
||||
content: "\e664";
|
||||
}
|
||||
|
||||
.icon-icon_list_shouqi:before {
|
||||
content: "\e61c";
|
||||
}
|
||||
|
||||
.icon-quanpingshouqi:before {
|
||||
content: "\e66f";
|
||||
}
|
||||
|
||||
.icon-shuzhuangtu_o:before {
|
||||
content: "\ebb3";
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,44 @@
|
||||
{
|
||||
"id": "3589612",
|
||||
"name": "炎黄",
|
||||
"font_family": "iconfont",
|
||||
"css_prefix_text": "icon-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "1057312",
|
||||
"name": "展开收缩",
|
||||
"font_class": "zhankaishousuo",
|
||||
"unicode": "e6cb",
|
||||
"unicode_decimal": 59083
|
||||
},
|
||||
{
|
||||
"icon_id": "1760316",
|
||||
"name": "收起",
|
||||
"font_class": "ICON-",
|
||||
"unicode": "e664",
|
||||
"unicode_decimal": 58980
|
||||
},
|
||||
{
|
||||
"icon_id": "14197982",
|
||||
"name": "收起",
|
||||
"font_class": "icon_list_shouqi",
|
||||
"unicode": "e61c",
|
||||
"unicode_decimal": 58908
|
||||
},
|
||||
{
|
||||
"icon_id": "29519761",
|
||||
"name": "全屏收起",
|
||||
"font_class": "quanpingshouqi",
|
||||
"unicode": "e66f",
|
||||
"unicode_decimal": 58991
|
||||
},
|
||||
{
|
||||
"icon_id": "5388006",
|
||||
"name": "树状图_o",
|
||||
"font_class": "shuzhuangtu_o",
|
||||
"unicode": "ebb3",
|
||||
"unicode_decimal": 60339
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,82 @@
|
||||
$(function(){
|
||||
if (methodId != 'process.subprocess') { // 如果当前打开的模型不是端到端总图 那么整个js也没有执行的必要
|
||||
return;
|
||||
}
|
||||
// 1. 子流程展开 事件:获取当前子流程所代表的模型文件
|
||||
(function (Model, ruuid, sid) {
|
||||
const subProcess = new SubProcess(Model, ruuid, sid);
|
||||
subProcess.shapeIconRender();
|
||||
|
||||
$('.shape_box.linker_box').css({
|
||||
'pointer-events': 'none'
|
||||
});
|
||||
|
||||
})(Model, ruuid, sid);
|
||||
});
|
||||
|
||||
class SubProcess {
|
||||
// 构造函数
|
||||
constructor(Model, ruuid, sid){
|
||||
this.Model = Model;
|
||||
this.repositoryId = ruuid;
|
||||
this.sid = sid;
|
||||
}
|
||||
|
||||
// 图形图标渲染 并绑定节点展开或者关闭事件
|
||||
shapeIconRender(){
|
||||
let elements = this.Model.define.elements;
|
||||
for (let shapeId in elements) {
|
||||
let shape = elements[shapeId];
|
||||
if (shape.name == 'linker') continue; // 当前元素为连线的话 直接略过
|
||||
if (shape.name == 'subProcess') { // 当前元素为子流程节点 渲染展开图标 并绑定展开事件
|
||||
let expandIcon = "<span id='icon_"+shapeId+"' class='iconfont icon-zhankaishousuo' style='position: absolute;cursor: pointer;'></span>";
|
||||
$('#'+shapeId).append(expandIcon);
|
||||
$('#icon_'+shapeId).on('click', '', {shapeId: shapeId, Model: this.Model, repositoryId: this.repositoryId, sid: this.sid}, this.shapeExpand);
|
||||
}else { // 当前元素为虚线范围限制框的话 渲染关闭图标 并绑定关闭事件
|
||||
let closeIcon = "<span id='icon_"+shapeId+"' class='iconfont icon-quanpingshouqi' style='position: absolute;cursor: pointer;'></span>";
|
||||
$('#'+shapeId).append(closeIcon);
|
||||
$('#icon_'+shapeId).on('click', '', {shapeId: shapeId, Model: this.Model, repositoryId: this.repositoryId, sid: this.sid}, this.shapeClose);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 节点展开事件
|
||||
shapeExpand(event){
|
||||
let param = event.data;
|
||||
alert('节点展开事件 ' + param.Model.define.elements[event.data.shapeId].text);
|
||||
// 1、同时只能支持一个子流程节点展开
|
||||
let elements = param.Model.define.elements;
|
||||
for (let key in elements) {
|
||||
let shape = elements[key];
|
||||
if (shape.name == 'linker') continue;
|
||||
if (shape.name == 'scopeLimitation') {
|
||||
$.simpleAlert("同一时间仅支持一个子流程节点展开", "warning");
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 2、传递当前模型文件ID、子流程节点ID
|
||||
awsui.ajax.request({
|
||||
url: './jd',
|
||||
method: 'POST',
|
||||
data: {
|
||||
cmd: 'com.actionsoft.apps.coe.method.process.subprocess.shape_expand',
|
||||
sid: param.sid,
|
||||
repositoryId: param.repositoryId,
|
||||
shapeId: param.shapeId
|
||||
},
|
||||
ok: function(r){
|
||||
console.log(r);
|
||||
},
|
||||
err: function(r){
|
||||
$.simpleAlert(r.msg);
|
||||
}
|
||||
});
|
||||
// 3、刷新当前画布
|
||||
}
|
||||
|
||||
// 节点关闭事件
|
||||
shapeClose(event){
|
||||
console.log('sss')
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user