| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- using PropertyGridLib.Controls;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading;
- using TeamAAS.FlowEditor.Execution;
- using TeamAAS.FlowEditor.Models;
- using TeamAAS.FlowEditor.Plugins;
- using Plugins.Standard.Models;
- using Plugins.Standard.Views;
- namespace Plugins.Standard
- {
- [Serializable]
- /// <summary>
- /// 组合模块插件 - 包含子流程,支持循环执行
- /// </summary>
- [Plugin("组合模块", PluginCategory.逻辑判断, typeof(GroupPluginModel), typeof(GroupEditorView),
- "FolderOutline",NodeShape = NodeCategory.Group, Description = "组合模块,包含子流程,支持循环执行")]
- public class GroupPlugin : BasePlugin<GroupPluginModel>
- {
- public override List<OutputField> DeclareOutputs()
- {
- var list = new List<OutputField>();
- if (Model?.ModuleOutputs != null)
- {
- foreach (var kv in Model.ModuleOutputs)
- {
- if (string.IsNullOrWhiteSpace(kv.OutName)) continue;
- list.Add(new OutputField(kv.OutName, kv.ResultType));
- }
- }
- list.Add(new OutputField("实际循环次数", typeof(int)));
- list.Add(new OutputField("循环设置", typeof(string)));
- list.Add(new OutputField("Message", typeof(string)));
- return list;
- }
- public override bool InitPlugin()
- {
- Model.EnsureSubGraph();
- return true;
- }
- [Newtonsoft.Json.JsonIgnore]
- public int CurrentCount { get; set; } = 0;
- public override NodeRunStatus PluginRun(CancellationToken token, out Dictionary<string, object> results)
- {
- results = new Dictionary<string, object>();
- Model.EnsureSubGraph();
- if (Model.LoopCount == 0)
- {
- Log(2, "循环次数为 0,跳过组合模块执行");
- return NodeRunStatus.Skipped;
- }
- Log(3, $"组合模块开始,循环设置={(Model.LoopCount == -1 ? "无限" : Model.LoopCount.ToString())},输入 {Model.ModuleInputs?.Count ?? 0} 个、输出 {Model.ModuleOutputs?.Count ?? 0} 个");
- Model.ModuleOutputs.ForEach(x => x.ResultList?.Clear());
- Model.IsBreakRequested = false;
- int maxLoops = Model.LoopCount == -1 ? int.MaxValue : Model.LoopCount;
- int actualLoops = 0;
- for (int i = 0; i < maxLoops; i++)
- {
- if (token.IsCancellationRequested)
- {
- break;
- }
- CurrentCount = i + 1;
- Log(4, $"第 {i + 1} 次循环开始");
- foreach (var node in Model.SubGraph.Nodes)
- {
- node.Status = NodeRunStatus.NotStarted;
- node.CostTime = 0;
- }
- // ResetAllNodes 会 ClearFlow 清掉子流程所有结果,
- // 所以输入必须在每次循环的 Reset 之后注册
- RegisterInputs();
- var executor = new FlowExecutor(Model.SubGraph) { SkipReset = true };
- executor.EndNodeEncountered += () =>
- {
- Model.IsBreakRequested = true;
- };
- executor.ExecuteAsync(token).Wait();
- actualLoops++;
- bool IsEnd = Model.IsBreakRequested || i == maxLoops - 1;
- SaveOutPut(ref results, IsEnd);
- if (Model.IsBreakRequested)
- {
- results["Message"] = $"第{i + 1}次循环时遇到结束节点";
- Log(2, $"第 {i + 1} 次循环遇到结束节点,跳出循环");
- break;
- }
- }
- results["实际循环次数"] = actualLoops;
- results["循环设置"] = Model.LoopCount == -1 ? "无限" : Model.LoopCount.ToString();
- if (token.IsCancellationRequested)
- {
- Log(1, $"组合模块被取消,已执行 {actualLoops} 次循环", TeamAAS.LogLevel.Warning);
- return NodeRunStatus.Failed;
- }
- Log(2, $"组合模块执行完成,实际循环 {actualLoops} 次");
- return NodeRunStatus.Success;
- }
- /// <summary>
- /// 将 ModuleInputs 映射到 ResultRegistry 子流程区域
- /// 内部节点通过 &{输入.变量名} 引用
- /// </summary>
- private void RegisterInputs()
- {
- if (Model?.ModuleInputs == null || Model.ModuleInputs.Count == 0) return;
- var subGraphId = Model.SubGraph.GraphId;
- var flowId = GetModel.FlowId;
- System.Diagnostics.Debug.WriteLine($"[GroupPlugin] RegisterInputs: flowId={flowId}, subGraphId={subGraphId}");
- foreach (var input in Model.ModuleInputs)
- {
- if (string.IsNullOrWhiteSpace(input.InputName)) continue;
- if (input.SourceValue == null) continue;
- object value = null;
- if (!string.IsNullOrWhiteSpace(input.SourceValue.Formula))
- {
- value = RegistryOrDebug.ResolveFormula(flowId, input.SourceValue.Formula);
- System.Diagnostics.Debug.WriteLine($"[GroupPlugin] {input.InputName} ← formula='{input.SourceValue.Formula}' → value={value} (null? {value == null})");
- }
- else
- {
- System.Diagnostics.Debug.WriteLine($"[GroupPlugin] {input.InputName} ← 无公式");
- }
- RegistryOrDebug.SetInputVariable(subGraphId, input.InputName, value);
- }
- RegistryOrDebug.GetFlowResults(subGraphId, out var after);
- System.Diagnostics.Debug.WriteLine($"[GroupPlugin] 验证子流程「输入」节点: " + (after.ContainsKey("输入") ? $"OK ({after["输入"].Count} vars)" : "MISSING!"));
- }
- public void SaveOutPut(ref Dictionary<string, object> results, bool IsEnd)
- {
- foreach (var kv in Model.ModuleOutputs)
- {
- if (kv.ResultList.Count == 0)
- {
- kv.ResultType = this.GetValue(kv.OutVale).GetType();
- }
- if (!kv.IsEndResult)//如果以列表形式输出,保存每次循环的结果
- {
- kv.ResultList.Add(GetValue(kv.OutVale));
- if (kv.ResultList.Count > kv.MaxResultNumber)
- {
- kv.ResultList = kv.ResultList.Skip(kv.ResultList.Count - kv.MaxResultNumber).ToList();
- }
- }
- if (IsEnd)
- {
- if (kv.IsEndResult)//如果是结束节点,保存输出
- {
- results.Add(kv.OutName, this.GetValue(kv.OutVale));
- }
- else
- {
- if (kv.ResultList.Count > 0)
- {
- // 方法:使用 Enumerable.Cast 的反射调用
- var castMethod = typeof(Enumerable)
- .GetMethod("Cast")
- .MakeGenericMethod(kv.ResultType);
- var casted = castMethod.Invoke(null, new object[] { kv.ResultList }); // 返回 IEnumerable<int>
- // 然后调用 ToList(也可用反射或直接转为 IEnumerable)
- var toListMethod = typeof(Enumerable)
- .GetMethod("ToList")
- .MakeGenericMethod(kv.ResultType);
- var result = toListMethod.Invoke(null, new object[] { casted }); // 返回 List<int>
- results.Add(kv.OutName, result);
- }
- else
- results.Add(kv.OutName, kv.ResultList);
- }
- }
- }
- }
- /// <summary>
- /// 通过公式获取节点执行结果值(优先从子流程节点本地读取)
- /// </summary>
- public new T GetValue<T>(FormulaBound<T> formula)
- {
- if (formula == null)
- return default(T);
- object _result = ResolveFromSubGraph(formula.Formula);
- if (_result == null || _result.ToString() == "")
- return formula.Value;
- if (_result is T typedResult)
- return typedResult;
- return (T)System.Convert.ChangeType(_result, typeof(T));
- }
- /// <summary>
- /// 从子流程节点本地解析 &{节点名.属性名},跨流程 &{流程名.节点名.属性名} 回退到 ResultRegistry
- /// </summary>
- private object ResolveFromSubGraph(string formula)
- {
- if (string.IsNullOrEmpty(formula)) return formula;
- var match2 = System.Text.RegularExpressions.Regex.Match(formula, @"^&\{(?<node>[^.}]+)\.(?<prop>[^.}]+)\}$");
- if (match2.Success)
- {
- var nodeName = match2.Groups["node"].Value;
- var propName = match2.Groups["prop"].Value;
- var node = Model.SubGraph?.Nodes?.FirstOrDefault(n => n.NodeName == nodeName);
- if (node?.RawResults != null && node.RawResults.TryGetValue(propName, out var val))
- return val;
- return null;
- }
- var match3 = System.Text.RegularExpressions.Regex.Match(formula, @"^&\{(?<flow>[^.}]+)\.(?<node>[^.}]+)\.(?<prop>[^.}]+)\}$");
- if (match3.Success)
- {
- return RegistryOrDebug.GetValue(
- match3.Groups["flow"].Value,
- match3.Groups["node"].Value,
- match3.Groups["prop"].Value);
- }
- return formula;
- }
- }
- }
|