Przeglądaj źródła

将生成流程图代码提取为一个公共类

luocaiyang 3 lat temu
rodzic
commit
4516de7fdb

+ 312 - 4
wispro.sp.api/Controllers/WorkflowEngineController.cs

@@ -60,7 +60,19 @@ namespace wispro.sp.api.Controllers
                     workflowObject.Workflow.CreateUserId = Context.Staffs.FirstOrDefault<Staff>(s => s.Name == User.Identity.Name).Id;
                     Context.Workflows.Add(workflowObject.Workflow);
 
+                    
+                    Context.SaveChanges();
+
+                    entity.workflowDefine.Step endStep = new entity.workflowDefine.Step() { 
+                        Name = "结束", 
+                        workflowId = workflowObject.Workflow.Id ,
+                    };
+                    Context.Steps.Add(endStep);
+                    Context.SaveChanges();
+
+                    workflowObject.Workflow.EndStepId = endStep.Id;
                     Context.SaveChanges();
+
                     t.Commit();
                 }
                 catch(Exception ex)
@@ -74,6 +86,87 @@ namespace wispro.sp.api.Controllers
             return ret;
         }
 
+        public ApiSaveResponse DeleteWorkflow(int workflowId)
+        {
+            ApiSaveResponse ret = new ApiSaveResponse();
+            ret.Success = true;
+
+            using (var t = Context.Database.BeginTransaction())
+            {
+                try
+                {
+                    var wInstanes = Context.WorkflowInstances.Where<WorkflowInstance>(w => w.workflowId == workflowId);
+                    if(wInstanes.Count() > 0)
+                    {
+                        ret.Success = false;
+                        ret.ErrorMessage = "流程已经使用,删除会影响到已有流程实例数据!";
+                        return ret;
+                    }
+                    else
+                    {
+                        var wf = Context.Workflows.FirstOrDefault(w=>w.Id == workflowId);
+                        if (wf != null)
+                        {
+                            entity.workflowDefine.Action  initAction = new entity.workflowDefine.Action() { Id = wf.InitActionId};
+                            var tfs = GetTrasfers(workflowId);
+                            var Actions = GetActions(workflowId);
+                            var Steps = GetSteps(workflowId);
+
+                            foreach (var tf in tfs)
+                            {
+                                Context.TrasferConditions.Remove(tf);
+                            }
+
+                            Context.SaveChanges();
+
+                            foreach (var action in Actions)
+                            {
+                                
+                                var ivSettings1 = Context.InputValueSettings.Where<entity.workflowDefine.InputValueSetting>(
+                                    s => s.actionId == action.Id).ToList();
+
+                                foreach(var iv in ivSettings1)
+                                {
+                                    Context.InputValueSettings.Remove(iv);
+                                }
+                                if (action.Id != wf.InitActionId)
+                                {
+
+                                    Context.Actions.Remove(action);
+                                }
+                                else
+                                {
+                                    initAction = action;
+                                }
+                                
+                            }
+                            Context.SaveChanges();
+
+                            foreach (var step in Steps)
+                            {
+                                Context.Steps.Remove(step);
+                            }
+                            Context.SaveChanges();
+
+                            Context.Workflows.Remove(wf);
+                            Context.Actions.Remove(initAction);
+
+                            Context.SaveChanges();
+                            t.Commit();
+                        }
+                    }
+                }
+                catch(Exception ex)
+                {
+                    t.Rollback();
+                    ret.Success = false;
+                    ret.ErrorMessage = ex.Message;
+                }
+            }
+
+            return ret;
+        }
+
         public ApiSaveResponse SaveStep(NewStepObject stepObj)
         {
             var ret = new ApiSaveResponse();
@@ -96,10 +189,54 @@ namespace wispro.sp.api.Controllers
                         Context.Steps.Add(step);
                         Context.SaveChanges();
 
-                        if (stepObj.isLastStep)
+                        if (stepObj.actions != null)
                         {
-                            wf.EndStepId = step.Id;
+                            foreach (var ac in stepObj.actions)
+                            {
+                                var temAc = Context.Actions.FirstOrDefault(a => a.Id == ac.Id);
+
+                                if (temAc == null)
+                                {
+                                    ac.StepId = step.Id;
+                                    Context.Actions.Add(ac);
+                                    Context.SaveChanges();
+                                }
+                                else
+                                {
+                                    temAc.Name = ac.Name;
+                                    temAc.InputForm = ac.InputForm;
+                                    temAc.OnActionObjectType = ac.OnActionObjectType;
+                                    temAc.StepId = ac.StepId;
+                                    Context.SaveChanges();
+                                }
+
+                                if (ac.inputValuesSettings != null)
+                                {
+                                    foreach (var iv in ac.inputValuesSettings)
+                                    {
+                                        var temIV = Context.InputValueSettings.FirstOrDefault(p => p.Id == iv.Id);
+                                        if (temIV == null)
+                                        {
+                                            iv.actionId = temAc.Id;
+                                            Context.InputValueSettings.Add(iv);
+                                            Context.SaveChanges();
+                                        }
+                                        else
+                                        {
+                                            temIV.actionId = temAc.Id;
+                                            temIV.bindField = iv.bindField;
+                                            temIV.bindFieldSavetoObjectCondition = iv.bindFieldSavetoObjectCondition;
+                                            temIV.DisplayName = iv.DisplayName;
+                                            temIV.Options = iv.Options;
+                                            temIV.ParentSettingId = iv.ParentSettingId;
+                                            temIV.valueType = iv.valueType;
+                                            Context.SaveChanges();
+                                        }
+                                    }
+                                }
+                            }
                         }
+                        
                     }
                     else
                     {
@@ -115,10 +252,52 @@ namespace wispro.sp.api.Controllers
                             temStep.stepType = step.stepType;
                             temStep.defaultResponseSetting = step.defaultResponseSetting;
 
-                            if (stepObj.isLastStep)
+                            foreach (var ac in stepObj.actions)
                             {
-                                wf.EndStepId = step.Id;
+                                var temAc = Context.Actions.FirstOrDefault(a => a.Id == ac.Id);
+
+                                if (temAc == null)
+                                {
+                                    ac.StepId = step.Id;
+                                    Context.Actions.Add(ac);
+                                    Context.SaveChanges();
+                                }
+                                else
+                                {
+                                    temAc.Name = ac.Name;
+                                    temAc.InputForm = ac.InputForm;
+                                    temAc.OnActionObjectType = ac.OnActionObjectType;
+                                    temAc.StepId = ac.StepId;
+                                    Context.SaveChanges();
+                                }
+
+                                if (ac.inputValuesSettings != null)
+                                {
+                                    foreach (var iv in ac.inputValuesSettings)
+                                    {
+                                        var temIV = Context.InputValueSettings.FirstOrDefault(p => p.Id == iv.Id);
+                                        if (temIV == null)
+                                        {
+                                            iv.actionId = temAc.Id;
+                                            Context.InputValueSettings.Add(iv);
+                                            Context.SaveChanges();
+                                        }
+                                        else
+                                        {
+                                            temIV.actionId = temAc.Id;
+                                            temIV.bindField = iv.bindField;
+                                            temIV.bindFieldSavetoObjectCondition = iv.bindFieldSavetoObjectCondition;
+                                            temIV.DisplayName = iv.DisplayName;
+                                            temIV.Options = iv.Options;
+                                            temIV.ParentSettingId = iv.ParentSettingId;
+                                            temIV.valueType = iv.valueType;
+                                            Context.SaveChanges();
+                                        }
+                                    }
+                                }
                             }
+
+                            
                         }
                         else
                         {
@@ -139,6 +318,129 @@ namespace wispro.sp.api.Controllers
 
             return ret;
         }
