using HandyControl.Tools.Extension; using PropertyGridLib.Controls; using System; using System.Collections.Generic; using System.Linq; using TeamAAS.Communication; using TeamAAS.FlowEditor.Execution; using TeamAAS.FlowEditor.Models; using TeamAAS.FlowEngine; namespace TeamAAS.FlowEngine.FormulaData { /// /// 普通节点属性的公式树数据源。基于当前选中节点 的上下文, /// 提供三类节点:全局变量(Gloab)、组合模块输入参数(输入)、当前流程所有前置节点输出结果。 /// 自动处理「编辑组合模块内部节点」「编辑组合模块输出属性」「编辑主流程普通节点」三种场景。 /// [Serializable] public class PluginDataProvider : IFormulaTreeProvider { /// /// 生成公式树节点列表,按 上下文过滤前置节点。 /// public List GetFormulaTree(PropertyItem propertyItem) { var nodes = new List(); try { Dictionary> flowResults; string findId; string findName = PluginLoader.Instance.SelectFlow.NodeName; FlowGraph graph = null; if (PluginLoader.Instance.SetGroupPluginModel != null) { // 编辑组合模块内部节点 — 查 SubGraph 结果(所有节点均为前置,不做过滤) findId = PluginLoader.Instance.SetGroupPluginModel.GraphId; findName = PluginLoader.Instance.SetGroupPluginModel.GraphName; graph = PluginLoader.Instance.SetGroupPluginModel; } else if (PluginLoader.Instance.SelectFlow.ToolName == "组合模块") { // 编辑组合模块输出属性 — 查 SubGraph 结果,全部节点均为前置 findId = PluginLoader.Instance.SelectFlow.NodeId; } else { // 普通节点 — 查当前流程结果(key=GraphId) findId = PluginLoader.Instance.SelectFlow.FlowId; var tab = PluginLoader.Instance.FlowTabs.FirstOrDefault(t => t.Graph != null && t.Graph.GraphId == findId); graph = tab != null ? tab.Graph : null; // 回退查找:子节点的 FlowId 是 SubGraph 的 GraphId,不在 FlowTabs 中 if (graph == null) { foreach (var t in PluginLoader.Instance.FlowTabs) { if (t?.Graph == null) continue; graph = FindSubGraphById(t.Graph, findId); if (graph != null) break; } } } // 使用选中节点所属流程绑定的注册表(编辑态=Debug,监控态挂接运行图=Main) var registry = PluginLoader.Instance.SelectFlow?.Registry ?? ResultRegistry.Debug; registry.GetFlowResults(findId, out flowResults); // 可见节点名集合(绑定树的一级节点): // - 普通节点:反向追溯到的前置节点(即使尚未运行、registry 无结果也可见 → 支持“跑之前就能绑”) // - 编辑组合模块内部:全部子节点均为前置 // - 拿不到 graph 时:退回运行时结果键(保持旧行为) HashSet visibleNodes; if (PluginLoader.Instance.SetGroupPluginModel == null) { flowResults.DeleteIfExistsKey(findName); if (graph != null && PluginLoader.Instance.SelectFlow != null) visibleNodes = GetPredecessorNodeNames(graph, PluginLoader.Instance.SelectFlow.NodeId); else visibleNodes = new HashSet(flowResults.Keys); } else { visibleNodes = new HashSet(flowResults.Keys); if (graph != null) foreach (var n in graph.Nodes) if (!string.IsNullOrEmpty(n?.NodeName)) visibleNodes.Add(n.NodeName); } // 声明 schema:节点名 -> (输出键 -> 声明类型),取自各节点插件的 DeclareOutputs() var schemaByName = new Dictionary>(); if (graph != null) { foreach (var n in graph.Nodes) { if (n?.PluginModel == null || !visibleNodes.Contains(n.NodeName)) continue; var dict = new Dictionary(); try { foreach (var f in n.PluginModel.DeclareOutputs()) if (f != null && !string.IsNullOrEmpty(f.Key)) dict[f.Key] = f.ValueType; } catch { } schemaByName[n.NodeName] = dict; } } if (propertyItem.Value == null) propertyItem.Value = new object(); var targetType = propertyItem.Value.GetType(); var formulaType = propertyItem.PropertyType; foreach (var nodeName in visibleNodes) { if (string.IsNullOrEmpty(nodeName)) continue; flowResults.TryGetValue(nodeName, out var runtime); schemaByName.TryGetValue(nodeName, out var declared); // 合并“声明键 + 运行时键”;有效类型优先取运行时值类型,值为空则回退到声明类型 var merged = new Dictionary(); if (declared != null) foreach (var kv in declared) merged[kv.Key] = kv.Value; if (runtime != null) foreach (var kv in runtime) merged[kv.Key] = kv.Value != null ? kv.Value.GetType() : (merged.TryGetValue(kv.Key, out var dt) ? dt : null); var children = merged .Where(kv => targetType == null || targetType == typeof(object) || (kv.Value != null && (kv.Value == targetType || kv.Value == formulaType))) .Select(kv => new FormulaTreeNode { Header = kv.Key, Formula = $"&{{{nodeName}.{kv.Key}}}" }).ToList(); if (children.Count == 0) continue; nodes.Add(new FormulaTreeNode { Header = nodeName, Children = children }); } // ========== 全局变量节点 ========== try { registry.RefreshGlobalVariables(); var gloabNode = new FormulaTreeNode { Header = "Gloab", Children = GlobalVariableManager.Instance.Variables .Where(v => !string.IsNullOrWhiteSpace(v.Name)) .Select(v => new FormulaTreeNode { Header = v.Name, Formula = $"&{{Gloab.{v.Name}}}" }).ToList() }; if (gloabNode.Children.Count > 0) nodes.Insert(0, gloabNode); } catch { } // ========== 输入参数节点(组合模块内部) ========== try { if (PluginLoader.Instance.SetGroupPluginModel == null) { var inputsNode = BuildInputsNode(propertyItem); if (inputsNode != null && inputsNode.Children.Count > 0) nodes.Insert(0, inputsNode); } } catch { } } catch { } return nodes; } /// /// 构建「输入」参数公式树节点 — 从 的 ModuleInputs 反射读取。 /// 用于组合模块内部节点属性编辑。 /// private static FormulaTreeNode BuildInputsNode(PropertyItem propertyItem) { var parent = PluginLoader.Instance.ParentGroupModel; if (parent == null) return null; var moduleInputsProp = parent.GetType().GetProperty("ModuleInputs"); if (moduleInputsProp == null) return null; var inputs = moduleInputsProp.GetValue(parent) as System.Collections.IList; if (inputs == null || inputs.Count == 0) return null; var targetType = propertyItem?.Value?.GetType(); var formulaType = propertyItem?.PropertyType; var children = new List(); foreach (var item in inputs) { if (item == null) continue; var nameProp = item.GetType().GetProperty("InputName"); var dataTypeProp = item.GetType().GetProperty("DataType"); var inputName = nameProp?.GetValue(item) as string; var dataType = dataTypeProp?.GetValue(item) as string ?? ""; if (string.IsNullOrWhiteSpace(inputName)) continue; if (targetType != null && targetType != typeof(object) && !string.IsNullOrEmpty(dataType)) { try { var inputType = Type.GetType(dataType) ?? Type.GetType("System." + dataType + ", mscorlib"); if (inputType != null && inputType != typeof(object) && inputType != targetType && inputType != formulaType) continue; } catch { } } children.Add(new FormulaTreeNode { Header = string.IsNullOrEmpty(dataType) ? inputName : $"{inputName} ({dataType})", Formula = $"&{{输入.{inputName}}}" }); } if (children.Count == 0) return null; return new FormulaTreeNode { Header = "输入", Children = children }; } /// /// 在流程图中递归查找 GraphId 匹配的 SubGraph(支持嵌套组合模块)。 /// private static FlowGraph FindSubGraphById(FlowGraph parentGraph, string graphId) { foreach (var node in parentGraph.Nodes) { var model = node.PluginModel?.GetModel; if (model == null) continue; var graphProp = model.GetType().GetProperty("SubGraph"); if (graphProp != null) { var subGraph = graphProp.GetValue(model) as FlowGraph; if (subGraph != null) { if (subGraph.GraphId == graphId) return subGraph; var nested = FindSubGraphById(subGraph, graphId); if (nested != null) return nested; } } } return null; } /// /// 获取指定节点的所有前置节点名称(通过连接线反向 BFS 追溯)。 /// private static HashSet GetPredecessorNodeNames(FlowGraph graph, string nodeId) { var predecessorIds = new HashSet(); var queue = new Queue(); // 从直接上游开始 foreach (var conn in graph.Connections) { if (conn.TargetNodeId == nodeId) queue.Enqueue(conn.SourceNodeId); } while (queue.Count > 0) { var current = queue.Dequeue(); if (predecessorIds.Add(current)) { foreach (var conn in graph.Connections) { if (conn.TargetNodeId == current) queue.Enqueue(conn.SourceNodeId); } } } // NodeId -> NodeName var result = new HashSet(); foreach (var node in graph.Nodes) { if (predecessorIds.Contains(node.NodeId)) result.Add(node.NodeName); } return result; } } }