|
@@ -0,0 +1,757 @@
|
|
|
+using Microsoft.AspNetCore.Components;
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Dynamic;
|
|
|
+using System.Linq;
|
|
|
+using System.Text;
|
|
|
+using System.Threading.Tasks;
|
|
|
+
|
|
|
+namespace wispro.sp.share.Utility
|
|
|
+{
|
|
|
+ public class shapeNode
|
|
|
+ {
|
|
|
+ public int InCount { get; set; }
|
|
|
+
|
|
|
+ public int OutCount { get; set; }
|
|
|
+ public double x { get; set; }
|
|
|
+
|
|
|
+ public double y { get; set; }
|
|
|
+
|
|
|
+ public double width { get; set; }
|
|
|
+
|
|
|
+ public double height { get; set; }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 形状类型
|
|
|
+ /// 0:圆
|
|
|
+ /// 1:矩形
|
|
|
+ /// 3: 虚拟
|
|
|
+ /// </summary>
|
|
|
+ public int Type { get; set; }
|
|
|
+
|
|
|
+ public int Level { get; set; } = 1;
|
|
|
+
|
|
|
+ public dynamic NodeObject { get; set; }
|
|
|
+
|
|
|
+ public List<shapeNode> Childrens { get; set; }
|
|
|
+
|
|
|
+ public List<shapeNode> Parents { get; set; }
|
|
|
+
|
|
|
+ public string FillColor { get; set; } = "white";
|
|
|
+
|
|
|
+ }
|
|
|
+ public class FlowChartUtility
|
|
|
+ {
|
|
|
+ public double TitleHeight { get; set; } = 100;
|
|
|
+ public double ChartWidth { get; set; } = 1200;
|
|
|
+ public double ChartHeight { get; set; } = 900;
|
|
|
+ public double rectWidth { get; set; } = 150;
|
|
|
+ public double rectHeight { get; set; } = 60;
|
|
|
+ public double initRadius { get; set; } = 20;
|
|
|
+ public double EndRadius { get; set; } = 20;
|
|
|
+ public double hSeparation { get; set; } = 40;
|
|
|
+ public string StepShapeColor { get; set; } = "green";
|
|
|
+ public string EndShapColor { get; set; } = "gray";
|
|
|
+ int rectFontSize { get; set; } = 18;
|
|
|
+ public List<entity.workflowDefine.Step> Steps { get; set; }
|
|
|
+ public List<entity.workflowDefine.TrasferCondition> Transfers { get; set; }
|
|
|
+ public List<entity.workflowDefine.Action> Actions { get; set; }
|
|
|
+ public entity.workflowDefine.Workflow workflow { get; set; }
|
|
|
+
|
|
|
+ private List<shapeNode> shapeTrees = null;
|
|
|
+
|
|
|
+ private shapeNode FindNode(int stepId, out int Level, List<shapeNode> lstNodes)
|
|
|
+ {
|
|
|
+
|
|
|
+ Level = 1;
|
|
|
+ foreach (var sNode in lstNodes)
|
|
|
+ {
|
|
|
+ if (sNode.NodeObject is entity.workflowDefine.Step && sNode.NodeObject.Id == stepId)
|
|
|
+ {
|
|
|
+ return sNode;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (sNode.Childrens != null)
|
|
|
+ {
|
|
|
+ Level += 1;
|
|
|
+
|
|
|
+ var retObj = FindNode(stepId, out Level, sNode.Childrens);
|
|
|
+
|
|
|
+ if (retObj != null)
|
|
|
+ {
|
|
|
+ return retObj;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void GetShapeLevelNodes(Dictionary<int, List<shapeNode>> levelNodes, List<shapeNode> TreeNodes)
|
|
|
+ {
|
|
|
+ if (TreeNodes != null)
|
|
|
+ {
|
|
|
+ foreach (var sNode in TreeNodes)
|
|
|
+ {
|
|
|
+ List<shapeNode> nodes = new List<shapeNode>();
|
|
|
+ if (levelNodes.ContainsKey(sNode.Level))
|
|
|
+ {
|
|
|
+ nodes = levelNodes[sNode.Level];
|
|
|
+ nodes.Add(sNode);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ nodes.Add(sNode);
|
|
|
+ levelNodes.Add(sNode.Level, nodes);
|
|
|
+ }
|
|
|
+
|
|
|
+ GetShapeLevelNodes(levelNodes, sNode.Childrens);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public shapeNode startNode;
|
|
|
+ public shapeNode InitShape;
|
|
|
+ public shapeNode endNode;
|
|
|
+ public Dictionary<int, List<shapeNode>> LevelNodes = new Dictionary<int, List<shapeNode>>();
|
|
|
+
|
|
|
+ private void initShapeTree()
|
|
|
+ {
|
|
|
+ shapeTrees = new List<shapeNode>();
|
|
|
+ LevelNodes = new Dictionary<int, List<shapeNode>>();
|
|
|
+
|
|
|
+ #region 添加开始节点
|
|
|
+ startNode = new shapeNode()
|
|
|
+ {
|
|
|
+ //NodeObject = workflow.InitAction,
|
|
|
+ InCount = 0,
|
|
|
+ OutCount = 0,
|
|
|
+ width = 2 * initRadius,
|
|
|
+ height = 2 * initRadius,
|
|
|
+ Level = 0
|
|
|
+ };
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 添加初始化Action节点
|
|
|
+ InitShape = new shapeNode()
|
|
|
+ {
|
|
|
+ NodeObject = workflow.InitAction,
|
|
|
+ InCount = 0,
|
|
|
+ OutCount = 0,
|
|
|
+ Type = 1,
|
|
|
+ Level = 1,
|
|
|
+ FillColor = StepShapeColor
|
|
|
+ };
|
|
|
+
|
|
|
+ startNode.Childrens = new List<shapeNode>();
|
|
|
+ startNode.Childrens.Add(InitShape);
|
|
|
+
|
|
|
+ InitShape.Parents = new List<shapeNode>();
|
|
|
+ InitShape.Parents.Add(startNode);
|
|
|
+
|
|
|
+ shapeTrees.Add(startNode);
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 将步骤对象生成形状Node并添加到列表中
|
|
|
+
|
|
|
+
|
|
|
+ if (Steps != null)
|
|
|
+ {
|
|
|
+ foreach (var step in Steps)
|
|
|
+ {
|
|
|
+ var temNode = new shapeNode() { NodeObject = step, InCount = 0, OutCount = 0, Type = 1, FillColor = StepShapeColor };
|
|
|
+
|
|
|
+ if (workflow.EndStepId == step.Id)
|
|
|
+ {
|
|
|
+ endNode = new shapeNode()
|
|
|
+ {
|
|
|
+ NodeObject = step,
|
|
|
+ InCount = 0,
|
|
|
+ OutCount = 0,
|
|
|
+ height = 2 * EndRadius,
|
|
|
+ width = 2 * EndRadius,
|
|
|
+ FillColor = EndShapColor
|
|
|
+ };
|
|
|
+ temNode = endNode;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ shapeTrees.Add(temNode);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 遍历转移条件,生成流程树
|
|
|
+ if (Transfers != null && Transfers.Count > 0)
|
|
|
+ {
|
|
|
+ foreach (var transfer in Transfers)
|
|
|
+ {
|
|
|
+ var FromNode = InitShape;
|
|
|
+ int FromLevel = 0;
|
|
|
+
|
|
|
+ if (transfer.StepId != null)
|
|
|
+ {
|
|
|
+ FromNode = FindNode(transfer.StepId.Value, out FromLevel, shapeTrees);
|
|
|
+ }
|
|
|
+
|
|
|
+ int ToLevel = 0;
|
|
|
+ var ToNode = FindNode(transfer.nextStepId, out ToLevel, shapeTrees);
|
|
|
+
|
|
|
+ if (FromNode.Childrens == null)
|
|
|
+ {
|
|
|
+ FromNode.Childrens = new List<shapeNode>();
|
|
|
+ }
|
|
|
+ FromNode.Childrens.Add(ToNode);
|
|
|
+
|
|
|
+ if (ToNode.Parents == null)
|
|
|
+ {
|
|
|
+ ToNode.Parents = new List<shapeNode>();
|
|
|
+ }
|
|
|
+ ToNode.Parents.Add(FromNode);
|
|
|
+
|
|
|
+ FromNode.OutCount += 1;
|
|
|
+ ToNode.InCount += 1;
|
|
|
+
|
|
|
+ if (FromNode.Level >= ToLevel)
|
|
|
+ {
|
|
|
+ ToNode.Level = FromNode.Level + 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (shapeTrees.Contains(ToNode))
|
|
|
+ {
|
|
|
+
|
|
|
+ shapeTrees.Remove(ToNode);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (endNode.Parents != null && endNode.Parents[0].NodeObject is entity.workflowDefine.Step)
|
|
|
+ {
|
|
|
+ endNode.Level = endNode.Parents[0].Level + 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ InitShape.Childrens = new List<shapeNode>();
|
|
|
+ InitShape.Childrens.Add(endNode);
|
|
|
+ InitShape.OutCount += 1;
|
|
|
+ endNode.Parents = new List<shapeNode>();
|
|
|
+ endNode.Parents.Add(InitShape);
|
|
|
+ endNode.InCount += 1;
|
|
|
+ endNode.Level = InitShape.Level + 1;
|
|
|
+ //Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(endNode));
|
|
|
+
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ GetShapeLevelNodes(LevelNodes, shapeTrees);
|
|
|
+
|
|
|
+ #region 添加跨层连接的中间层的虚拟节点
|
|
|
+ List<dynamic> AddNodes = new List<dynamic>();
|
|
|
+ foreach (int level in LevelNodes.Keys)
|
|
|
+ {
|
|
|
+ foreach (var temNode in LevelNodes[level])
|
|
|
+ {
|
|
|
+ if (temNode.Childrens != null)
|
|
|
+ {
|
|
|
+ foreach (var temChildrenNode in temNode.Childrens)
|
|
|
+ {
|
|
|
+
|
|
|
+ if ((temChildrenNode.Level - temNode.Level) > 1)
|
|
|
+ {
|
|
|
+ dynamic temAddInfo = new ExpandoObject();
|
|
|
+ temAddInfo.Parent = temNode;
|
|
|
+ temAddInfo.Children = temChildrenNode;
|
|
|
+ temAddInfo.Start = temNode.Level;
|
|
|
+ temAddInfo.End = temChildrenNode.Level;
|
|
|
+ AddNodes.Add(temAddInfo);
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach (dynamic dynObj in AddNodes)
|
|
|
+ {
|
|
|
+ shapeNode parentNode = dynObj.Parent;
|
|
|
+ shapeNode endNode = dynObj.Children;
|
|
|
+
|
|
|
+ for (int i = dynObj.Start + 1; i < dynObj.End; i++)
|
|
|
+ {
|
|
|
+ var xnNode = new shapeNode() { Type = 3, Parents = new List<shapeNode>(), Childrens = new List<shapeNode>(), Level = i };
|
|
|
+ parentNode.Childrens.Add(xnNode);
|
|
|
+ xnNode.Parents.Add(parentNode);
|
|
|
+
|
|
|
+ parentNode.Childrens.Remove(endNode);
|
|
|
+ parentNode.Childrens.Add(xnNode);
|
|
|
+
|
|
|
+ endNode.Parents.Remove(parentNode);
|
|
|
+ endNode.Parents.Add(xnNode);
|
|
|
+ parentNode = xnNode;
|
|
|
+
|
|
|
+ LevelNodes[xnNode.Level].Add(xnNode);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ int MaxNodeLevel = 0;
|
|
|
+ int NodeCount = 0;
|
|
|
+
|
|
|
+ foreach (int level in LevelNodes.Keys)
|
|
|
+ {
|
|
|
+ if (level > 1)
|
|
|
+ {
|
|
|
+ int temLevelCount = 0;
|
|
|
+
|
|
|
+ foreach (var temNode in LevelNodes[level])
|
|
|
+ {
|
|
|
+ int graterInOrOut = (temNode.OutCount > temNode.InCount) ? temNode.OutCount : temNode.InCount;
|
|
|
+ if (graterInOrOut <= 1)
|
|
|
+ {
|
|
|
+ temLevelCount += 1;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ temLevelCount += graterInOrOut;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (temLevelCount > MaxNodeLevel)
|
|
|
+ {
|
|
|
+ MaxNodeLevel = level;
|
|
|
+ NodeCount = temLevelCount;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ #region 每层节点排序
|
|
|
+
|
|
|
+ for (var i = 1; i < LevelNodes.Count; ++i)
|
|
|
+ {
|
|
|
+ var top_layer = LevelNodes[i - 1];
|
|
|
+
|
|
|
+ LevelNodes[i] = LevelNodes[i].OrderBy(node =>
|
|
|
+ {
|
|
|
+ if (node.Parents == null)
|
|
|
+ {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ var connected_nodes = node.Parents
|
|
|
+ .Where(l => l.Level == (i - 1)).ToList();
|
|
|
+
|
|
|
+ if (!connected_nodes.Any())
|
|
|
+ {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ var average_index = connected_nodes.Select(cn => { var i = top_layer.IndexOf(cn); return i; }).Average();
|
|
|
+ return average_index;
|
|
|
+ }).ToList();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (LevelNodes.Count > 1)
|
|
|
+ {
|
|
|
+ LevelNodes[0] = LevelNodes[0].OrderBy(node =>
|
|
|
+ {
|
|
|
+ var connected_nodes = node.Childrens
|
|
|
+ .Where(l => l.Level == 1)
|
|
|
+ .ToList();
|
|
|
+
|
|
|
+ if (!connected_nodes.Any())
|
|
|
+ {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ var average_index = connected_nodes.Select(cn => { var i = LevelNodes[1].IndexOf(cn); return i; }).Average();
|
|
|
+ return average_index;
|
|
|
+ }).ToList();
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ ArrangeNodesInRows(LevelNodes);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private void ArrangeNodesInRows(Dictionary<int, List<shapeNode>> LevelNodes)
|
|
|
+ {
|
|
|
+ double preBotton = TitleHeight;
|
|
|
+ for (int iLevel = 0; iLevel < LevelNodes.Count; iLevel++)
|
|
|
+ {
|
|
|
+ int iCount = 0;
|
|
|
+ foreach (var node in LevelNodes[iLevel])
|
|
|
+ {
|
|
|
+ int max = (node.InCount > node.OutCount) ? node.InCount : node.OutCount;
|
|
|
+ if (max == 0)
|
|
|
+ {
|
|
|
+ max = 1;
|
|
|
+ }
|
|
|
+ iCount += max;
|
|
|
+ }
|
|
|
+
|
|
|
+ double onNodeWidth = ChartWidth / (iCount + 1);
|
|
|
+
|
|
|
+ iCount = 0;
|
|
|
+ double maxHeight = 0;
|
|
|
+ foreach (var node in LevelNodes[iLevel])
|
|
|
+ {
|
|
|
+
|
|
|
+
|
|
|
+ int max = (node.InCount > node.OutCount) ? node.InCount : node.OutCount;
|
|
|
+ if (max == 0)
|
|
|
+ {
|
|
|
+ max = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ node.x = onNodeWidth * (iCount + 1) + (max - 1) * onNodeWidth / 2;
|
|
|
+ if (node.Type == 0)
|
|
|
+ {
|
|
|
+ node.width = 2 * initRadius;
|
|
|
+ node.height = 2 * initRadius;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ node.width = rectWidth;
|
|
|
+ node.height = rectHeight;
|
|
|
+ }
|
|
|
+ iCount += max;
|
|
|
+
|
|
|
+ if (node.height > maxHeight)
|
|
|
+ {
|
|
|
+ maxHeight = node.height;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach (var node in LevelNodes[iLevel])
|
|
|
+ {
|
|
|
+ node.y = preBotton + hSeparation + maxHeight / 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ preBotton = preBotton + hSeparation + maxHeight;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public dynamic GetLineParater(entity.workflowDefine.TrasferCondition trasferCondition)
|
|
|
+ {
|
|
|
+ int level = 0;
|
|
|
+ var startNode = InitShape;
|
|
|
+ if (trasferCondition.StepId != null)
|
|
|
+ {
|
|
|
+ startNode = FindNode(trasferCondition.StepId.Value, out level, shapeTrees);
|
|
|
+ }
|
|
|
+ var endNode = FindNode(trasferCondition.nextStepId, out level, shapeTrees);
|
|
|
+
|
|
|
+ dynamic ret = new ExpandoObject();
|
|
|
+ ret.x1 = startNode.x;
|
|
|
+ ret.y1 = startNode.y + startNode.height / 2;
|
|
|
+
|
|
|
+ ret.x2 = endNode.x;
|
|
|
+ ret.y2 = endNode.y - endNode.height / 2;
|
|
|
+
|
|
|
+ double x3 = 0.0;
|
|
|
+ double y3 = 0.0;
|
|
|
+ GetArrorEndPoint(ret, out x3, out y3);
|
|
|
+
|
|
|
+ ret.x2 = x3;
|
|
|
+ ret.y2 = y3;
|
|
|
+
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void GetArrorEndPoint(dynamic ret, out double x3, out double y3)
|
|
|
+ {
|
|
|
+ if (ret.x1 == ret.x2)
|
|
|
+ {
|
|
|
+ x3 = ret.x1;
|
|
|
+ if (ret.y2 > ret.y1)
|
|
|
+ {
|
|
|
+ y3 = ret.y2 - 8;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ y3 = ret.y2 + 8;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (ret.y1 == ret.y2)
|
|
|
+ {
|
|
|
+ y3 = ret.y1;
|
|
|
+
|
|
|
+ if (ret.x1 < ret.x2)
|
|
|
+ {
|
|
|
+ x3 = ret.x2 - 8;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ x3 = ret.x2 + 8;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ double k = (ret.y1 - ret.y2) / (ret.x1 - ret.x2);
|
|
|
+ double b = ret.y2 - k * ret.x2;
|
|
|
+
|
|
|
+ double a = k * k + 1;
|
|
|
+ double B = 2 * k * (b - ret.y2) - 2 * ret.x2;
|
|
|
+ double c = (b - ret.y2) * (b - ret.y2) + ret.x2 * ret.x2 - 100;
|
|
|
+
|
|
|
+
|
|
|
+ double x3_1 = (Math.Sqrt(B * B - 4 * a * c) - B) / (2 * a);
|
|
|
+ double x3_2 = ((Math.Sqrt(B * B - 4 * a * c) + B) / (2 * a)) * -1;
|
|
|
+
|
|
|
+ if (ret.x1 < ret.x2)
|
|
|
+ {
|
|
|
+ x3 = (x3_1 < x3_2) ? x3_1 : x3_2;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ x3 = (x3_1 < x3_2) ? x3_2 : x3_1;
|
|
|
+ }
|
|
|
+
|
|
|
+ y3 = k * x3 + b;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public dynamic GetEndStepLine()
|
|
|
+ {
|
|
|
+ var startNode = InitShape;
|
|
|
+ if (endNode.Parents != null)
|
|
|
+ {
|
|
|
+ startNode = endNode.Parents[0];
|
|
|
+ }
|
|
|
+ dynamic ret = new ExpandoObject();
|
|
|
+ ret.x1 = startNode.x;
|
|
|
+ ret.y1 = startNode.y + startNode.height / 2;
|
|
|
+
|
|
|
+ ret.x2 = endNode.x;
|
|
|
+ ret.y2 = endNode.y - endNode.height / 2;
|
|
|
+
|
|
|
+ double x3 = 0.0;
|
|
|
+ double y3 = 0.0;
|
|
|
+ GetArrorEndPoint(ret, out x3, out y3);
|
|
|
+
|
|
|
+ ret.x2 = x3;
|
|
|
+ ret.y2 = y3;
|
|
|
+
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ public dynamic GetStartInitLine()
|
|
|
+ {
|
|
|
+ dynamic ret = new ExpandoObject();
|
|
|
+ ret.x1 = this.startNode.x;
|
|
|
+ ret.y1 = this.startNode.y + startNode.height / 2;
|
|
|
+
|
|
|
+ ret.x2 = InitShape.x;
|
|
|
+ ret.y2 = InitShape.y - InitShape.height / 2;
|
|
|
+
|
|
|
+ double x3 = 0.0;
|
|
|
+ double y3 = 0.0;
|
|
|
+ GetArrorEndPoint(ret, out x3, out y3);
|
|
|
+
|
|
|
+ ret.x2 = x3;
|
|
|
+ ret.y2 = y3;
|
|
|
+
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public void Refresh()
|
|
|
+ {
|
|
|
+ //System.Text.Json.JsonSerializer.Serialize(Actions);
|
|
|
+ initShapeTree();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ void InitAction()
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ #region 单击/双击事件
|
|
|
+ public EventCallback<entity.workflowDefine.Step> OnClickStep { get; set; }
|
|
|
+
|
|
|
+ public EventCallback<entity.workflowDefine.Action> OnClickAction { get; set; }
|
|
|
+
|
|
|
+ public EventCallback<entity.workflowDefine.TrasferCondition> OnClickTransfer { get; set; }
|
|
|
+
|
|
|
+ public EventCallback<entity.workflowDefine.Step> OnDoubleClickStep { get; set; }
|
|
|
+
|
|
|
+ [Parameter]
|
|
|
+ public EventCallback<entity.workflowDefine.Action> OnDoubleClickAction { get; set; }
|
|
|
+
|
|
|
+ [Parameter]
|
|
|
+ public EventCallback<entity.workflowDefine.TrasferCondition> OnDoubleClickTransfer { get; set; }
|
|
|
+
|
|
|
+ public shapeNode SelectedShape { get; set; }
|
|
|
+
|
|
|
+ void ClickNode(shapeNode node)
|
|
|
+ {
|
|
|
+ SelectedShape = node;
|
|
|
+
|
|
|
+ if (node.NodeObject is entity.workflowDefine.Step)
|
|
|
+ {
|
|
|
+ if (OnClickStep.HasDelegate)
|
|
|
+ {
|
|
|
+ OnClickStep.InvokeAsync((entity.workflowDefine.Step)node.NodeObject);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (node.NodeObject is entity.workflowDefine.Action)
|
|
|
+ {
|
|
|
+ if (OnClickAction.HasDelegate)
|
|
|
+ {
|
|
|
+ OnClickAction.InvokeAsync((entity.workflowDefine.Action)node.NodeObject);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void DoubleClickNode(shapeNode node)
|
|
|
+ {
|
|
|
+ SelectedShape = node;
|
|
|
+
|
|
|
+ if (node.NodeObject is entity.workflowDefine.Step)
|
|
|
+ {
|
|
|
+ if (OnDoubleClickStep.HasDelegate)
|
|
|
+ {
|
|
|
+ OnDoubleClickStep.InvokeAsync((entity.workflowDefine.Step)node.NodeObject);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (node.NodeObject is entity.workflowDefine.Action)
|
|
|
+ {
|
|
|
+ if (OnDoubleClickAction.HasDelegate)
|
|
|
+ {
|
|
|
+ OnDoubleClickAction.InvokeAsync((entity.workflowDefine.Action)node.NodeObject);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void ClickTrasfer(entity.workflowDefine.TrasferCondition trasferCondition)
|
|
|
+ {
|
|
|
+ SelectedShape = null;
|
|
|
+
|
|
|
+ if (OnClickTransfer.HasDelegate)
|
|
|
+ {
|
|
|
+ OnClickTransfer.InvokeAsync(trasferCondition);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void DoubleClickTrasfer(entity.workflowDefine.TrasferCondition trasferCondition)
|
|
|
+ {
|
|
|
+ SelectedShape = null;
|
|
|
+
|
|
|
+ if (OnDoubleClickTransfer.HasDelegate)
|
|
|
+ {
|
|
|
+ OnDoubleClickTransfer.InvokeAsync(trasferCondition);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ public string GetSvgString()
|
|
|
+ {
|
|
|
+ initShapeTree();
|
|
|
+ string strReturn = $"<svg width =\"{ChartWidth}\" height = \"{ChartHeight}\" id = \"FlowChartContainer\" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">";
|
|
|
+ strReturn = strReturn +
|
|
|
+ "<defs>\r\n" +
|
|
|
+ "\t<marker id =\"idArrow\" viewBox=\"0 0 20 20\" refX = \"0\" refY = \"10\" markerUnits = \"strokeWidth\" markerWidth = \"5\" markerHeight = \"10\" orient=\"auto\">\r\n" +
|
|
|
+ "\t\t<path d =\"M 0 0 L 20 10 L 0 20 z\" fill=\"black\" stroke = \"black\" />\r\n" +
|
|
|
+ "</marker>" +
|
|
|
+ "</defs>";
|
|
|
+
|
|
|
+ if (shapeTrees != null)
|
|
|
+ {
|
|
|
+ strReturn += $"<text x=\"{ChartWidth / 2}\" y=\"{TitleHeight / 2}\" fill=\"black\" alignment-baseline=\"middle\" text-anchor=\"middle\" font-size=\"{30}\" font-weight=\"800\">{workflow.Name}</text>\r\n";
|
|
|
+ dynamic startLine = GetStartInitLine();
|
|
|
+ strReturn += $"<line x1=\"{startLine.x1}\" y1=\"{startLine.y1}\" x2 =\"{startLine.x2}\" y2=\"{startLine.y2}\" stroke=\"black\" stroke-width=\"2\" marker-end=\"url(#idArrow)\"/>\r\n";
|
|
|
+
|
|
|
+ for (int iLevel = 0; iLevel < LevelNodes.Count; iLevel++)
|
|
|
+ {
|
|
|
+ foreach (var node in LevelNodes[iLevel])
|
|
|
+ {
|
|
|
+ if (node.Type == 0)
|
|
|
+ {
|
|
|
+ strReturn += $"<circle cx =\"{node.x}\" cy=\"{node.y}\" r=\"{node.width / 2}\" stroke=\"black\" stroke-width=\"2\" fill=\"{node.FillColor}\"/>\r\n";
|
|
|
+ strReturn += "<a>" +
|
|
|
+ $"<text x =\"{node.x}\" y=\"{node.y}\" fill=\"black\" alignment-baseline=\"middle\" text-anchor=\"middle\" font-size=\"14\">\r\n";
|
|
|
+ if (node == startNode)
|
|
|
+ {
|
|
|
+ strReturn += "开始";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (node == endNode)
|
|
|
+ {
|
|
|
+ strReturn += "结束";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (node.NodeObject is entity.workflowDefine.Step)
|
|
|
+ {
|
|
|
+ strReturn += ((entity.workflowDefine.Step)node.NodeObject).Name;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ strReturn += "</text>\r\n</a>\r\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ if (node.Type == 1)
|
|
|
+ {
|
|
|
+ strReturn += $"<rect x =\"{(node.x-node.width/2)}\" y=\"{(node.y-node.height/2)}\" rx=\"10\" ry=\"10\" width=\"{node.width}\" height=\"{node.height}\" style=\"fill:{node.FillColor};stroke:black;stroke-width:3;opacity:0.5\"/>\r\n";
|
|
|
+ strReturn += $"<a ondblclick =\"() => DoubleClickNode(node)\" onclick=\"()=>ClickNode(node)\">\r\n";
|
|
|
+ strReturn += $"<text x =\"{node.x}\" y=\"{node.y}\" fill=\"black\" alignment-baseline=\"middle\" text-anchor=\"middle\" font-size=\"{rectFontSize}\" font-weight=\"700\">\r\n";
|
|
|
+
|
|
|
+ if (node.NodeObject is entity.workflowDefine.Action)
|
|
|
+ {
|
|
|
+ strReturn += ((workflow.InitAction == null || string.IsNullOrEmpty(workflow.InitAction.Name)) ? $"启动{workflow.Name}" : workflow.InitAction.Name) + "\r\n";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ strReturn += (((entity.workflowDefine.Step)node.NodeObject).Name) + "\r\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ strReturn += "</text>\r\n</a>\r\n";
|
|
|
+
|
|
|
+ if (SelectedShape == node)
|
|
|
+ {
|
|
|
+ strReturn += $"<circle cx =\"{(node.x - node.width / 2)}\" cy=\"{(node.y)}\" r=\"3\" stroke=\"black\" stroke-width=\"1\" fill=\"white\"/>\r\n";
|
|
|
+ strReturn += $"<circle cx =\"{(node.x + node.width / 2)}\"cy=\"{(node.y)}\" r=\"3\" stroke=\"black\" stroke-width=\"1\" fill=\"white\"/>\r\n";
|
|
|
+ strReturn += $"<circle cx =\"{(node.x)}\" cy=\"{(node.y - node.height / 2)}\" r=\"3\" stroke=\"black\" stroke-width=\"1\" fill=\"white\"/>\r\n";
|
|
|
+ strReturn += $"<circle cx =\"{(node.x)}\" cy=\"{(node.y + node.height / 2)}\" r=\"3\" stroke=\"black\" stroke-width=\"1\" fill=\"white\"/>\r\n";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach (var t in Transfers)
|
|
|
+ {
|
|
|
+ dynamic ret = GetLineParater(t);
|
|
|
+
|
|
|
+ strReturn += $"<line x1 =\"{ret.x1}\" y1=\"{ret.y1}\" x2=\"{ret.x2}\" y2=\"{ret.y2}\" stroke=\"black\" stroke-width=\"2\" marker-end=\"url(#idArrow)\"/>\r\n";
|
|
|
+ strReturn += $"<circle cx =\"{((ret.x1 + ret.x2) / 2)}\" cy=\"{((ret.y1 + ret.y2) / 2)}\" r=\"7\" stroke=\"black\" stroke-width=\"1.5\" fill=\"white\"/>\r\n";
|
|
|
+ strReturn += $"<a ondblclick =\"() => DoubleClickTrasfer(t)\" onclick=\"()=>ClickTrasfer(t)\">\r\n";
|
|
|
+ strReturn += $"<text x =\"{((ret.x1 + ret.x2) / 2)}\" y=\"{((ret.y1 + ret.y2) / 2)}\" fill=\"black\" alignment-baseline=\"middle\" text-anchor=\"middle\" font-size=\"12\">c</text>\r\n";
|
|
|
+ strReturn += "</a>";
|
|
|
+ }
|
|
|
+
|
|
|
+ //dynamic endLine = GetEndStepLine();
|
|
|
+ //strReturn += $"<line x1 =\"{endLine.x1}\" y1=\"{endLine.y1}\" x2=\"{endLine.x2}\" y2=\"{endLine.y2}\" stroke=\"black\" stroke-width=\"2\" marker-end=\"url(#idArrow)\"/>\r\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ return strReturn + "</svg>";
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|