+        public ApiSaveResponse DeleteAction(int Id)
+        {
+            ApiSaveResponse ret = new ApiSaveResponse();
+            ret.Success = true;
+
+            using (var t = Context.Database.BeginTransaction())
+            {
+                try
+                {
+                    var action = Context.Actions.Where<entity.workflowDefine.Action>(w => w.Id == Id).FirstOrDefault();
+                    if (action != null)
+                    {
+                        var ivSettings1 = Context.InputValueSettings.Where<entity.workflowDefine.InputValueSetting>(
+                            s => s.actionId == action.Id).ToList();
+
+                        foreach (var iv in ivSettings1)
+                        {
+                            Context.InputValueSettings.Remove(iv);
+                        }
+
+                        Context.Actions.Remove(action);
+
+                        Context.SaveChanges();
+                        t.Commit();
+                    }
+                }
+                catch (Exception ex)
+                {
+                    t.Rollback();
+                    ret.Success = false;
+                    ret.ErrorMessage = ex.Message;
+                }
+            }
+
+            return ret;
+        }
+
+        public ApiSaveResponse DeleteTransfer(int Id)
+        {
+            ApiSaveResponse ret = new ApiSaveResponse();
+            ret.Success = true;
+
+            using (var t = Context.Database.BeginTransaction())
+            {
+                try
+                {
+                    Context.TrasferConditions.Remove(new entity.workflowDefine.TrasferCondition() { Id=Id });
+                    Context.SaveChanges();
+                    t.Commit();
+                }
+                catch (Exception ex) 
+                {
+                    t.Rollback();
+                    ret.Success = false;
+                    ret.ErrorMessage = ex.Message;
+                }
+            }
+
+            return ret;
+        }
+
+        public ApiSaveResponse DeleteStep(int Id)
+        {
+            ApiSaveResponse ret = new ApiSaveResponse();
+            ret.Success = true;
+
+            using (var t = Context.Database.BeginTransaction())
+            {
+                try
+                {
+                    var step = Context.Steps.FirstOrDefault(s=>s.Id == Id);
+
+                    if(step != null)
+                    {
+                        var Transfers = Context.TrasferConditions.Where<entity.workflowDefine.TrasferCondition>(t => t.StepId == step.Id || t.nextStepId == step.Id).ToList();
+                        if(Transfers != null)
+                        {
+                            foreach(var tf in Transfers)
+                            {
+                                Context.TrasferConditions.Remove(tf);
+                            }
+
+                            Context.SaveChanges();
+                        }
+
+                        var Actions = Context.Actions.Where<entity.workflowDefine.Action>(s => s.StepId == step.Id).ToList();
+
+                        if(Actions != null)
+                        {
+                            foreach(var ac in Actions)
+                            {
+                                foreach(var iv in Context.InputValueSettings.Where(p=>p.actionId== ac.Id).ToList())
+                                {
+                                    Context.InputValueSettings.Remove(iv);
+                                }
+                                
+
+                                Context.Actions.Remove(ac);
+                            }
+
+                            Context.SaveChanges();
+                        }
+
+                        Context.Steps.Remove(step);
+                        Context.SaveChanges();
+                    }
+
+
+
+
+
+                    t.Commit();
+                }
+                catch (Exception ex)
+                {
+                    t.Rollback();
+                    ret.Success = false;
+                    ret.ErrorMessage = ex.Message;
+                }
+            }
+
+            return ret;
+        }
 
         public ApiSaveResponse SaveAction(entity.workflowDefine.Action action)
         {
@@ -256,5 +558,11 @@ namespace wispro.sp.api.Controllers
             return Context.TrasferConditions.Where(d => d.Step.workflowId == workflowId || d.nextStep.workflowId == workflowId).ToList();
         }
 
+        public List<entity.workflowDefine.InputValueSetting>  getInputValueSteein(int actionId)
+        {
+            var retList=  Context.InputValueSettings.Where<entity.workflowDefine.InputValueSetting>(p => p.actionId == actionId).ToList();
+            return retList;
+        }
+
     }
 }

+ 2 - 0
wispro.sp.share/NewStepObject.cs

@@ -11,5 +11,7 @@ namespace wispro.sp.share
         public entity.workflowDefine.Step Step { get; set; }
 
         public bool isLastStep { get; set; }
+
+        public List<entity.workflowDefine.Action> actions { get; set; }
     }
 }

+ 757 - 0
wispro.sp.share/Utility/FlowChartUtility.cs

@@ -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>";
+        }
+    }
+}

+ 11 - 18
wispro.sp.web/Components/FlowChart.razor

@@ -1,7 +1,7 @@
 
