| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- 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
- {
- /// <summary>
- /// 普通节点属性的公式树数据源。基于当前选中节点 <see cref="PluginLoader.SelectFlow"/> 的上下文,
- /// 提供三类节点:全局变量(Gloab)、组合模块输入参数(输入)、当前流程所有前置节点输出结果。
- /// 自动处理「编辑组合模块内部节点」「编辑组合模块输出属性」「编辑主流程普通节点」三种场景。
- /// </summary>
- [Serializable]
- public class PluginDataProvider : IFormulaTreeProvider
- {
- /// <summary>
- /// 生成公式树节点列表,按 <see cref="PluginLoader.SelectFlow"/> 上下文过滤前置节点。
- /// </summary>
- public List<FormulaTreeNode> GetFormulaTree(PropertyItem propertyItem)
- {
- var nodes = new List<FormulaTreeNode>();
- try
- {
- Dictionary<string, Dictionary<string, object>> 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<string> 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<string>(flowResults.Keys);
- }
- else
- {
- visibleNodes = new HashSet<string>(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<string, Dictionary<string, Type>>();
- if (graph != null)
- {
- foreach (var n in graph.Nodes)
- {
- if (n?.PluginModel == null || !visibleNodes.Contains(n.NodeName)) continue;
- var dict = new Dictionary<string, Type>();
- 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<string, Type>();
- 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;
- }
- /// <summary>
- /// 构建「输入」参数公式树节点 — 从 <see cref="PluginLoader.ParentGroupModel"/> 的 ModuleInputs 反射读取。
- /// 用于组合模块内部节点属性编辑。
- /// </summary>
- 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<FormulaTreeNode>();
- 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 };
- }
- /// <summary>
- /// 在流程图中递归查找 GraphId 匹配的 SubGraph(支持嵌套组合模块)。
- /// </summary>
- 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;
- }
- /// <summary>
- /// 获取指定节点的所有前置节点名称(通过连接线反向 BFS 追溯)。
- /// </summary>
- private static HashSet<string> GetPredecessorNodeNames(FlowGraph graph, string nodeId)
- {
- var predecessorIds = new HashSet<string>();
- var queue = new Queue<string>();
- // 从直接上游开始
- 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<string>();
- foreach (var node in graph.Nodes)
- {
- if (predecessorIds.Contains(node.NodeId))
- result.Add(node.NodeName);
- }
- return result;
- }
- }
- }
|