FlowGraph.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.Runtime.Serialization;
  5. using System.Xml.Linq;
  6. using TeamAAS.FlowEditor.Execution;
  7. using TeamAAS.FlowEditor.Plugins;
  8. namespace TeamAAS.FlowEditor.Models
  9. {
  10. [Serializable]
  11. /// <summary>
  12. /// 流程图模型 - 管理节点和连线的集合
  13. /// </summary>
  14. public class FlowGraph : TeamAAS.BindableBase
  15. {
  16. /// <summary>
  17. /// 本流程绑定的执行结果注册表(主页面运行流程 = ResultRegistry.Main,编辑/调试流程 = ResultRegistry.Debug)。
  18. /// 运行态/编辑态各自独立,互不干扰;监控模式挂接运行态流程时自动指向主面对象。
  19. /// </summary>
  20. [Newtonsoft.Json.JsonIgnore]
  21. [field: NonSerialized]
  22. public ResultRegistry Registry { get; set; } = ResultRegistry.Debug;
  23. public string GraphId { get; set; } = System.Guid.NewGuid().ToString("N");
  24. public string GraphName
  25. {
  26. get => _graphName;
  27. set => SetProperty(ref _graphName, value);
  28. }
  29. private string _graphName = "新流程";
  30. public ObservableCollection<FlowNode> Nodes { get; set; } = new ObservableCollection<FlowNode>();
  31. public ObservableCollection<FlowConnection> Connections { get; set; } = new ObservableCollection<FlowConnection>();
  32. /// <summary>
  33. /// 添加节点
  34. /// </summary>
  35. public void AddNode(FlowNode node)
  36. {
  37. Nodes.Add(node);
  38. }
  39. /// <summary>
  40. /// 删除节点及其关联连线
  41. /// </summary>
  42. public void RemoveNode(string nodeId)
  43. {
  44. // 删除关联连线
  45. var connectionsToRemove = new List<FlowConnection>();
  46. foreach (var conn in Connections)
  47. {
  48. if (conn.SourceNodeId == nodeId || conn.TargetNodeId == nodeId)
  49. connectionsToRemove.Add(conn);
  50. }
  51. foreach (var conn in connectionsToRemove)
  52. Connections.Remove(conn);
  53. // 删除节点 + 清理 ResultRegistry 中的执行结果
  54. for (int i = Nodes.Count - 1; i >= 0; i--)
  55. {
  56. if (Nodes[i].NodeId == nodeId)
  57. {
  58. Registry?.RemoveNodeResult(GraphId, Nodes[i].NodeName);
  59. Nodes.RemoveAt(i);
  60. break;
  61. }
  62. }
  63. }
  64. /// <summary>
  65. /// 检查连线是否合法(不自连、非End下游、不重复、不成环)— 只检查不添加
  66. /// </summary>
  67. public bool CanConnect(FlowConnection connection)
  68. {
  69. // 不允许自连接
  70. if (connection.SourceNodeId == connection.TargetNodeId)
  71. return false;
  72. // 结束节点不允许添加下游连线
  73. var sourceNode = GetNode(connection.SourceNodeId);
  74. if (sourceNode != null && sourceNode.Category == NodeCategory.End)
  75. return false;
  76. // 检查重复 — 同一对节点之间不允许连线(双向检查,防止反向连接)
  77. foreach (var conn in Connections)
  78. {
  79. if ((conn.SourceNodeId == connection.SourceNodeId && conn.TargetNodeId == connection.TargetNodeId) ||
  80. (conn.SourceNodeId == connection.TargetNodeId && conn.TargetNodeId == connection.SourceNodeId))
  81. return false;
  82. }
  83. // 检查是否形成环(多级链路:A→B→C 后不允许 C→A)
  84. if (WouldCreateCycle(connection.SourceNodeId, connection.TargetNodeId))
  85. return false;
  86. return true;
  87. }
  88. /// <summary>
  89. /// 添加连线(自动检查重复和环)
  90. /// </summary>
  91. public bool TryAddConnection(FlowConnection connection)
  92. {
  93. if (!CanConnect(connection))
  94. return false;
  95. Connections.Add(connection);
  96. return true;
  97. }
  98. /// <summary>
  99. /// 删除连线
  100. /// </summary>
  101. public void RemoveConnection(string connectionId)
  102. {
  103. for (int i = Connections.Count - 1; i >= 0; i--)
  104. {
  105. if (Connections[i].ConnectionId == connectionId)
  106. {
  107. Connections.RemoveAt(i);
  108. break;
  109. }
  110. }
  111. }
  112. /// <summary>
  113. /// 检查添加连线后是否形成环
  114. /// </summary>
  115. private bool WouldCreateCycle(string sourceId, string targetId)
  116. {
  117. // 如果 target 能到达 source,则形成环
  118. return CanReach(targetId, sourceId, new HashSet<string>());
  119. }
  120. private bool CanReach(string fromId, string toId, HashSet<string> visited)
  121. {
  122. if (fromId == toId) return true;
  123. if (visited.Contains(fromId)) return false;
  124. visited.Add(fromId);
  125. foreach (var conn in Connections)
  126. {
  127. if (conn.SourceNodeId == fromId)
  128. {
  129. if (CanReach(conn.TargetNodeId, toId, visited))
  130. return true;
  131. }
  132. }
  133. return false;
  134. }
  135. /// <summary>
  136. /// 获取节点
  137. /// </summary>
  138. public FlowNode GetNode(string nodeId)
  139. {
  140. foreach (var node in Nodes)
  141. {
  142. if (node.NodeId == nodeId) return node;
  143. }
  144. return null;
  145. }
  146. }
  147. }