-    @if (shapeTrees != null)
+    @if (flowChartUtility != null)
     {
-<svg width="@ChartWidth" height="@ChartHeight" id="FlowChartContainer">
+<svg width="@ChartWidth" height="@ChartHeight" id="FlowChartContainer" xmlns="http://www.w3.org/2000/svg">
     <defs>
         <marker id="idArrow"
                 viewBox="0 0 20 20" refX="0" refY="10"
@@ -15,27 +15,27 @@
     <text x="@(ChartWidth/2)" y="@(TitleHeight/2)" fill="black" alignment-baseline="middle" text-anchor="middle" font-size="30" font-weight="800">@workflow.Name</text>
 
     @{
-        dynamic startLine = GetStartInitLine();
+        dynamic startLine = flowChartUtility.GetStartInitLine();
         <line x1="@startLine.x1" y1="@startLine.y1 " x2="@startLine.x2" y2="@startLine.y2" stroke="black" stroke-width="2" marker-end="url(#idArrow)" />
 
     }
 
-    @for (int iLevel = 0; iLevel < LevelNodes.Count; iLevel++)
+    @for (int iLevel = 0; iLevel < flowChartUtility.LevelNodes.Count; iLevel++)
     {
-        @foreach (var node in LevelNodes[iLevel])
+        @foreach (var node in flowChartUtility.LevelNodes[iLevel])
         {
             if (node.Type == 0)
             {
                 <circle cx="@(node.x)" cy="@node.y" r="@(node.width / 2) " stroke="black" stroke-width="2" fill="@(node.FillColor)" />
                 <a>
                     <text x="@(node.x)" y="@node.y" fill="black" alignment-baseline="middle" text-anchor="middle" font-size="14">
-                        @if (node == startNode)
+                        @if (node == flowChartUtility.startNode)
                         {
                             @("开始")
                         }
                         else
                         {
-                            if (node == endNode)
+                            if (node == flowChartUtility.endNode)
                             {
                                 @("结束")
                             }
@@ -67,7 +67,7 @@
                         }
                     </text>
                 </a>
-                @if (SelectedShape == node)
+                @if (flowChartUtility.SelectedShape == node)
                 {
                     <circle cx="@(node.x - node.width / 2)" cy="@(node.y)" r="3" stroke="black" stroke-width="1" fill="white" />
                     <circle cx="@(node.x + node.width / 2)" cy="@(node.y)" r="3" stroke="black" stroke-width="1" fill="white" />
@@ -80,7 +80,7 @@
 
     @foreach (var t in Transfers)
     {
-        dynamic ret = GetLineParater(t);
+        dynamic ret = flowChartUtility.GetLineParater(t);
         <line x1="@ret.x1" y1="@ret.y1" x2="@ret.x2" y2="@ret.y2" stroke="black" stroke-width="2" marker-end="url(#idArrow)" />
 
         <circle cx="@((ret.x1 + ret.x2) / 2)" cy="@((ret.y1 + ret.y2) / 2)" r="7" stroke="black" stroke-width="1.5" fill="white" />
@@ -91,15 +91,8 @@
     }
 
 
-    @{
-        dynamic endLine = GetEndStepLine();
-        <line x1="@endLine.x1" y1="@endLine.y1" x2="@endLine.x2" y2="@endLine.y2" stroke="black" stroke-width="2" marker-end="url(#idArrow)" />
-    }
-
-    @*<circle cx="@(endNode.x)" cy="@endNode.y" r="@(endNode.width/2) " stroke="black" stroke-width="2" fill="gray" />
-        <a>
-            <text x="@(endNode.x)" y="@endNode.y" fill="black" alignment-baseline="middle" text-anchor="middle" font-size="5">结束</text>
-        </a>*@
+   
+    
 </svg>
     }
     else

+ 26 - 540
wispro.sp.web/Components/FlowChart.razor.cs

@@ -6,11 +6,13 @@ using System.Dynamic;
 using System.Linq;
 using System.Threading.Tasks;
 using wispro.sp.entity.workflowDefine;
+using wispro.sp.share.Utility;
 
 namespace wispro.sp.web.Components
 {
     public partial class FlowChart
     {
+        share.Utility.FlowChartUtility flowChartUtility;
         [Parameter]
         public double TitleHeight { get; set; } = 100;
 
@@ -50,532 +52,6 @@ namespace wispro.sp.web.Components
         [Parameter]
         public entity.workflowDefine.Workflow workflow { get; set; }
 
-        internal 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";
-
-        }
-
-        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);
-                }
-            }
-        }
-
-        shapeNode startNode;
-        shapeNode InitShape;
-        shapeNode endNode;
-        Dictionary<int, List<shapeNode>> LevelNodes = new Dictionary<int, List<shapeNode>>();
-
-        private void initShapeTree()
-        {
-            shapeTrees = new List<shapeNode>();
-            LevelNodes = new Dictionary<int, List<shapeNode>>();
-
-            startNode = new shapeNode()
-            {
-                //NodeObject = workflow.InitAction,
-                InCount = 0,
-                OutCount = 0,
-                width = 2 * initRadius,
-                height = 2 * initRadius,
-                Level = 0
-            };
-
-            
-            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);
-
-            endNode = new shapeNode()
-            {
-                InCount = 0,
-                OutCount = 0,
-                height = 2 * EndRadius,
-                width = 2 * EndRadius,
-                FillColor = EndShapColor
-            };
-
-            shapeTrees.Add(startNode);
-
-            //shapeTrees.Add(endNode);
-
-            #region 将步骤对象生成形状Node并添加到列表中
-            if (Steps == null || Steps.Count == 0 || (Steps.FirstOrDefault(s => s.Id == workflow.EndStepId) == null ))
-            {
-                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;
-            }
-
-            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 && workflow.EndStepId>0)
-                    {
-                        temNode.Childrens = new List<shapeNode>();
-                        temNode.Childrens.Add(endNode);
-                        endNode.Parents = new List<shapeNode>();
-                        endNode.Parents.Add(temNode);
-                    }
-
-                    shapeTrees.Add(temNode);
-                }
-            }
-
-            #endregion
-
-            #region 遍历转移条件,生成流程树
-            if (Transfers != null)
-            {
-                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;
-                }
-            }
-            #endregion
-
-            GetShapeLevelNodes(LevelNodes, shapeTrees);
-
-            #region 添加跨层连接的中间层的虚拟节点
-            //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)
-            //                {
-            //                    temNode.Childrens.Remove(temChildrenNode);
-            //                    temChildrenNode.Parents.Remove(temNode);
-
-            //                    var parentNode = temNode;
-
-            //                    for (int iLevel = temNode.Level + 1; iLevel < temChildrenNode.Level; iLevel++)
-            //                    {
-            //                        var xnNode = new shapeNode() { Type = 3, Parents = new List<shapeNode>(), Childrens = new List<shapeNode>() };
-            //                        parentNode.Childrens.Add(xnNode);
-            //                        xnNode.Parents = new List<shapeNode>();
-            //                        xnNode.Parents.Add(parentNode);
-            //                        parentNode = xnNode;
-            //                    }
-
-            //                    parentNode.Childrens.Add(temChildrenNode);
-            //                    temChildrenNode.Parents.Add(parentNode);
-            //                }
-            //            }
-            //        }
-            //    }
-            //}
-            #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 每层节点排序
-            // 2.1. sort out each layer by looking at where it connects from
-            for (var i = 1; i < LevelNodes.Count; ++i)
-            {
-                var top_layer = LevelNodes[i - 1];
-
-                LevelNodes[i] = LevelNodes[i].OrderBy(node =>
-                {
-                    // calculate average position based on connected nodes in top layer
-                    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();
-            }
-
-            // 2.2. now that all but the first layer are layed out, let's deal with the first
-            if (LevelNodes.Count > 1)
-            {
-                LevelNodes[0] = LevelNodes[0].OrderBy(node =>
-                {
-                    // calculate average position based on connected nodes in top layer
-                    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;
-            
-        }
-
         protected  override  void OnInitialized()
         {
             Refresh();
@@ -583,14 +59,24 @@ namespace wispro.sp.web.Components
 
         public void Refresh()
         {
-            //System.Text.Json.JsonSerializer.Serialize(Actions);
-            initShapeTree();
+            flowChartUtility = new share.Utility.FlowChartUtility();
+            flowChartUtility.workflow = workflow;
+            flowChartUtility.Actions = Actions;
+            flowChartUtility.Steps = Steps;
+            flowChartUtility.Transfers = Transfers;
+            flowChartUtility.hSeparation = hSeparation;
+            flowChartUtility.initRadius = initRadius;
+            flowChartUtility.EndShapColor = EndShapColor;
+            flowChartUtility.EndRadius = EndRadius;
+            flowChartUtility.ChartHeight = ChartHeight;
+            flowChartUtility.ChartWidth = ChartWidth;
+            flowChartUtility.rectHeight = rectHeight;
+            flowChartUtility.rectWidth = rectWidth;
+            flowChartUtility.Refresh();
+
             StateHasChanged();
         }
 
-        
-        
-
         void InitAction()
         {
 
@@ -615,11 +101,12 @@ namespace wispro.sp.web.Components
         [Parameter]
         public EventCallback<entity.workflowDefine.TrasferCondition> OnDoubleClickTransfer { get; set; }
 
-        private shapeNode SelectedShape;
+        public dynamic SelectedObject;
 
         void ClickNode(shapeNode node)
         {
-            SelectedShape = node;
+            SelectedObject = node.NodeObject;
+            flowChartUtility.SelectedShape = node;
             StateHasChanged();
 
             if (node.NodeObject is entity.workflowDefine.Step)
@@ -641,7 +128,8 @@ namespace wispro.sp.web.Components
 
         void DoubleClickNode(shapeNode node)
         {
-            SelectedShape = node;
+            SelectedObject = node.NodeObject;
+            flowChartUtility.SelectedShape = node;
             StateHasChanged();
             if (node.NodeObject is entity.workflowDefine.Step)
             {
@@ -663,7 +151,8 @@ namespace wispro.sp.web.Components
 
         void ClickTrasfer(entity.workflowDefine.TrasferCondition trasferCondition)
         {
-            SelectedShape = null;
+            SelectedObject = trasferCondition;
+            flowChartUtility.SelectedShape = null;
 
             if (OnClickTransfer.HasDelegate)
             {
@@ -673,7 +162,8 @@ namespace wispro.sp.web.Components
 
         void DoubleClickTrasfer(entity.workflowDefine.TrasferCondition trasferCondition)
         {
-            SelectedShape = null;
+            SelectedObject = trasferCondition;
+            flowChartUtility.SelectedShape = null;
 
             if (OnDoubleClickTransfer.HasDelegate)
             {
@@ -682,10 +172,6 @@ namespace wispro.sp.web.Components
         }
         #endregion
 
-        public string GetSvgString()
-        {
-            return null;
-        }
     }
 
 }

+ 13 - 9
wispro.sp.web/Components/UserConditionInput.razor.cs

@@ -51,17 +51,21 @@ namespace wispro.sp.web.Components
         protected async override Task OnInitializedAsync()
         {
             UserItems = new List<UserItem>();
-            string temString = wfService.GetBindObjectName(Workflow.ContentObjectType);
-            var dic = share.Utility.UserConditionHelper.GetPropertyDescription<Staff>(Workflow.ContentObjectType);
-            foreach(string key in dic.Keys)
+
+            if (!string.IsNullOrEmpty(Workflow.ContentObjectType))
             {
-                UserItems.Add(new UserItem()
+                string temString = wfService.GetBindObjectName(Workflow.ContentObjectType);
+                var dic = share.Utility.UserConditionHelper.GetPropertyDescription<Staff>(Workflow.ContentObjectType);
+                foreach (string key in dic.Keys)
                 {
-                    Value = dic[key].ToString(),
-                    Label = $"{temString}.{key}",
-                    UserType = UserType.BindObjectProperty,
-                    GroupName = temString //EnumHelper.GetDescription<UserType>(UserType.BindObjectProperty)
-                }) ;
+                    UserItems.Add(new UserItem()
+                    {
+                        Value = dic[key].ToString(),
+                        Label = $"{temString}.{key}",
+                        UserType = UserType.BindObjectProperty,
+                        GroupName = temString //EnumHelper.GetDescription<UserType>(UserType.BindObjectProperty)
+                    });
+                }
             }
 
             var actions =await wfService.GetActions(Workflow.Id);

+ 12 - 4
wispro.sp.web/Pages/Workflow/WorkflowDefine.razor.cs

@@ -97,7 +97,7 @@ namespace wispro.sp.web.Pages.Workflow
                     break;
                 }
             }
-            return (pageIndex - 1) * pageSize + iIndex;
+            return iIndex;
         }
 
         wispro.sp.entity.workflowDefine.Workflow SelectedWorkflow;
@@ -111,11 +111,19 @@ namespace wispro.sp.web.Pages.Workflow
             })
         };
 
-        void Delete(entity.workflowDefine.Workflow workflow)
+        async Task Delete(entity.workflowDefine.Workflow workflow)
         {
+            var ret = await workflowService.Delete(workflow.Id);
+
+            if (ret.Success)
+            {
+                workflows.Remove(workflow);
+            }
+            else
+            {
+                await _msgService.Error(ret.ErrorMessage);
+            }
             
-            workflows.Remove(workflow);
-            _total = workflows.Count;
         }
 
         void Detail(int Id)

+ 51 - 10
wispro.sp.web/Pages/Workflow/WorkflowDetail.razor

@@ -14,15 +14,29 @@
     <Content>
         <Space>
             <SpaceItem>
-                <Button Type="primary" Icon="plus" OnClick="AddNewStep" Style="float:right">添加步骤</Button>
+                <Button Type="primary" Icon="new" OnClick="AddNewStep">添加步骤</Button>
             </SpaceItem>
 
             <SpaceItem>
-                <Button Type="primary" Icon="plus" OnClick="AddNewAction" Style="float:right">添加操作</Button>
+                <Button Type="primary" Icon="new" OnClick="AddNewTransfer">添加步骤转移条件</Button>
             </SpaceItem>
-
-            <SpaceItem>
-                <Button Type="primary" Icon="plus" OnClick="AddNewTransfer" Style="float:right">添加步骤转移条件</Button>
+            
+            <SpaceItem Style="float:right">
+                <Space>
+                    <SpaceItem>
+                        <Button Type="primary" Icon="refresh" OnClick="OnRefresh">刷新</Button>
+                    </SpaceItem>
+                    <SpaceItem>
+                        <Popconfirm Title="您确认删除选中的对象?"
+                                    OnConfirm="DeleteObject"
+                                    OkText="Yes"
+                                    CancelText="No">
+                            <a>删除</a>
+                        </Popconfirm>
+                        @*<Button Danger Icon="delete" OnClick="DeleteObject" disabled="@(chart.SelectedObject != null)">删除</Button>*@
+                    </SpaceItem>
+                </Space>
+                
             </SpaceItem>
         </Space>
         
@@ -65,9 +79,36 @@
             <wispro.sp.web.Components.ResponseManCondition Workflow="workflow" UserField="userField"/>
         </FormItem>
 
-        <FormItem Label="最后步骤">
-            <Checkbox @bind-Value="context.isLastStep" />
-        </FormItem>
+        <div><Button Type="primary" Icon="plus" OnClick="AddNewAction" Style="float:right">添加操作</Button></div>
+        <AntDesign.Table TItem="wispro.sp.entity.workflowDefine.Action"                         
+                         DataSource="@EditStep.actions"
+                         Bordered=@true
+                         Size=@TableSize.Middle
+                         HidePagination
+                         Context="ss">
+            <ChildContent>
+                
+                <AntDesign.Column Title="名称" @bind-Field="@ss.Name" Sortable Filterable />
+                <AntDesign.Column Title="操作界面" @bind-Field="@ss.InputForm" Format="yyyy-MM-dd" Sortable Filterable />
+                <AntDesign.Column Title="所属步骤" TData="string">
+
+                    @if (context.Step.Name != null)
+                    {
+                        <span>@context.Step.Name</span>
+                    }
+
+                </AntDesign.Column>
+                <ActionColumn>
+                    <Space>
+                        <SpaceItem><Button OnClick="()=>BeginEditAction(ss.Id)">修改</Button></SpaceItem>
+                    </Space>
+                    <Space>
+                        <SpaceItem><Button Danger OnClick="()=>DeleteAction(ss.Id)">删除</Button></SpaceItem>
+                    </Space>
+                </ActionColumn>
+            </ChildContent>
+            
+        </AntDesign.Table>
     </Form>
 
 </Modal>
@@ -76,7 +117,7 @@
        Visible="@ActionModalShow"
        OnOk="@EditActionOK"
        OnCancel="@EditActionCancel"
-       OkText="@("保存")"
+       OkText="@("确定")"
        CancelText="@("取消")"
        Width="1000" MaskClosable="false">
 
@@ -95,7 +136,7 @@
                 AllowClear>
         </Select>
         </FormItem>
-        <FormItem Label="初始化操作名称">
+        <FormItem Label="操作名称">
             <Input @bind-Value="@EditAction.Name" />
         </FormItem>
         <FormItem Label="初始化界面">

+ 83 - 73
wispro.sp.web/Pages/Workflow/WorkflowDetail.razor.cs

@@ -17,6 +17,7 @@ namespace wispro.sp.web.Pages.Workflow
         List<entity.workflowDefine.Step> Steps;
         List<entity.workflowDefine.Action> Actions;
         List<entity.workflowDefine.TrasferCondition> Transfers;
+        List<InputValueSetting> inputValueSettings;
 
 
         UserField userField = new UserField();
@@ -43,64 +44,6 @@ namespace wispro.sp.web.Pages.Workflow
 
             #region Demo流程数据
             await InitData();
-
-            //在此处添加获取流程数据栏位
-
-
-            //workflow = new entity.workflowDefine.Workflow();
-            //workflow.Name = "请假流程";
-            //workflow.InitAction = new entity.workflowDefine.Action();
-            //workflow.InitAction.Name = "填写请假条";
-
-            //Steps = new List<entity.workflowDefine.Step>();
-            //var step1 = new entity.workflowDefine.Step();
-            //step1.Name = "部门主管申核";
-            //step1.Id = 1;
-            //Steps.Add(step1);
-
-            //var step2 = new entity.workflowDefine.Step();
-            //step2.Name = "总经理申核";
-            //step2.Id = 2;
-            //Steps.Add(step2);
-
-            //var step3 = new entity.workflowDefine.Step();
-            //step3.Name = "申核结果通知";
-            //step3.Id = 3;
-            //Steps.Add(step3);
-
-            //var step4 = new entity.workflowDefine.Step();
-            //step4.Name = "新步骤";
-            //step4.Id = 4;
-            //Steps.Add(step4);
-
-            //var step5 = new entity.workflowDefine.Step();
-            //step5.Name = "新步骤";
-            //step5.Id = 5;
-            //Steps.Add(step5);
-
-
-            //workflow.EndStepId = 3;
-
-            //Transfers = new List<entity.workflowDefine.TrasferCondition>();
-            //var t = new entity.workflowDefine.TrasferCondition();
-            //t.StepId = null;
-            //t.nextStepId = 1;
-            //Transfers.Add(t);
-
-            //var t1 = new entity.workflowDefine.TrasferCondition();
-            //t1.StepId = 1;
-            //t1.nextStepId = 2;
-            //Transfers.Add(t1);
-
-            //var t2 = new entity.workflowDefine.TrasferCondition();
-            //t2.StepId = 1;
-            //t2.nextStepId = 3;
-            //Transfers.Add(t2);
-
-            //var t3 = new entity.workflowDefine.TrasferCondition();
-            //t3.StepId = 2;
-            //t3.nextStepId = 3;
-            //Transfers.Add(t3);
             #endregion
         }
 
@@ -109,6 +52,7 @@ namespace wispro.sp.web.Pages.Workflow
         void OnClickStep(entity.workflowDefine.Step step)
         {
             //_msgService.Info($"您点击了:【{step.Name}】步骤");
+            
         }
 
         void OnDblClickStep(entity.workflowDefine.Step step)
@@ -122,6 +66,8 @@ namespace wispro.sp.web.Pages.Workflow
             catch {
                 userField = new UserField();
             }
+
+            EditStep.actions = GetActions(step.Id);
             //Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(EditStep));
             StepModalShow = true;
 
@@ -152,6 +98,7 @@ namespace wispro.sp.web.Pages.Workflow
             EditStep.Step = new entity.workflowDefine.Step() { Name = "新步骤", stepType = 2, workflowId = workflow.Id };
             EditStep.isLastStep = false;
             userField = new UserField();
+            newActions = new List<entity.workflowDefine.Action>();
 
             StepModalShow = true;
         }
@@ -165,29 +112,64 @@ namespace wispro.sp.web.Pages.Workflow
             ActionModalShow = true;
         }
 
+        async Task BeginEditAction(int Id)
+        {
+            EditAction = Actions.FirstOrDefault(a=>a.Id == Id);
+
+            if(EditAction != null)
+            {
+                if(EditAction.inputValuesSettings == null)
+                {
+                    EditAction.inputValuesSettings = await _wfService.getInputValueSteeing(EditAction.Id);
+                }
+                ActionModalShow = true;
+            }
+
+        }
+
+        async void DeleteAction(int Id)
+        {
+            var ret = await _wfService.DeleteAction(Id);
+
+            if (!ret.Success)
+            {
+                await _msgService.Error("删除Action出错!");
+            }
+            else
+            {
+                Actions = await _wfService.GetActions(workflow.Id);
+                EditStep.actions = GetActions(EditStep.Step.Id);
+            }
+        }
+
         void AddNewTransfer()
         {
             EditTransfer = new entity.workflowDefine.TrasferCondition();
-            
             TransferModalShow = true;
         }
+
+        List<entity.workflowDefine.Action> GetActions(int stepId)
+        {
+            return Actions.Where<entity.workflowDefine.Action>(a=>a.StepId == stepId).ToList();
+        }
+
         async Task EditStepOK()
         {
             Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(userField));
             EditStep.Step.defaultResponseSetting = System.Text.Json.JsonSerializer.Serialize(userField);
+            
             var ret = await _wfService.SaveStep(EditStep);
             if (ret.Success)
             {
                 StepModalShow = false;
                 await InitData();
-                chart.Refresh();
-                StateHasChanged();
-                
             }
             else
             {
                 await _msgService.Error("保存出现错误!");
             }
+
+            OnRefresh();
         }
 
         void EditStepCancel()
