mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-05-04 06:11:28 +08:00
重新设计了条件节点的Model
This commit is contained in:
@@ -698,9 +698,10 @@ namespace Serein.Library.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 立刻调用某个节点,并获取其返回值
|
/// 立刻调用某个节点,并获取其返回值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="context">调用时的上下文</param>
|
||||||
/// <param name="nodeGuid">节点Guid</param>
|
/// <param name="nodeGuid">节点Guid</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<object> InvokeNodeAsync(string nodeGuid);
|
Task<object> InvokeNodeAsync(IDynamicContext context, string nodeGuid);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 结束运行
|
/// 结束运行
|
||||||
|
|||||||
@@ -325,15 +325,15 @@ namespace Serein.Library
|
|||||||
|
|
||||||
for (int i = 0; i < parameters.Length; i++)
|
for (int i = 0; i < parameters.Length; i++)
|
||||||
{
|
{
|
||||||
var ed = md.ParameterDetailss[i]; // 方法入参描述
|
var pd = md.ParameterDetailss[i]; // 方法入参描述
|
||||||
|
|
||||||
#region 获取基础的上下文数据
|
#region 获取基础的上下文数据
|
||||||
if (ed.DataType == typeof(IFlowEnvironment)) // 获取流程上下文
|
if (pd.DataType == typeof(IFlowEnvironment)) // 获取流程上下文
|
||||||
{
|
{
|
||||||
parameters[i] = nodeModel.Env;
|
parameters[i] = nodeModel.Env;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ed.DataType == typeof(IDynamicContext)) // 获取流程上下文
|
if (pd.DataType == typeof(IDynamicContext)) // 获取流程上下文
|
||||||
{
|
{
|
||||||
parameters[i] = context;
|
parameters[i] = context;
|
||||||
continue;
|
continue;
|
||||||
@@ -342,41 +342,41 @@ namespace Serein.Library
|
|||||||
|
|
||||||
#region 确定[预入参]数据
|
#region 确定[预入参]数据
|
||||||
object inputParameter; // 存放解析的临时参数
|
object inputParameter; // 存放解析的临时参数
|
||||||
if (ed.IsExplicitData) // 判断是否使用显示的输入参数
|
if (pd.IsExplicitData) // 判断是否使用显示的输入参数
|
||||||
{
|
{
|
||||||
if (ed.DataValue.StartsWith("@get", StringComparison.OrdinalIgnoreCase))
|
if (pd.DataValue.StartsWith("@get", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var previousNode = context.GetPreviousNode(nodeModel);
|
var previousNode = context.GetPreviousNode(nodeModel);
|
||||||
var previousFlowData = context.GetFlowData(previousNode.Guid); // 当前传递的数据
|
var previousFlowData = context.GetFlowData(previousNode.Guid); // 当前传递的数据
|
||||||
|
|
||||||
|
|
||||||
// 执行表达式从上一节点获取对象
|
// 执行表达式从上一节点获取对象
|
||||||
inputParameter = SerinExpressionEvaluator.Evaluate(ed.DataValue, previousFlowData, out _);
|
inputParameter = SerinExpressionEvaluator.Evaluate(pd.DataValue, previousFlowData, out _);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 使用输入的固定值
|
// 使用输入的固定值
|
||||||
inputParameter = ed.DataValue;
|
inputParameter = pd.DataValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ed.ArgDataSourceType == ConnectionArgSourceType.GetPreviousNodeData)
|
if (pd.ArgDataSourceType == ConnectionArgSourceType.GetPreviousNodeData)
|
||||||
{
|
{
|
||||||
var previousNode = context.GetPreviousNode(nodeModel);
|
var previousNode = context.GetPreviousNode(nodeModel);
|
||||||
inputParameter = context.GetFlowData(previousNode.Guid); // 当前传递的数据
|
inputParameter = context.GetFlowData(previousNode.Guid); // 当前传递的数据
|
||||||
}
|
}
|
||||||
else if (ed.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
|
else if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
|
||||||
{
|
{
|
||||||
// 获取指定节点的数据
|
// 获取指定节点的数据
|
||||||
// 如果指定节点没有被执行,会返回null
|
// 如果指定节点没有被执行,会返回null
|
||||||
// 如果执行过,会获取上一次执行结果作为预入参数据
|
// 如果执行过,会获取上一次执行结果作为预入参数据
|
||||||
inputParameter = context.GetFlowData(ed.ArgDataSourceNodeGuid);
|
inputParameter = context.GetFlowData(pd.ArgDataSourceNodeGuid);
|
||||||
}
|
}
|
||||||
else if (ed.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
|
else if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
|
||||||
{
|
{
|
||||||
// 立刻调用对应节点获取数据。
|
// 立刻调用对应节点获取数据。
|
||||||
var result = await context.Env.InvokeNodeAsync(ed.ArgDataSourceNodeGuid);
|
var result = await context.Env.InvokeNodeAsync(context, pd.ArgDataSourceNodeGuid);
|
||||||
inputParameter = result;
|
inputParameter = result;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -386,18 +386,18 @@ namespace Serein.Library
|
|||||||
}
|
}
|
||||||
if (inputParameter is null)
|
if (inputParameter is null)
|
||||||
{
|
{
|
||||||
throw new Exception($"[arg{ed.Index}][{ed.Name}][{ed.DataType}]参数不能为null");
|
throw new Exception($"[arg{pd.Index}][{pd.Name}][{pd.DataType}]参数不能为null");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 入参存在取值转换器,调用对应的转换器获取入参数据
|
#region 入参存在取值转换器,调用对应的转换器获取入参数据
|
||||||
// 入参存在取值转换器
|
// 入参存在取值转换器
|
||||||
if (ed.ExplicitType.IsEnum && !(ed.Convertor is null))
|
if (pd.ExplicitType.IsEnum && !(pd.Convertor is null))
|
||||||
{
|
{
|
||||||
//var resultEnum = Enum.ToObject(ed.ExplicitType, ed.DataValue);
|
//var resultEnum = Enum.ToObject(ed.ExplicitType, ed.DataValue);
|
||||||
var resultEnum = Enum.Parse(ed.ExplicitType, ed.DataValue);
|
var resultEnum = Enum.Parse(pd.ExplicitType, pd.DataValue);
|
||||||
var value = ed.Convertor(resultEnum);
|
var value = pd.Convertor(resultEnum);
|
||||||
if (value is null)
|
if (value is null)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("转换器调用失败");
|
throw new InvalidOperationException("转换器调用失败");
|
||||||
@@ -413,11 +413,11 @@ namespace Serein.Library
|
|||||||
|
|
||||||
#region 入参存在基于BinValue的类型转换器,获取枚举转换器中记录的类型
|
#region 入参存在基于BinValue的类型转换器,获取枚举转换器中记录的类型
|
||||||
// 入参存在基于BinValue的类型转换器,获取枚举转换器中记录的类型
|
// 入参存在基于BinValue的类型转换器,获取枚举转换器中记录的类型
|
||||||
if (ed.ExplicitType.IsEnum && ed.DataType != ed.ExplicitType)
|
if (pd.ExplicitType.IsEnum && pd.DataType != pd.ExplicitType)
|
||||||
{
|
{
|
||||||
var resultEnum = Enum.Parse(ed.ExplicitType, ed.DataValue);
|
var resultEnum = Enum.Parse(pd.ExplicitType, pd.DataValue);
|
||||||
// 获取绑定的类型
|
// 获取绑定的类型
|
||||||
var type = EnumHelper.GetBoundValue(ed.ExplicitType, resultEnum, attr => attr.Value);
|
var type = EnumHelper.GetBoundValue(pd.ExplicitType, resultEnum, attr => attr.Value);
|
||||||
if (type is Type enumBindType && !(enumBindType is null))
|
if (type is Type enumBindType && !(enumBindType is null))
|
||||||
{
|
{
|
||||||
var value = nodeModel.Env.IOC.Instantiate(enumBindType);
|
var value = nodeModel.Env.IOC.Instantiate(enumBindType);
|
||||||
@@ -437,30 +437,30 @@ namespace Serein.Library
|
|||||||
|
|
||||||
#region 对入参数据尝试进行转换
|
#region 对入参数据尝试进行转换
|
||||||
|
|
||||||
if (inputParameter.GetType() == ed.DataType)
|
if (inputParameter.GetType() == pd.DataType)
|
||||||
{
|
{
|
||||||
parameters[i] = inputParameter; // 类型一致无需转换,直接装入入参数组
|
parameters[i] = inputParameter; // 类型一致无需转换,直接装入入参数组
|
||||||
}
|
}
|
||||||
else if (ed.DataType.IsValueType)
|
else if (pd.DataType.IsValueType)
|
||||||
{
|
{
|
||||||
// 值类型
|
// 值类型
|
||||||
var valueStr = inputParameter?.ToString();
|
var valueStr = inputParameter?.ToString();
|
||||||
parameters[i] = valueStr.ToValueData(ed.DataType); // 类型不一致,尝试进行转换,如果转换失败返回类型对应的默认值
|
parameters[i] = valueStr.ToValueData(pd.DataType); // 类型不一致,尝试进行转换,如果转换失败返回类型对应的默认值
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 引用类型
|
// 引用类型
|
||||||
if (ed.DataType == typeof(string)) // 转为字符串
|
if (pd.DataType == typeof(string)) // 转为字符串
|
||||||
{
|
{
|
||||||
var valueStr = inputParameter?.ToString();
|
var valueStr = inputParameter?.ToString();
|
||||||
parameters[i] = valueStr;
|
parameters[i] = valueStr;
|
||||||
}
|
}
|
||||||
else if(ed.DataType.IsSubclassOf(inputParameter.GetType())) // 入参类型 是 预入参数据类型 的 子类/实现类
|
else if(pd.DataType.IsSubclassOf(inputParameter.GetType())) // 入参类型 是 预入参数据类型 的 子类/实现类
|
||||||
{
|
{
|
||||||
// 方法入参中,父类不能隐式转为子类,这里需要进行强制转换
|
// 方法入参中,父类不能隐式转为子类,这里需要进行强制转换
|
||||||
parameters[i] = ObjectConvertHelper.ConvertParentToChild(inputParameter, ed.DataType);
|
parameters[i] = ObjectConvertHelper.ConvertParentToChild(inputParameter, pd.DataType);
|
||||||
}
|
}
|
||||||
else if(ed.DataType.IsAssignableFrom(inputParameter.GetType())) // 入参类型 是 预入参数据类型 的 父类/接口
|
else if(pd.DataType.IsAssignableFrom(inputParameter.GetType())) // 入参类型 是 预入参数据类型 的 父类/接口
|
||||||
{
|
{
|
||||||
parameters[i] = inputParameter;
|
parameters[i] = inputParameter;
|
||||||
}
|
}
|
||||||
@@ -469,12 +469,12 @@ namespace Serein.Library
|
|||||||
{
|
{
|
||||||
var enumerableMethods = typeof(Enumerable).GetMethods(); // 获取所有的 Enumerable 扩展方法
|
var enumerableMethods = typeof(Enumerable).GetMethods(); // 获取所有的 Enumerable 扩展方法
|
||||||
MethodInfo conversionMethod;
|
MethodInfo conversionMethod;
|
||||||
if (ed.DataType.IsArray) // 转为数组
|
if (pd.DataType.IsArray) // 转为数组
|
||||||
{
|
{
|
||||||
parameters[i] = inputParameter;
|
parameters[i] = inputParameter;
|
||||||
conversionMethod = enumerableMethods.FirstOrDefault(m => m.Name == "ToArray" && m.IsGenericMethodDefinition);
|
conversionMethod = enumerableMethods.FirstOrDefault(m => m.Name == "ToArray" && m.IsGenericMethodDefinition);
|
||||||
}
|
}
|
||||||
else if (ed.DataType.GetGenericTypeDefinition() == typeof(List<>)) // 转为集合
|
else if (pd.DataType.GetGenericTypeDefinition() == typeof(List<>)) // 转为集合
|
||||||
{
|
{
|
||||||
conversionMethod = enumerableMethods.FirstOrDefault(m => m.Name == "ToList" && m.IsGenericMethodDefinition);
|
conversionMethod = enumerableMethods.FirstOrDefault(m => m.Name == "ToList" && m.IsGenericMethodDefinition);
|
||||||
}
|
}
|
||||||
@@ -482,7 +482,7 @@ namespace Serein.Library
|
|||||||
{
|
{
|
||||||
throw new InvalidOperationException("输入对象不是集合或目标类型不支持(目前仅支持Array、List的自动转换)");
|
throw new InvalidOperationException("输入对象不是集合或目标类型不支持(目前仅支持Array、List的自动转换)");
|
||||||
}
|
}
|
||||||
var genericMethod = conversionMethod.MakeGenericMethod(ed.DataType);
|
var genericMethod = conversionMethod.MakeGenericMethod(pd.DataType);
|
||||||
var result = genericMethod.Invoke(null, new object[] { collection });
|
var result = genericMethod.Invoke(null, new object[] { collection });
|
||||||
parameters[i] = result;
|
parameters[i] = result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -405,15 +405,13 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="nodeGuid"></param>
|
/// <param name="nodeGuid"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<object> InvokeNodeAsync(string nodeGuid)
|
public async Task<object> InvokeNodeAsync(IDynamicContext context, string nodeGuid)
|
||||||
{
|
{
|
||||||
IDynamicContext context = new DynamicContext(this);
|
|
||||||
object result = true;
|
object result = true;
|
||||||
if (this.NodeModels.TryGetValue(nodeGuid, out var model))
|
if (this.NodeModels.TryGetValue(nodeGuid, out var model))
|
||||||
{
|
{
|
||||||
result = await model.InvokeAsync(context);
|
result = await model.InvokeAsync(context);
|
||||||
}
|
}
|
||||||
context.Exit();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -364,9 +364,9 @@ namespace Serein.NodeFlow.Env
|
|||||||
await currentFlowEnvironment.StartAsyncInSelectNode(startNodeGuid);
|
await currentFlowEnvironment.StartAsyncInSelectNode(startNodeGuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<object> InvokeNodeAsync( string nodeGuid)
|
public async Task<object> InvokeNodeAsync(IDynamicContext context, string nodeGuid)
|
||||||
{
|
{
|
||||||
return await currentFlowEnvironment.InvokeNodeAsync( nodeGuid);
|
return await currentFlowEnvironment.InvokeNodeAsync(context, nodeGuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task StartRemoteServerAsync(int port = 7525)
|
public async Task StartRemoteServerAsync(int port = 7525)
|
||||||
|
|||||||
@@ -459,7 +459,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
//UIContextOperation?.Invoke(() => OnStartNodeChange?.Invoke(new StartNodeChangeEventArgs(nodeGuid,nodeGuid)));
|
//UIContextOperation?.Invoke(() => OnStartNodeChange?.Invoke(new StartNodeChangeEventArgs(nodeGuid,nodeGuid)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<object> InvokeNodeAsync(string nodeGuid)
|
public async Task<object> InvokeNodeAsync(IDynamicContext context, string nodeGuid)
|
||||||
{
|
{
|
||||||
Console.WriteLine("远程环境尚未实现接口 InvokeNodeAsync");
|
Console.WriteLine("远程环境尚未实现接口 InvokeNodeAsync");
|
||||||
_ = msgClient.SendAsync(EnvMsgTheme.SetStartNode, new
|
_ = msgClient.SendAsync(EnvMsgTheme.SetStartNode, new
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ namespace Serein.NodeFlow.Model
|
|||||||
/// 自定义参数值
|
/// 自定义参数值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PropertyInfo(IsNotification = true)]
|
[PropertyInfo(IsNotification = true)]
|
||||||
|
|
||||||
private object? _customData;
|
private object? _customData;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 条件表达式
|
/// 条件表达式
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -72,32 +72,56 @@ namespace Serein.NodeFlow.Model
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context"></param>
|
/// <param name="context"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public override Task<object?> ExecutingAsync(IDynamicContext context)
|
public override async Task<object?> ExecutingAsync(IDynamicContext context)
|
||||||
{
|
{
|
||||||
// 接收上一节点参数or自定义参数内容
|
// 接收上一节点参数or自定义参数内容
|
||||||
object? parameter;
|
object? parameter;
|
||||||
object? result = context.TransmissionData(this); // 条件节点透传上一节点的数据
|
object? result = null;
|
||||||
if (IsCustomData) // 是否使用自定义参数
|
if (!IsCustomData) // 是否使用自定义参数
|
||||||
{
|
{
|
||||||
// 表达式获取上一节点数据
|
|
||||||
var getObjExp = CustomData?.ToString();
|
var pd = MethodDetails.ParameterDetailss[0];
|
||||||
if (!string.IsNullOrEmpty(getObjExp) && getObjExp.Length >= 4 && getObjExp[..4].Equals("@get", StringComparison.CurrentCultureIgnoreCase))
|
|
||||||
|
if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
|
||||||
{
|
{
|
||||||
|
// 使用自定义节点的参数
|
||||||
|
result = context.GetFlowData(pd.ArgDataSourceNodeGuid);
|
||||||
|
}
|
||||||
|
else if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
|
||||||
|
{
|
||||||
|
// 立刻调用目标节点,然后使用其返回值
|
||||||
|
result = await Env.InvokeNodeAsync(context, pd.ArgDataSourceNodeGuid);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 条件节点透传上一节点的数据
|
||||||
|
result = context.TransmissionData(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用上一节点的参数
|
||||||
|
parameter = result;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
var getObjExp = CustomData?.ToString();
|
||||||
|
if (string.IsNullOrEmpty(getObjExp) || getObjExp.Length < 4 || !getObjExp[..4].Equals("@get", StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
// 使用自定义的参数
|
||||||
|
parameter = CustomData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 表达式获取上一节点数据
|
||||||
parameter = result;
|
parameter = result;
|
||||||
if (parameter is not null)
|
if (parameter is not null)
|
||||||
{
|
{
|
||||||
parameter = SerinExpressionEvaluator.Evaluate(getObjExp, parameter, out _);
|
parameter = SerinExpressionEvaluator.Evaluate(getObjExp, parameter, out _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
parameter = CustomData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parameter = result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -111,7 +135,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine($"{result} {Expression} -> " + context.NextOrientation);
|
Console.WriteLine($"{result} {Expression} -> " + context.NextOrientation);
|
||||||
return Task.FromResult(result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ParameterData[] GetParameterdatas()
|
public override ParameterData[] GetParameterdatas()
|
||||||
|
|||||||
Reference in New Issue
Block a user