2025-07-27 23:34:01 +08:00
|
|
|
|
using Serein.Library;
|
2025-05-27 23:46:06 +08:00
|
|
|
|
using Serein.Library.Api;
|
2025-07-08 14:22:41 +08:00
|
|
|
|
using Serein.NodeFlow.Services;
|
2025-05-28 23:19:00 +08:00
|
|
|
|
using System.Dynamic;
|
2025-07-08 14:22:41 +08:00
|
|
|
|
using System.Reflection;
|
2025-05-27 23:46:06 +08:00
|
|
|
|
|
2025-07-29 14:25:31 +08:00
|
|
|
|
namespace Serein.NodeFlow.Model.Nodes
|
2025-05-27 23:46:06 +08:00
|
|
|
|
{
|
2025-05-28 23:19:00 +08:00
|
|
|
|
|
2025-07-30 21:15:07 +08:00
|
|
|
|
[FlowDataProperty(ValuePath = NodeValuePath.Node, IsNodeImp = true)]
|
2025-05-28 23:19:00 +08:00
|
|
|
|
public partial class SingleFlowCallNode
|
|
|
|
|
|
{
|
2025-05-30 01:02:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 目标公开节点
|
|
|
|
|
|
/// </summary>
|
2025-07-30 21:15:07 +08:00
|
|
|
|
[DataInfo(IsNotification = true)]
|
|
|
|
|
|
private string targetNodeGuid = string.Empty;
|
2025-05-28 23:19:00 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 使用目标节点的参数(如果为true,则使用目标节点的入参,如果为false,则使用节点自定义入参)
|
|
|
|
|
|
/// </summary>
|
2025-07-30 21:15:07 +08:00
|
|
|
|
[DataInfo(IsNotification = true)]
|
|
|
|
|
|
private bool _isShareParam ;
|
2025-07-08 14:22:41 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 接口全局名称
|
|
|
|
|
|
/// </summary>
|
2025-07-30 21:15:07 +08:00
|
|
|
|
[DataInfo(IsNotification = true)]
|
|
|
|
|
|
private string _apiGlobalName = string.Empty;
|
2025-05-28 23:19:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-05-27 23:46:06 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 流程调用节点
|
|
|
|
|
|
/// </summary>
|
2025-05-28 23:19:00 +08:00
|
|
|
|
public partial class SingleFlowCallNode : NodeModelBase
|
2025-05-27 23:46:06 +08:00
|
|
|
|
{
|
2025-05-28 23:19:00 +08:00
|
|
|
|
/// <summary>
|
2025-07-04 21:31:07 +08:00
|
|
|
|
/// 被调用的节点
|
2025-05-28 23:19:00 +08:00
|
|
|
|
/// </summary>
|
2025-07-08 14:22:41 +08:00
|
|
|
|
public IFlowNode TargetNode { get; private set; }
|
2025-05-28 23:19:00 +08:00
|
|
|
|
/// <summary>
|
2025-05-30 01:02:25 +08:00
|
|
|
|
/// 缓存的方法信息
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public MethodDetails CacheMethodDetails { get; private set; }
|
2025-07-04 21:31:07 +08:00
|
|
|
|
|
2025-07-30 21:15:07 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 流程接口节点
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="environment"></param>
|
2025-05-27 23:46:06 +08:00
|
|
|
|
public SingleFlowCallNode(IFlowEnvironment environment) : base(environment)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-30 01:02:25 +08:00
|
|
|
|
|
2025-05-28 23:19:00 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 重置接口节点
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void ResetTargetNode()
|
|
|
|
|
|
{
|
2025-07-08 14:22:41 +08:00
|
|
|
|
if (TargetNode is not null)
|
2025-05-28 23:19:00 +08:00
|
|
|
|
{
|
|
|
|
|
|
// 取消接口
|
2025-05-30 01:02:25 +08:00
|
|
|
|
TargetNodeGuid = string.Empty;
|
2025-05-28 23:19:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-05-30 01:02:25 +08:00
|
|
|
|
/// 设置接口节点
|
2025-05-28 23:19:00 +08:00
|
|
|
|
/// </summary>
|
2025-05-30 01:02:25 +08:00
|
|
|
|
/// <param name="nodeGuid"></param>
|
|
|
|
|
|
public void SetTargetNode(string? nodeGuid)
|
2025-05-28 23:19:00 +08:00
|
|
|
|
{
|
2025-05-30 01:02:25 +08:00
|
|
|
|
if (nodeGuid is null || !Env.TryGetNodeModel(nodeGuid, out _))
|
2025-05-28 23:19:00 +08:00
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-05-30 01:02:25 +08:00
|
|
|
|
TargetNodeGuid = nodeGuid;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-13 17:34:03 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 目标节点发生改变
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="value"></param>
|
2025-05-30 01:02:25 +08:00
|
|
|
|
partial void OnTargetNodeGuidChanged(string value)
|
|
|
|
|
|
{
|
2025-07-08 14:22:41 +08:00
|
|
|
|
if (string.IsNullOrEmpty(value) || !Env.TryGetNodeModel(value, out var targetNode))
|
2025-05-30 01:02:25 +08:00
|
|
|
|
{
|
|
|
|
|
|
// 取消设置接口节点
|
2025-07-13 17:34:03 +08:00
|
|
|
|
TargetNode.PropertyChanged -= TargetNode_PropertyChanged; // 不再监听目标属通知
|
2025-07-08 14:22:41 +08:00
|
|
|
|
TargetNode = null;
|
|
|
|
|
|
this.ApiGlobalName = "";
|
2025-05-30 01:02:25 +08:00
|
|
|
|
this.MethodDetails = new MethodDetails();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-07-08 14:22:41 +08:00
|
|
|
|
TargetNode = targetNode;
|
2025-07-13 17:34:03 +08:00
|
|
|
|
if (!this.IsShareParam // 不共享参数
|
|
|
|
|
|
&& TargetNode.MethodDetails is not null // 目标节点有方法描述
|
|
|
|
|
|
&& CacheMethodDetails is not null // 存在缓存
|
|
|
|
|
|
&& TargetNode.MethodDetails.AssemblyName == CacheMethodDetails.AssemblyName // 与缓存中一致
|
|
|
|
|
|
&& TargetNode.MethodDetails.MethodName == CacheMethodDetails.MethodName) // 与缓存中一致
|
2025-05-30 01:02:25 +08:00
|
|
|
|
{
|
2025-07-13 17:34:03 +08:00
|
|
|
|
this.MethodDetails = CacheMethodDetails; // 直接使用缓存
|
|
|
|
|
|
this.ApiGlobalName = GetApiInvokeName(this); // 生成新的接口名称
|
2025-05-30 01:02:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-07-13 17:34:03 +08:00
|
|
|
|
if (TargetNode.MethodDetails is not null) // // 目标节点有方法描述
|
2025-05-30 01:02:25 +08:00
|
|
|
|
{
|
2025-07-13 17:34:03 +08:00
|
|
|
|
CacheMethodDetails = TargetNode.MethodDetails.CloneOfNode(this); // 从目标节点复制一份到缓存中
|
|
|
|
|
|
TargetNode.PropertyChanged += TargetNode_PropertyChanged; // 监听目标属性通知(“IsPublic”属性)
|
|
|
|
|
|
this.MethodDetails = CacheMethodDetails; // 设置流程接口节点的方法描述为目标节点的方法描述(共享参数更改)
|
|
|
|
|
|
this.ApiGlobalName = GetApiInvokeName(this); // 生成新的接口名称
|
2025-05-30 15:42:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-30 01:02:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2025-07-13 17:34:03 +08:00
|
|
|
|
OnPropertyChanged(nameof(MethodDetails)); // 通知控件,MethodDetails属性发生改变
|
2025-05-28 23:19:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
partial void OnIsShareParamChanged(bool value)
|
|
|
|
|
|
{
|
2025-07-08 14:22:41 +08:00
|
|
|
|
if (TargetNode is null || TargetNode.MethodDetails is null)
|
2025-05-28 23:19:00 +08:00
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (value)
|
|
|
|
|
|
{
|
2025-07-13 17:34:03 +08:00
|
|
|
|
// 不再与目标节点共享参数,而是拷贝新的实体,缓存起来,自己单独使用
|
2025-07-08 14:22:41 +08:00
|
|
|
|
CacheMethodDetails = TargetNode.MethodDetails.CloneOfNode(this);
|
2025-05-30 15:42:59 +08:00
|
|
|
|
this.MethodDetails = CacheMethodDetails;
|
2025-05-28 23:19:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-05-30 15:42:59 +08:00
|
|
|
|
|
2025-07-08 14:22:41 +08:00
|
|
|
|
if(TargetNode.ControlType == NodeControlType.Script)
|
2025-05-30 15:42:59 +08:00
|
|
|
|
{
|
2025-07-13 17:34:03 +08:00
|
|
|
|
// 限制脚本节点对于入参数量、入参名称的修改
|
2025-05-30 15:42:59 +08:00
|
|
|
|
foreach (var item in CacheMethodDetails.ParameterDetailss)
|
|
|
|
|
|
{
|
|
|
|
|
|
item.IsParams = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-13 17:34:03 +08:00
|
|
|
|
// 与目标节点共享参数
|
|
|
|
|
|
if(CacheMethodDetails is null)
|
|
|
|
|
|
{
|
|
|
|
|
|
CacheMethodDetails = TargetNode.MethodDetails; // 防御性代码,几乎不可能触发
|
|
|
|
|
|
}
|
|
|
|
|
|
this.MethodDetails = CacheMethodDetails;
|
2025-05-28 23:19:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-30 01:02:25 +08:00
|
|
|
|
OnPropertyChanged(nameof(MethodDetails));
|
|
|
|
|
|
}
|
2025-05-28 23:19:00 +08:00
|
|
|
|
|
|
|
|
|
|
private void TargetNode_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果不再公开
|
|
|
|
|
|
if (sender is NodeModelBase node && !node.IsPublic)
|
|
|
|
|
|
{
|
2025-05-30 01:02:25 +08:00
|
|
|
|
foreach (ConnectionInvokeType ctType in NodeStaticConfig.ConnectionTypes)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.SuccessorNodes[ctType] = [];
|
|
|
|
|
|
}
|
2025-07-08 14:22:41 +08:00
|
|
|
|
TargetNode.PropertyChanged -= TargetNode_PropertyChanged;
|
2025-05-28 23:19:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 从节点Guid刷新实体
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private bool UploadTargetNode()
|
|
|
|
|
|
{
|
2025-07-08 14:22:41 +08:00
|
|
|
|
if (TargetNode is null)
|
2025-05-28 23:19:00 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(TargetNodeGuid))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!Env.TryGetNodeModel(TargetNodeGuid, out var targetNode) || targetNode is null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-08 14:22:41 +08:00
|
|
|
|
this.TargetNode = targetNode;
|
2025-05-28 23:19:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 保存全局变量的数据
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="nodeInfo"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public override NodeInfo SaveCustomData(NodeInfo nodeInfo)
|
|
|
|
|
|
{
|
|
|
|
|
|
dynamic data = new ExpandoObject();
|
2025-07-08 14:22:41 +08:00
|
|
|
|
data.TargetNodeGuid = TargetNode?.Guid; // 变量名称
|
2025-05-28 23:19:00 +08:00
|
|
|
|
data.IsShareParam = IsShareParam;
|
2025-07-08 14:22:41 +08:00
|
|
|
|
data.ApiGlobalName = ApiGlobalName;
|
2025-05-28 23:19:00 +08:00
|
|
|
|
nodeInfo.CustomData = data;
|
|
|
|
|
|
return nodeInfo;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-08 14:22:41 +08:00
|
|
|
|
private static Dictionary<string, int> ApiInvokeNameCache = new Dictionary<string, int>();
|
2025-07-30 21:15:07 +08:00
|
|
|
|
private static int getApiInvokeNameCount = 0;
|
2025-07-08 14:22:41 +08:00
|
|
|
|
private static string GetApiInvokeName(SingleFlowCallNode node, string apiName)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ApiInvokeNameCache.ContainsKey(apiName))
|
|
|
|
|
|
{
|
|
|
|
|
|
var count = ApiInvokeNameCache[apiName];
|
|
|
|
|
|
count++;
|
|
|
|
|
|
ApiInvokeNameCache[apiName] = count;
|
|
|
|
|
|
return $"{apiName}{count}";
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
ApiInvokeNameCache[apiName] = 0;
|
|
|
|
|
|
return $"{apiName}";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-30 21:15:07 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取流程接口节点的名称
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="node"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-07-08 14:22:41 +08:00
|
|
|
|
public static string GetApiInvokeName(SingleFlowCallNode node)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(node.TargetNode is null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return GetApiInvokeName(node, "ApiInvoke"); // 如果没有目标节点,则返回默认名称
|
|
|
|
|
|
}
|
|
|
|
|
|
var md = node.TargetNode.MethodDetails;
|
|
|
|
|
|
if (md is null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var apiName = $"{node.TargetNode.ControlType}";
|
|
|
|
|
|
return GetApiInvokeName(node, apiName);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-07-18 22:45:06 +08:00
|
|
|
|
/*var tempName = node.MethodDetails.MethodName;
|
|
|
|
|
|
var index = node.MethodDetails.MethodName.IndexOf('(');
|
|
|
|
|
|
var methodName = tempName[..(index - 1)];
|
|
|
|
|
|
return GetApiInvokeName(node, methodName);*/
|
2025-07-08 14:22:41 +08:00
|
|
|
|
FlowLibraryService service = node.Env.IOC.Get<FlowLibraryService>();
|
|
|
|
|
|
if (service.TryGetMethodInfo(md.AssemblyName, md.MethodName, out var methodInfo))
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
var apiName = $"{methodInfo.Name}";
|
|
|
|
|
|
return GetApiInvokeName(node, apiName);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var apiName = $"{node.TargetNode.ControlType}";
|
|
|
|
|
|
return GetApiInvokeName(node, apiName);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-05-28 23:19:00 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 加载全局变量的数据
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="nodeInfo"></param>
|
|
|
|
|
|
public override void LoadCustomData(NodeInfo nodeInfo)
|
|
|
|
|
|
{
|
2025-05-30 01:02:25 +08:00
|
|
|
|
CacheMethodDetails = this.MethodDetails; // 缓存
|
2025-05-28 23:19:00 +08:00
|
|
|
|
string targetNodeGuid = nodeInfo.CustomData?.TargetNodeGuid ?? "";
|
|
|
|
|
|
this.IsShareParam = nodeInfo.CustomData?.IsShareParam;
|
|
|
|
|
|
if (Env.TryGetNodeModel(targetNodeGuid, out var targetNode))
|
|
|
|
|
|
{
|
2025-05-30 01:02:25 +08:00
|
|
|
|
TargetNodeGuid = targetNode.Guid;
|
2025-07-08 14:22:41 +08:00
|
|
|
|
this.TargetNode = targetNode;
|
2025-07-06 14:34:49 +08:00
|
|
|
|
|
|
|
|
|
|
if(this.IsShareParam == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var item in nodeInfo.ParameterData)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-08 14:22:41 +08:00
|
|
|
|
|
|
|
|
|
|
this.ApiGlobalName = nodeInfo.CustomData?.ApiGlobalName ?? GetApiInvokeName(this);
|
2025-05-28 23:19:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
SereinEnv.WriteLine(InfoType.ERROR, $"流程接口节点[{this.Guid}]无法找到对应的节点:{targetNodeGuid}");
|
|
|
|
|
|
}
|
2025-05-30 01:02:25 +08:00
|
|
|
|
|
2025-05-28 23:19:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-06-22 21:53:37 +08:00
|
|
|
|
/*public override void Remove()
|
2025-05-30 01:02:25 +08:00
|
|
|
|
{
|
|
|
|
|
|
var tmp = this;
|
|
|
|
|
|
targetNode = null;
|
|
|
|
|
|
CacheMethodDetails = null;
|
|
|
|
|
|
}
|
2025-06-22 21:53:37 +08:00
|
|
|
|
*/
|
2025-05-30 15:42:59 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 需要调用其它流程图中的某个节点
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="context"></param>
|
|
|
|
|
|
/// <param name="token"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-07-23 16:20:41 +08:00
|
|
|
|
public override async Task<FlowResult> ExecutingAsync(IFlowContext context, CancellationToken token)
|
2025-05-30 15:42:59 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (!UploadTargetNode())
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new ArgumentNullException();
|
|
|
|
|
|
}
|
|
|
|
|
|
if (IsShareParam)
|
|
|
|
|
|
{
|
2025-07-08 14:22:41 +08:00
|
|
|
|
this.MethodDetails = TargetNode.MethodDetails;
|
2025-05-30 15:42:59 +08:00
|
|
|
|
}
|
2025-07-08 14:22:41 +08:00
|
|
|
|
this.SuccessorNodes = TargetNode.SuccessorNodes;
|
2025-05-30 15:42:59 +08:00
|
|
|
|
|
2025-07-08 14:22:41 +08:00
|
|
|
|
FlowResult flowData = await (TargetNode.ControlType switch
|
2025-05-30 15:42:59 +08:00
|
|
|
|
{
|
2025-07-08 14:22:41 +08:00
|
|
|
|
NodeControlType.Script => ((SingleScriptNode)TargetNode).ExecutingAsync(this, context, token),
|
2025-05-30 15:42:59 +08:00
|
|
|
|
_ => base.ExecutingAsync(context, token)
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-07-09 21:49:26 +08:00
|
|
|
|
// 对于目标节点的后续节点,如果入参参数来源指定为它(目标节点)时,就需要从上下文中根据它的Guid获取流程数据
|
|
|
|
|
|
context.AddOrUpdateFlowData(TargetNode.Guid, flowData);
|
2025-05-30 15:42:59 +08:00
|
|
|
|
if (IsShareParam)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 设置运行时上一节点
|
|
|
|
|
|
|
|
|
|
|
|
// 此处代码与SereinFlow.Library.FlowNode.ParameterDetails
|
|
|
|
|
|
// ToMethodArgData()方法中判断流程接口节点分支逻辑耦合
|
|
|
|
|
|
// 不要轻易修改
|
|
|
|
|
|
foreach (ConnectionInvokeType ctType in NodeStaticConfig.ConnectionTypes)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (this.SuccessorNodes[ctType] == null) continue;
|
|
|
|
|
|
foreach (var node in this.SuccessorNodes[ctType])
|
|
|
|
|
|
{
|
|
|
|
|
|
if (node.DebugSetting.IsEnable)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
2025-07-06 14:34:49 +08:00
|
|
|
|
context.SetPreviousNode(node.Guid, this.Guid);
|
2025-05-30 15:42:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return flowData;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-05-28 23:19:00 +08:00
|
|
|
|
|
2025-05-27 23:46:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|