@@ -195,21 +177,25 @@ namespace wispro.sp.web.Pages.Workflow
             StepModalShow = false;
         }
 
+        List<entity.workflowDefine.Action> newActions;
         async Task EditActionOK()
         {
-            var ret =await _wfService.SaveAction(EditAction);
-            if (ret.Success)
+            if (EditStep != null)
             {
-                ActionModalShow = false;
-                await InitData();
-                chart.Refresh();
-                StateHasChanged();
-                
+                if (!EditStep.actions.Contains(EditAction))
+                {
+                    EditStep.actions.Add(EditAction);
+                }
             }
             else
             {
-                await _msgService.Error("保存出现错误!");
+                if(newActions == null)
+                {
+                    newActions.Add(EditAction);
+                }
             }
+
+            ActionModalShow = false;
         }
 
         void EditActionCancel()
@@ -217,7 +203,6 @@ namespace wispro.sp.web.Pages.Workflow
             ActionModalShow = false;
         }
 
-        int EditTransferStepId = 0;
         async Task EditTransferOK()
         {
             
@@ -234,13 +219,14 @@ namespace wispro.sp.web.Pages.Workflow
             {
                 TransferModalShow = false;
                 await InitData();
-                chart.Refresh();
-                StateHasChanged();
+                
                 
             }
             else {
                await _msgService.Error("保存出现错误!");
             }
+
+            OnRefresh();
         }
 
         void EditTransferCancel()
