From 74961fa2c4d86a9f5732b5d9ff1020df9d970d99 Mon Sep 17 00:00:00 2001
From: fengjiayi <12821976+ning_xi@user.noreply.gitee.com>
Date: Mon, 28 Jul 2025 17:38:51 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B5=81=E7=A8=8B=E4=B8=8A=E4=B8=8B=E6=96=87?=
=?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=E8=B0=83=E7=94=A8=E4=BF=A1=E6=81=AF?=
=?UTF-8?q?=E8=AE=B0=E5=BD=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Library/Api/IFlowContext.cs | 195 +++++++++++++++++-
Library/Api/IFlowEnvironment.cs | 8 +-
Library/Api/INodeContainer.cs | 2 +
Library/Extension/FlowModelExtension.cs | 56 ++++-
Library/FlowNode/FlowContext.cs | 106 +++++-----
.../FlowNode/LightweightFlowEnvironment.cs | 1 -
Library/FlowNode/ParameterDetails.cs | 22 +-
Library/Utils/BenchmarkHelpers.cs | 34 +--
NodeFlow/Env/FlowControl.cs | 9 +-
NodeFlow/Env/FlowEdit.cs | 4 +-
NodeFlow/Env/FlowEnvironment.cs | 24 +--
NodeFlow/Model/Node/NodeModelBaseFunc.cs | 2 -
NodeFlow/Model/Node/SingleGlobalDataNode.cs | 9 +-
.../Operation/ContainerPlaceNodeOperation.cs | 28 ++-
.../ContainerTakeOutNodeOperation.cs | 26 ++-
NodeFlow/Services/FlowWorkManagement.cs | 65 +++++-
Workbench/Node/NodeControlBase.cs | 2 +-
Workbench/Node/View/GlobalDataControl.xaml | 2 +-
Workbench/Node/View/GlobalDataControl.xaml.cs | 4 +
Workbench/Services/FlowNodeService.cs | 6 +-
Workbench/Views/BaseNodesView.xaml | 2 +-
Workbench/Views/FlowCanvasView.xaml.cs | 17 +-
22 files changed, 480 insertions(+), 144 deletions(-)
diff --git a/Library/Api/IFlowContext.cs b/Library/Api/IFlowContext.cs
index 116d95d..fe35e20 100644
--- a/Library/Api/IFlowContext.cs
+++ b/Library/Api/IFlowContext.cs
@@ -2,6 +2,9 @@
using Serein.Library.Utils;
using System;
using System.Collections.Generic;
+using System.Data.Common;
+using System.Globalization;
+using System.Linq;
using System.Threading.Tasks;
namespace Serein.Library.Api
@@ -11,6 +14,12 @@ namespace Serein.Library.Api
///
public interface IFlowContext
{
+ ///
+ /// 是否记录流程信息
+ ///
+ bool IsRecordInvokeInfo { get; set; }
+
+
///
/// 标识流程
///
@@ -39,6 +48,19 @@ namespace Serein.Library.Api
Exception ExceptionOfRuning { get; set; }
+ ///
+ /// 获取当前流程上下文的所有节点调用信息,包含每个节点的执行时间、调用类型、执行状态等。
+ ///
+ ///
+ List GetAllInvokeInfos();
+
+
+ ///
+ /// 新增当前流程上下文的节点调用信息。
+ ///
+ FlowInvokeInfo NewInvokeInfo(IFlowNode previousNode, IFlowNode theNode, FlowInvokeInfo.InvokeType invokeType);
+
+
///
/// 获取节点的运行时参数数据
///
@@ -107,5 +129,176 @@ namespace Serein.Library.Api
/// 用以提前结束当前上下文流程的运行
///
void Exit();
- }
+ }
+
+
+ ///
+ /// 流程调用信息,记录每个节点的调用信息,包括执行时间、调用类型、执行状态等。
+ ///
+ public sealed class FlowInvokeInfo
+ {
+ ///
+ /// 调用类型枚举,指示节点的调用方式。
+ ///
+ public enum InvokeType
+ {
+ ///
+ /// 初始化。
+ ///
+ None = -1,
+ ///
+ /// 上游分支调用,指向上游流程的节点。
+ ///
+ Upstream = 0,
+ ///
+ /// 真分支调用,指示节点执行成功后的分支。
+ ///
+ IsSucceed = 1,
+ ///
+ /// 假分支调用,指示节点执行失败后的分支。
+ ///
+ IsFail = 2,
+ ///
+ /// 异常发生分支调用,指示节点执行过程中发生异常后的分支。
+ ///
+ IsError = 3,
+ ///
+ /// 参数来源调用,标明此次调用出自其它节点需要参数时的执行。
+ ///
+ ArgSource = 4,
+ }
+
+ ///
+ /// 运行状态枚举,指示节点的执行结果。
+ ///
+ public enum RunState
+ {
+ ///
+ /// 初始化
+ ///
+ None = -1,
+ ///
+ /// 正在运行,指示节点正在执行中。
+ ///
+ Running = 0,
+ ///
+ /// 执行成功,指示节点执行完成且结果正常。
+ ///
+ Succeed = 1,
+ ///
+ /// 执行失败,指示节点执行完成但结果异常或不符合预期。
+ ///
+ Failed = 2,
+ ///
+ /// 执行异常,指示节点在执行过程中发生了未处理的异常。
+ ///
+ Error = 3,
+ }
+
+ ///
+ /// 流程上下文标识符,唯一标识一个流程上下文
+ ///
+ public string ContextGuid { get; set; }
+
+ ///
+ /// 节点执行信息标识符,唯一标识一个节点执行信息
+ ///
+ public long Id { get; set; }
+
+ ///
+ /// 上一节点的唯一标识符,指向流程图中的上一个节点
+ ///
+ public string PreviousNodeGuid { get; set; }
+
+ ///
+ /// 节点唯一标识符,指向流程图中的节点
+ ///
+ public string NodeGuid { get; set; }
+
+ ///
+ /// 执行时间,记录节点执行的时间戳
+ ///
+ public DateTime StateTime { get; } = DateTime.Now;
+
+ ///
+ /// 节点调用类型,指示节点的调用方式
+ ///
+ public InvokeType Type { get; set; }
+
+
+
+ ///
+ /// 节点方法名称,指示节点执行的方法
+ ///
+ public string Method { get; set; }
+
+ ///
+ /// 节点执行状态,指示节点的执行结果
+ ///
+ public RunState State { get; set; }
+
+ ///
+ /// 耗时,记录节点执行的耗时(单位:毫秒)
+ ///
+ public TimeSpan TS { get; private set; } = TimeSpan.Zero;
+
+ ///
+ /// 节点参数,存储节点执行时的参数信息
+ ///
+ public string[] Parameters { get; private set; }
+
+ ///
+ /// 节点执行结果,存储节点执行后的结果信息
+ ///
+ public string Result { get; private set; }
+
+ public void UploadState(RunState runState)
+ {
+ State = runState;
+ TS = DateTime.Now - StateTime;
+ }
+ public void UploadResultValue(object value = null)
+ {
+ if(value is null)
+ {
+ Result = string.Empty;
+ }
+ else
+ {
+ Result = value.ToString();
+ }
+ }
+ public void UploadParameters(object[] values = null)
+ {
+ if (values is null)
+ {
+ Parameters = [];
+
+ }
+ else
+ {
+ Parameters = values.Select(v => v.ToString()).ToArray();
+ }
+ }
+
+ public override string ToString()
+ {
+ return $"[{State}]{TS.TotalSeconds:0.000}ms : {Result}";
+ }
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
}
+
+
diff --git a/Library/Api/IFlowEnvironment.cs b/Library/Api/IFlowEnvironment.cs
index fe5e0ba..d8eaa04 100644
--- a/Library/Api/IFlowEnvironment.cs
+++ b/Library/Api/IFlowEnvironment.cs
@@ -414,10 +414,11 @@ namespace Serein.Library.Api
///
public class NodeTakeOutEventArgs : FlowEventArgs
{
- public NodeTakeOutEventArgs(string canvasGuid, string nodeGuid)
+ public NodeTakeOutEventArgs(string canvasGuid, string containerNodeGuid, string nodeGuid)
{
CanvasGuid = canvasGuid;
NodeGuid = nodeGuid;
+ ContainerNodeGuid = containerNodeGuid;
}
public string CanvasGuid { get; }
@@ -426,6 +427,11 @@ namespace Serein.Library.Api
/// 需要取出的节点Guid
///
public string NodeGuid { get; private set; }
+
+ ///
+ /// 容器节点Guid
+ ///
+ public string ContainerNodeGuid { get; private set; }
}
diff --git a/Library/Api/INodeContainer.cs b/Library/Api/INodeContainer.cs
index cdd8198..ebdc398 100644
--- a/Library/Api/INodeContainer.cs
+++ b/Library/Api/INodeContainer.cs
@@ -11,6 +11,8 @@ namespace Serein.Library.Api
///
public interface INodeContainer
{
+
+ string Guid { get; }
///
/// 放置一个节点
///
diff --git a/Library/Extension/FlowModelExtension.cs b/Library/Extension/FlowModelExtension.cs
index 3320261..4defd34 100644
--- a/Library/Extension/FlowModelExtension.cs
+++ b/Library/Extension/FlowModelExtension.cs
@@ -208,7 +208,9 @@ namespace Serein.Library
Stack stack = new Stack();
HashSet processedNodes = new HashSet(); // 用于记录已处理上游节点的节点
stack.Push(nodeModel);
-
+#nullable enable
+ IFlowNode? previousNode = null;
+ IFlowNode? currentNode = null;
while (true)
{
if (token.IsCancellationRequested)
@@ -218,9 +220,30 @@ namespace Serein.Library
#region 执行相关
// 从栈中弹出一个节点作为当前节点进行处理
- var currentNode = stack.Pop();
+ previousNode = currentNode;
+ currentNode = stack.Pop();
+
+
+
+ #region 新增调用信息
+ FlowInvokeInfo? invokeInfo = null;
+ var isRecordInvokeInfo = context.IsRecordInvokeInfo;
+ if (!isRecordInvokeInfo) goto Label_NotRecordInvoke;
+
+ FlowInvokeInfo.InvokeType invokeType = context.NextOrientation switch
+ {
+ ConnectionInvokeType.IsSucceed => FlowInvokeInfo.InvokeType.IsSucceed,
+ ConnectionInvokeType.IsFail => FlowInvokeInfo.InvokeType.IsFail,
+ ConnectionInvokeType.IsError => FlowInvokeInfo.InvokeType.IsError,
+ ConnectionInvokeType.Upstream => FlowInvokeInfo.InvokeType.Upstream,
+ _ => FlowInvokeInfo.InvokeType.None
+ };
+ invokeInfo = context.NewInvokeInfo(previousNode, currentNode, invokeType);
+ #endregion
+
+Label_NotRecordInvoke:
context.NextOrientation = ConnectionInvokeType.None; // 重置上下文状态
- FlowResult flowResult = null;
+ FlowResult flowResult = null;
try
{
flowResult = await currentNode.ExecutingAsync(context, token);
@@ -239,6 +262,22 @@ namespace Serein.Library
}
#endregion
+ #region 更新调用信息
+ var state = context.NextOrientation switch
+ {
+ ConnectionInvokeType.IsFail => FlowInvokeInfo.RunState.Failed,
+ ConnectionInvokeType.IsError => FlowInvokeInfo.RunState.Error,
+ _ => FlowInvokeInfo.RunState.Succeed
+ };
+ if (isRecordInvokeInfo)
+ {
+ invokeInfo.UploadState(state);
+ invokeInfo.UploadResultValue(flowResult.Value);
+ }
+
+
+ #endregion
+
#region 执行完成时更新栈
context.AddOrUpdateFlowData(currentNode.Guid, flowResult); // 上下文中更新数据
@@ -289,10 +328,18 @@ namespace Serein.Library
#endregion
#if DEBUG
- await Task.Delay(1);
+ //await Task.Delay(1);
#endif
}
}
+
+ ///
+ /// 获取所有参数
+ ///
+ ///
+ ///
+ ///
+ ///
public static async Task