@@ -248,6 +234,30 @@ namespace wispro.sp.web.Pages.Workflow
             TransferModalShow = false;
         }
 
+        void OnRefresh()
+        {
+            chart.Refresh();
+        }
+
+        [Inject] ModalService _modalService { get; set; }
+        async Task DeleteObject()
+        {
+            if(chart.SelectedObject != null)
+            {
+                if(chart.SelectedObject is entity.workflowDefine.TrasferCondition)
+                {
+                    TrasferCondition transfer = chart.SelectedObject as TrasferCondition;
+                    await _wfService.DeleteTransfer(transfer);
+                }
+
+                if(chart.SelectedObject is entity.workflowDefine.Step)
+                {
+                    await _wfService.DeleteStep((entity.workflowDefine.Step)chart.SelectedObject);
+                }
+            }
 
+            await InitData();
+            chart.Refresh();
+        }
     }
 }

+ 30 - 0
wispro.sp.web/Services/WorkflowService.cs

@@ -102,10 +102,40 @@ namespace wispro.sp.web.Services
             return ret;
         }
 
+        public async Task<ApiSaveResponse> Delete(int id)
+        {
+            var ret = await _httpClient.Get<ApiSaveResponse>($"WorkflowEngine/DeleteWorkflow?workflowId={id}");
+            return ret;
+        }
+
         public async Task<ApiSaveResponse> SaveTransfer(entity.workflowDefine.TrasferCondition  trasfer)
         {
             var ret = await _httpClient.Post<ApiSaveResponse>("WorkflowEngine/SaveTransfer", trasfer);
             return ret;
         }
+
+        public async Task<ApiSaveResponse> DeleteAction(int id)
+        {
+            var ret = await _httpClient.Get<ApiSaveResponse>($"WorkflowEngine/DeleteAction?Id={id}");
+            return ret;
+        }
+
+        public async Task<List<InputValueSetting>> getInputValueSteeing(int actionId)
+        {
+            var ret = await _httpClient.Get<List<InputValueSetting>>($"WorkflowEngine/getInputValueSteein?actionId={actionId}");
+            return ret;
+        }
+
+        public async Task DeleteStep(Step selectedObject)
+        {
+            var ret = await _httpClient.Get<bool>($"WorkflowEngine/DeleteStep?Id={selectedObject.Id}");
+            //return ret;
+        }
+
+        public async Task DeleteTransfer(TrasferCondition transfer)
+        {
+            var ret = await _httpClient.Get<bool>($"WorkflowEngine/DeleteTransfer?Id={transfer.Id}");
+            //return ret;
+        }
     }
 }

+ 1 - 1
wispro.sp.web/wwwroot/index.html

@@ -225,7 +225,7 @@
     <script src="_content/AntDesign/js/ant-design-blazor.js"></script>
     <script src="_content/AntDesign.Charts/ant-design-charts-blazor.js"></script>
     <script src="_framework/blazor.webassembly.js"></script>
-    <script src="saveSvgAsPng.js"></script>
+    <!--<script src="saveSvgAsPng.js"></script>-->
 </body>
 
 </html>

+ 0 - 5
wispro.sp.web/wwwroot/saveSvgAsPng.js

@@ -1,9 +1,4 @@
 
-
-
-
-
-
 <!DOCTYPE html>
 <html lang="en" data-color-mode="auto" data-light-theme="light" data-dark-theme="dark">
   <head>

+ 0 - 498
wispro.sp.winClient/FlowChart.cs

@@ -1,498 +0,0 @@
-using Microsoft.AspNetCore.Components;
-using System;
-using System.Collections.Generic;
-using System.Dynamic;
-using System.Linq;
-using System.Threading.Tasks;
-
-namespace wispro.sp.winClient
-{
-    public partial class FlowChart
-    {
-        [Parameter]
-        public double TitleHeight { get; set; } = 100;
-
-
-        [Parameter]
-        public double ChartWidth { get; set; } = 1200;
-        [Parameter]
-        public double ChartHeight { get; set; } = 900;
-        [Parameter]
-        public double rectWidth { get; set; } = 150;
-
-        [Parameter]
-        public double rectHeight { get; set; } = 60;
-        [Parameter]
-        public double initRadius { get; set; } = 25;
-        [Parameter]
-        public double EndRadius { get; set; } = 25;
-        [Parameter]
-        public double hSeparation { get; set; } = 40;
-
-        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; }
-
-        internal 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; }
-
-        }
-
-        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);
-                }
-            }
-        }
-
-        shapeNode startNode;
-        shapeNode InitShape;
-        shapeNode endNode;
-        Dictionary<int, List<shapeNode>> LevelNodes = new Dictionary<int, List<shapeNode>>();
-
-        private void initShapeTree()
-        {
-            shapeTrees = new List<shapeNode>();
-            LevelNodes = new Dictionary<int, List<shapeNode>>();
-            startNode = new shapeNode()
-            {
-                //NodeObject = workflow.InitAction,
-                InCount = 0,
-                OutCount = 0,
-                width = 2 * initRadius,
-                height = 2 * initRadius,
-                Level = 0
-            };
-            InitShape = new shapeNode()
-            {
-                NodeObject = workflow.InitAction,
-                InCount = 0,
-                OutCount = 0,
-                Type = 1,
-                Level = 1
-            };
-
-            startNode.Childrens = new List<shapeNode>();
-            startNode.Childrens.Add(InitShape);
-
-            InitShape.Parents = new List<shapeNode>();
-            InitShape.Parents.Add(startNode);
-
-            endNode = new shapeNode()
-            {
-                InCount = 0,
-                OutCount = 0,
-                height = 2 * EndRadius,
-                width = 2 * EndRadius
-            };
-
-            shapeTrees.Add(startNode);
-            
-
-            #region 将步骤对象生成形状Node并添加到列表中
-            if (Steps == null || Steps.Count == 0 || Steps.FirstOrDefault(s => s.Id == workflow.EndStepId) == null)
-            {
-                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;
-            }
-            
-                foreach (var step in Steps)
-                {
-                    var temNode = new shapeNode() { NodeObject = step, InCount = 0, OutCount = 0, Type = 1 };
-
-                    if (workflow.EndStepId == step.Id)
-                    {
-                        temNode.Childrens = new List<shapeNode>();
-                        temNode.Childrens.Add(endNode);
-                        endNode.Parents = new List<shapeNode>();
-                        endNode.Parents.Add(temNode);
-                    }
-
-                    shapeTrees.Add(temNode);
-                }
-            #endregion
-
-            #region 遍历转移条件,生成流程树
-            if (Transfers != null)
-            {
-                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);
-                    }
-                }
-
-                endNode.Level = endNode.Parents[0].Level + 1;
-            }
-            #endregion
-
-
-
-            GetShapeLevelNodes(LevelNodes, shapeTrees);
-
-            #region 添加跨层连接的中间层的虚拟节点
-            //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)
-            //                {
-            //                    temNode.Childrens.Remove(temChildrenNode);
-            //                    temChildrenNode.Parents.Remove(temNode);
-
-            //                    var parentNode = temNode;
-
-            //                    for (int iLevel = temNode.Level + 1; iLevel < temChildrenNode.Level; iLevel++)
-            //                    {
-            //                        var xnNode = new shapeNode() { Type = 3, Parents = new List<shapeNode>(), Childrens = new List<shapeNode>() };
-            //                        parentNode.Childrens.Add(xnNode);
-            //                        xnNode.Parents = new List<shapeNode>();
-            //                        xnNode.Parents.Add(parentNode);
-            //                        parentNode = xnNode;
-            //                    }
-
-            //                    parentNode.Childrens.Add(temChildrenNode);
-            //                    temChildrenNode.Parents.Add(parentNode);
-            //                }
-            //            }
-            //        }
-            //    }
-            //}
-            #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 每层节点排序
-            // 2.1. sort out each layer by looking at where it connects from
-            for (var i = 1; i < LevelNodes.Count; ++i)
-            {
-                var top_layer = LevelNodes[i - 1];
-
-                LevelNodes[i] = LevelNodes[i].OrderBy(node =>
-                {
-                    // calculate average position based on connected nodes in top layer
-                    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();
-            }
-
-            // 2.2. now that all but the first layer are layed out, let's deal with the first
-            if (LevelNodes.Count > 1)
-            {
-                LevelNodes[0] = LevelNodes[0].OrderBy(node =>
-                {
-                    // calculate average position based on connected nodes in top layer
-                    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;
-
-            return ret;
-        }
-
-        public dynamic GetEndStepLine()
-        {
-            var 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;
-
-            return ret;
-        }
-
-        
-
-        public void Refresh()
-        {
-            System.Text.Json.JsonSerializer.Serialize(Actions);
-            initShapeTree();
-            
-        }
-
-        void ClickStep(entity.workflowDefine.Step step)
-        {
-
-        }
-
-        void ClickTrasfer(entity.workflowDefine.TrasferCondition trasferCondition)
-        {
-
-        }
-
-        void InitAction()
-        {
-
-        }
-
-        void ClickNode(shapeNode node)
-        {
-
-        }
-
-
-    }
-
-}

+ 42 - 69
wispro.sp.winClient/Form1.cs

@@ -16,6 +16,7 @@ using System.Threading.Tasks;
 using System.Windows.Forms;
 using wispro.sp.entity;
 using wispro.sp.share;
+using wispro.sp.share.Utility;
 using wispro.sp.utility;
 
 namespace wispro.sp.winClient
@@ -180,82 +181,29 @@ namespace wispro.sp.winClient
 
         private async void button3_Click(object sender, EventArgs e)
         {
-            share.Utility.UserConditionHelper.GetPropertyDescription<Staff>(typeof(PerformanceItem).AssemblyQualifiedName);
+            //share.Utility.UserConditionHelper.GetPropertyDescription<Staff>(typeof(PerformanceItem).AssemblyQualifiedName);
 
             #region Demo流程数据
-            //entity.workflowDefine.Workflow workflow = new entity.workflowDefine.Workflow();
-            //workflow.Name = "专案绩效流程";
-            //workflow.Id = 1;
-            //workflow.EndStepId = -1;
-
-            //workflow.InitAction = new entity.workflowDefine.Action();
-            //workflow.InitAction.Name = "填写请教条";
-
-            //List<entity.workflowDefine.Step> Steps = new List<entity.workflowDefine.Step>();
-            //var step1 = new entity.workflowDefine.Step();
-            //step1.Name = "部门主管申核";
-            //step1.Id = 1;
-            //Steps.Add(step1);
-
-            //var step2 = new entity.workflowDefine.Step();
-            //step2.Name = "老板申核";
-            //step2.Id = 2;
-            //Steps.Add(step2);
-
-            //var step3 = new entity.workflowDefine.Step();
-            //step3.Name = "申核结果通知";
-            //step3.Id = 3;
-            //Steps.Add(step3);
-
-            //var step4 = new entity.workflowDefine.Step();
-            //step4.Name = "新步骤";
-            //step4.Id = 4;
-            //Steps.Add(step4);
-
-            //var step5 = new entity.workflowDefine.Step();
-            //step5.Name = "新步骤";
-            //step5.Id = 5;
-            //Steps.Add(step5);
-
-
-            //workflow.EndStepId = 3;
-
-            //List<entity.workflowDefine.TrasferCondition> Transfers = new List<entity.workflowDefine.TrasferCondition>();
-            //var t = new entity.workflowDefine.TrasferCondition();
-            //t.StepId = null;
-            //t.nextStepId = 1;
-            //Transfers.Add(t);
-
-            //var t1 = new entity.workflowDefine.TrasferCondition();
-            //t1.StepId = 1;
-            //t1.nextStepId = 2;
-            //Transfers.Add(t1);
-
-            //var t2 = new entity.workflowDefine.TrasferCondition();
-            //t2.StepId = 1;
-            //t2.nextStepId = 3;
-            //Transfers.Add(t2);
-
-            //var t3 = new entity.workflowDefine.TrasferCondition();
-            //t3.StepId = 2;
-            //t3.nextStepId = 3;
-            //Transfers.Add(t3);
+            HttpClient http = new HttpClient();
+            int wfId = 5;
+            var workflow = await GetWorkflow(wfId, http);
+            var Steps = await GetSteps(wfId, http);
+            var Actions = await GetActions(wfId, http);
+            var Transfers = await GetTransfers(wfId,http);
             #endregion
-            //FlowChart flowChart = new FlowChart();
-            //flowChart.workflow = workflow;
-            //flowChart.Steps = Steps;
-            //flowChart.Transfers = Transfers;
+            FlowChartUtility flowChart = new FlowChartUtility();
+            flowChart.workflow = workflow;
+            flowChart.Steps = Steps;
+            flowChart.Transfers = Transfers;
 
-            //var newStep = new entity.workflowDefine.Step();
-            //newStep.Name = "新步骤";
-            //newStep.workflowId = workflow.Id;
-            //Steps.Add(newStep);
+            string strSvg = flowChart.GetSvgString();
+
+            var file = System.IO.File.CreateText("c:\\temp\\tem.svg");
+            file.WriteLine(strSvg);
+            file.Close();
 
-            //flowChart.Refresh();
 
-            //flowChart.Refresh();
 
-            
 
 
             //var test =wispro.sp.utility.EmunHelper.getEnumDescriptionDic<wispro.sp.entity.workflowDefine.LogicSymbols>();
@@ -728,6 +676,31 @@ namespace wispro.sp.winClient
             return retStr;
         }
 
+        public async Task<entity.workflowDefine.Workflow> GetWorkflow(int Id, HttpClient _httpClient)
+        {
+            var ret = await _httpClient.GetFromJsonAsync<entity.workflowDefine.Workflow>($"http://localhost:39476/api/WorkflowEngine/GetWorkflow?workflowId={Id}");
+
+            
+            return ret;
+        }
+
+        public async Task<List<entity.workflowDefine.Step>> GetSteps(int Id, HttpClient _httpClient)
+        {
+            var ret = await _httpClient.GetFromJsonAsync<List<entity.workflowDefine.Step>>($"http://localhost:39476/api/WorkflowEngine/GetSteps?workflowId={Id}");
+            return ret;
+        }
+
+        public async Task<List<entity.workflowDefine.Action>> GetActions(int workflowId, HttpClient _httpClient)
+        {
+            var ret = await _httpClient.GetFromJsonAsync<List<entity.workflowDefine.Action>>($"http://localhost:39476/api/WorkflowEngine/GetActions?workflowId={workflowId}");
+            return ret;
+        }
+
+        public async Task<List<entity.workflowDefine.TrasferCondition>> GetTransfers(int workflowId, HttpClient _httpClient)
+        {
+            var ret = await _httpClient.GetFromJsonAsync<List<entity.workflowDefine.TrasferCondition>>($"http://localhost:39476/api/WorkflowEngine/GetTrasfers?workflowId={workflowId}");
+            return ret;
+        }
         private async  Task SaveStaff(Staff obj)
         {
             HttpClient http = new HttpClient();