mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-02 15:50:47 +08:00
添加了@Dtc(数据类型转换)、@Data(获取全局数据)表达式
This commit is contained in:
@@ -917,7 +917,30 @@ namespace Serein.Library.Api
|
||||
|
||||
#endregion
|
||||
|
||||
#region 流程依赖类库的接口
|
||||
#region 流程运行时
|
||||
|
||||
#region 全局数据/方法信息
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加或更新全局数据
|
||||
/// </summary>
|
||||
/// <param name="keyName">数据名称</param>
|
||||
/// <param name="data">数据集</param>
|
||||
/// <returns></returns>
|
||||
object AddOrUpdateGlobalData(string keyName, object data);
|
||||
|
||||
/// <summary>
|
||||
/// 获取全局数据
|
||||
/// </summary>
|
||||
/// <param name="keyName">数据名称</param>
|
||||
/// <returns></returns>
|
||||
object GetGlobalData(string keyName);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region 加载依赖
|
||||
|
||||
/// <summary>
|
||||
/// 运行时加载
|
||||
@@ -933,6 +956,7 @@ namespace Serein.Library.Api
|
||||
/// <param name="isRecurrence">是否递归加载</param>
|
||||
void LoadAllNativeLibraryOfRuning(string path, bool isRecurrence = true);
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region UI视觉
|
||||
|
||||
@@ -78,30 +78,34 @@ namespace Serein.Library
|
||||
args = Array.Empty<object>();
|
||||
}
|
||||
object result = null;
|
||||
try
|
||||
if (_emitMethodType == EmitMethodType.HasResultTask && _emitDelegate is Func<object, object[], Task<object>> hasResultTask)
|
||||
{
|
||||
if (_emitMethodType == EmitMethodType.HasResultTask && _emitDelegate is Func<object, object[], Task<object>> hasResultTask)
|
||||
{
|
||||
result = await hasResultTask(instance, args);
|
||||
}
|
||||
else if (_emitMethodType == EmitMethodType.Task && _emitDelegate is Func<object, object[], Task> task)
|
||||
{
|
||||
await task.Invoke(instance, args);
|
||||
}
|
||||
else if (_emitMethodType == EmitMethodType.Func && _emitDelegate is Func<object, object[], object> func)
|
||||
{
|
||||
result = func.Invoke(instance, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException("创建了非预期委托(应该不会出现)");
|
||||
}
|
||||
return result;
|
||||
result = await hasResultTask(instance, args);
|
||||
}
|
||||
catch
|
||||
else if (_emitMethodType == EmitMethodType.Task && _emitDelegate is Func<object, object[], Task> task)
|
||||
{
|
||||
throw;
|
||||
await task.Invoke(instance, args);
|
||||
}
|
||||
else if (_emitMethodType == EmitMethodType.Func && _emitDelegate is Func<object, object[], object> func)
|
||||
{
|
||||
result = func.Invoke(instance, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException("创建了非预期委托(应该不会出现)");
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
|
||||
//try
|
||||
//{
|
||||
|
||||
//}
|
||||
//catch
|
||||
//{
|
||||
// throw;
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,8 +262,9 @@ namespace Serein.Library
|
||||
catch (Exception ex)
|
||||
{
|
||||
newFlowData = null;
|
||||
await Console.Out.WriteLineAsync($"节点[{this.MethodDetails?.MethodName}]异常:" + ex);
|
||||
context.Env.WriteLine(InfoType.ERROR,$"节点[{this.Guid}]异常:" + ex);
|
||||
context.NextOrientation = ConnectionInvokeType.IsError;
|
||||
context.ExceptionOfRuning = ex;
|
||||
}
|
||||
|
||||
|
||||
@@ -455,16 +456,31 @@ namespace Serein.Library
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 处理Get表达式
|
||||
if (pd.IsExplicitData // 输入了表达式
|
||||
&& pd.DataValue.StartsWith("@get", StringComparison.OrdinalIgnoreCase) // Get表达式
|
||||
)
|
||||
#region 处理 @Get / @DTC 表达式 (Data type conversion) / @Data (全局数据)
|
||||
if (pd.IsExplicitData)
|
||||
{
|
||||
//var previousNode = context.GetPreviousNode(nodeModel);
|
||||
//var previousFlowData = context.GetFlowData(previousNode.Guid); // 当前传递的数据
|
||||
// 执行表达式从上一节点获取对象
|
||||
inputParameter = SerinExpressionEvaluator.Evaluate(pd.DataValue, inputParameter, out _);
|
||||
|
||||
// @Get 表达式 (从上一节点获取对象)
|
||||
if (pd.DataValue.StartsWith("@get", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
inputParameter = SerinExpressionEvaluator.Evaluate(pd.DataValue, inputParameter, out _);
|
||||
}
|
||||
|
||||
// @DTC 表达式 (Data type conversion)
|
||||
if (pd.DataValue.StartsWith("@dtc", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
inputParameter = SerinExpressionEvaluator.Evaluate(pd.DataValue, inputParameter, out _);
|
||||
}
|
||||
|
||||
// @Data 表达式 (获取全局数据)
|
||||
if (pd.DataValue.StartsWith("@data", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
inputParameter = SerinExpressionEvaluator.Evaluate(pd.DataValue, inputParameter, out _);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -6,6 +6,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Serein.Library
|
||||
{
|
||||
@@ -88,21 +89,57 @@ namespace Serein.Library
|
||||
return value;
|
||||
}
|
||||
|
||||
[NodeAction(NodeType.Action, "文本拼接")]
|
||||
private string SereinTextJoin(params object[] value)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
foreach (var item in value)
|
||||
{
|
||||
var tmp = item.ToString();
|
||||
if (tmp == "\\n")
|
||||
{
|
||||
sb.Append(Environment.NewLine);
|
||||
}
|
||||
else if (tmp == "\\t")
|
||||
{
|
||||
sb.Append('\t');
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(tmp);
|
||||
}
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/* if (!DynamicObjectHelper.TryResolve(dict, className, out var result))
|
||||
{
|
||||
Console.WriteLine("赋值过程中有错误,请检查属性名和类型!");
|
||||
}
|
||||
else
|
||||
{
|
||||
DynamicObjectHelper.PrintObjectProperties(result);
|
||||
}
|
||||
//if (!ObjDynamicCreateHelper.TryResolve(externalData, "RootType", out var result))
|
||||
//{
|
||||
// Console.WriteLine("赋值过程中有错误,请检查属性名和类型!");
|
||||
|
||||
//}
|
||||
//ObjDynamicCreateHelper.PrintObjectProperties(result!);
|
||||
return result;*/
|
||||
[NodeAction(NodeType.Action, "键值对动态构建对象")]
|
||||
private object SereinKvDataToObject(Dictionary<string, object> dict,
|
||||
string classTypeName = "newClass_dynamic",
|
||||
bool IsPrint = false)
|
||||
{
|
||||
if (!DynamicObjectHelper.TryResolve(dict, classTypeName, out var result))
|
||||
{
|
||||
Console.WriteLine("赋值过程中有错误,请检查属性名和类型!");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsPrint)
|
||||
{
|
||||
Console.WriteLine("创建完成,正在打印结果");
|
||||
DynamicObjectHelper.PrintObjectProperties(result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
[NodeAction(NodeType.Action, "设置/更新全局数据")]
|
||||
private object SereinAddOrUpdateFlowGlobalData(string name,object data)
|
||||
{
|
||||
SereinEnv.EnvGlobalData.AddOrUpdate(name, data,(k,o)=> data);
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,6 +201,10 @@ namespace Serein.Library.Utils
|
||||
result = nuint.Parse(valueStr, CultureInfo.InvariantCulture);
|
||||
}
|
||||
#endif
|
||||
else if(type == typeof(DateTime))
|
||||
{
|
||||
return DateTime.Parse(valueStr);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("非预期值类型");
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Serein.Library.Api;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Linq;
|
||||
@@ -11,6 +12,39 @@ namespace Serein.Library.Utils
|
||||
public static class SereinEnv
|
||||
{
|
||||
private static IFlowEnvironment environment;
|
||||
|
||||
/// <summary>
|
||||
/// 记录全局数据
|
||||
/// </summary>
|
||||
public static ConcurrentDictionary<string, object> EnvGlobalData { get; } = new ConcurrentDictionary<string, object>();
|
||||
/// <summary>
|
||||
/// 清空全局数据
|
||||
/// </summary>
|
||||
public static void ClearGlobalData()
|
||||
{
|
||||
foreach (var nodeObj in EnvGlobalData.Values)
|
||||
{
|
||||
if (nodeObj != null)
|
||||
{
|
||||
if (typeof(IDisposable).IsAssignableFrom(nodeObj?.GetType()) && nodeObj is IDisposable disposable)
|
||||
{
|
||||
disposable?.Dispose();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
EnvGlobalData.Clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 设置运行流程
|
||||
/// </summary>
|
||||
/// <param name="environment"></param>
|
||||
public static void SetEnv(IFlowEnvironment environment)
|
||||
{
|
||||
if (environment != null)
|
||||
@@ -18,10 +52,22 @@ namespace Serein.Library.Utils
|
||||
SereinEnv.environment = environment;
|
||||
}
|
||||
}
|
||||
public static void WriteLine(InfoType type, string message, InfoClass @class = InfoClass.Trivial)
|
||||
|
||||
/// <summary>
|
||||
/// 输出内容
|
||||
/// </summary>
|
||||
/// <param name="type">类型</param>
|
||||
/// <param name="message">内容</param>
|
||||
/// <param name="class">级别</param>
|
||||
public static void WriteLine(InfoType type, string message, InfoClass @class = InfoClass.General)
|
||||
{
|
||||
SereinEnv.environment.WriteLine(type,message,@class);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
@@ -83,6 +84,16 @@ namespace Serein.Library.Utils.SereinExpression
|
||||
isChange = true;
|
||||
result = SetMember(targetObJ, operand);
|
||||
}
|
||||
else if (operation == "@dtc")
|
||||
{
|
||||
isChange = true;
|
||||
result = DataTypeConversion(targetObJ, operand);
|
||||
}
|
||||
else if (operation == "@data")
|
||||
{
|
||||
isChange = true;
|
||||
result = GetGlobleData(targetObJ, operand);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException($"Operation {operation} is not supported.");
|
||||
@@ -402,11 +413,106 @@ namespace Serein.Library.Utils.SereinExpression
|
||||
{
|
||||
return ComputedNumber<decimal>(value, expression);
|
||||
}
|
||||
|
||||
private static T ComputedNumber<T>(object value, string expression) where T : struct, IComparable<T>
|
||||
{
|
||||
T result = value.ToConvert<T>();
|
||||
return SerinArithmeticExpressionEvaluator<T>.Evaluate(expression, result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据类型转换
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="expression"></param>
|
||||
/// <returns></returns>
|
||||
private static object DataTypeConversion(object value, string expression)
|
||||
{
|
||||
Type tempType;
|
||||
|
||||
int typeStartIndex = expression.IndexOf('<');
|
||||
int typeEndIndex = expression.IndexOf('>');
|
||||
string typeStr = expression.Substring(typeStartIndex + 1, typeEndIndex - typeStartIndex - 1)
|
||||
.Trim().ToLower(); // 手动置顶的类型
|
||||
string valueStr = expression.Substring(typeEndIndex + 1, expression.Length - typeEndIndex - 1);
|
||||
switch (typeStr)
|
||||
{
|
||||
case "bool":
|
||||
tempType = typeof(bool);
|
||||
break;
|
||||
case "float":
|
||||
tempType = typeof(float);
|
||||
break;
|
||||
case "decimal":
|
||||
tempType = typeof(decimal);
|
||||
break;
|
||||
case "double":
|
||||
tempType = typeof(double);
|
||||
break;
|
||||
case "sbyte":
|
||||
tempType = typeof(sbyte);
|
||||
break;
|
||||
case "byte":
|
||||
tempType = typeof(byte);
|
||||
break;
|
||||
case "short":
|
||||
tempType = typeof(short);
|
||||
break;
|
||||
case "ushort":
|
||||
tempType = typeof(ushort);
|
||||
break;
|
||||
case "int":
|
||||
tempType = typeof(int);
|
||||
break;
|
||||
case "uint":
|
||||
tempType = typeof(uint);
|
||||
break;
|
||||
case "long":
|
||||
tempType = typeof(long);
|
||||
break;
|
||||
case "ulong":
|
||||
tempType = typeof(ulong);
|
||||
break;
|
||||
// 如果需要支持 nint 和 nuint
|
||||
// case "nint":
|
||||
// tempType = typeof(nint);
|
||||
// break;
|
||||
// case "nuint":
|
||||
// tempType = typeof(nuint);
|
||||
// break;
|
||||
case "string":
|
||||
tempType = typeof(string);
|
||||
break;
|
||||
case "datetime":
|
||||
tempType = typeof(DateTime);
|
||||
break;
|
||||
default:
|
||||
tempType = Type.GetType(typeStr);
|
||||
break;
|
||||
}
|
||||
|
||||
if (tempType.IsValueType)
|
||||
{
|
||||
return valueStr.ToValueData(tempType);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取全局数据
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="expression"></param>
|
||||
/// <returns></returns>
|
||||
private static object GetGlobleData(object value, string expression)
|
||||
{
|
||||
var keyName = expression;
|
||||
SereinEnv.EnvGlobalData.TryGetValue(keyName, out var data);
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,8 +323,6 @@ namespace Serein.NodeFlow.Env
|
||||
/// </summary>
|
||||
private FlowStarter? flowStarter;
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 环境对外接口
|
||||
@@ -526,6 +524,8 @@ namespace Serein.NodeFlow.Env
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 加载项目文件
|
||||
/// </summary>
|
||||
@@ -535,13 +535,15 @@ namespace Serein.NodeFlow.Env
|
||||
{
|
||||
var projectData = flowEnvInfo.Project;
|
||||
// 加载项目配置文件
|
||||
var dllPaths = projectData.Librarys.Select(it => it.FileName).ToList();
|
||||
var dllPaths = projectData.Librarys.Select(it => it.FilePath).ToList();
|
||||
List<MethodDetails> methodDetailss = [];
|
||||
|
||||
// 遍历依赖项中的特性注解,生成方法详情
|
||||
foreach (var dllPath in dllPaths)
|
||||
{
|
||||
var dllFilePath = Path.GetFullPath(Path.Combine(filePath, dllPath));
|
||||
string cleanedRelativePath = dllPath.TrimStart('.', '\\');
|
||||
var tmpPath = Path.Combine(filePath, cleanedRelativePath);
|
||||
var dllFilePath = Path.GetFullPath(tmpPath);
|
||||
LoadLibrary(dllFilePath); // 加载项目文件时加载对应的程序集
|
||||
}
|
||||
|
||||
@@ -550,39 +552,48 @@ namespace Serein.NodeFlow.Env
|
||||
// 加载节点
|
||||
foreach (NodeInfo? nodeInfo in projectData.Nodes)
|
||||
{
|
||||
var controlType = FlowFunc.GetNodeControlType(nodeInfo);
|
||||
NodeControlType controlType = FlowFunc.GetNodeControlType(nodeInfo);
|
||||
if (controlType == NodeControlType.None)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
MethodDetails? methodDetails = null;
|
||||
|
||||
if (controlType.IsBaseNode())
|
||||
{
|
||||
// 加载基础节点
|
||||
methodDetails = new MethodDetails();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 加载方法节点
|
||||
if (string.IsNullOrEmpty(nodeInfo.AssemblyName) && string.IsNullOrEmpty(nodeInfo.MethodName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
MethodDetails? methodDetails = null;
|
||||
FlowLibraryManagement.TryGetMethodDetails(nodeInfo.AssemblyName, nodeInfo.MethodName,out methodDetails); // 加载项目时尝试获取方法信息
|
||||
var nodeModel = FlowFunc.CreateNode(this, controlType, methodDetails); // 加载项目时创建节点
|
||||
nodeModel.LoadInfo(nodeInfo); // 创建节点model
|
||||
if (nodeModel is null)
|
||||
{
|
||||
nodeInfo.Guid = string.Empty;
|
||||
continue;
|
||||
}
|
||||
|
||||
TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
|
||||
if (nodeInfo.ChildNodeGuids?.Length > 0)
|
||||
{
|
||||
regionChildNodes.Add((nodeModel, nodeInfo.ChildNodeGuids));
|
||||
|
||||
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position)));
|
||||
}
|
||||
else
|
||||
{
|
||||
ordinaryNodes.Add((nodeModel, nodeInfo.Position));
|
||||
}
|
||||
FlowLibraryManagement.TryGetMethodDetails(nodeInfo.AssemblyName, nodeInfo.MethodName, out methodDetails); // 加载项目时尝试获取方法信息
|
||||
}
|
||||
|
||||
var nodeModel = FlowFunc.CreateNode(this, controlType, methodDetails); // 加载项目时创建节点
|
||||
nodeModel.LoadInfo(nodeInfo); // 创建节点model
|
||||
if (nodeModel is null)
|
||||
{
|
||||
nodeInfo.Guid = string.Empty;
|
||||
continue;
|
||||
}
|
||||
|
||||
TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
|
||||
if (nodeInfo.ChildNodeGuids?.Length > 0)
|
||||
{
|
||||
regionChildNodes.Add((nodeModel, nodeInfo.ChildNodeGuids));
|
||||
|
||||
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position)));
|
||||
}
|
||||
else
|
||||
{
|
||||
ordinaryNodes.Add((nodeModel, nodeInfo.Position));
|
||||
}
|
||||
|
||||
}
|
||||
// 加载区域子项
|
||||
foreach ((NodeModelBase region, string[] childNodeGuids) item in regionChildNodes)
|
||||
@@ -1323,7 +1334,6 @@ namespace Serein.NodeFlow.Env
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 记录节点更改数据,防止重复更改
|
||||
/// </summary>
|
||||
@@ -1466,6 +1476,31 @@ namespace Serein.NodeFlow.Env
|
||||
|
||||
#region 流程依赖类库的接口
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加或更新全局数据
|
||||
/// </summary>
|
||||
/// <param name="keyName">数据名称</param>
|
||||
/// <param name="data">数据集</param>
|
||||
/// <returns></returns>
|
||||
public object AddOrUpdateGlobalData(string keyName, object data)
|
||||
{
|
||||
SereinEnv.EnvGlobalData.AddOrUpdate(keyName, data, (k, o) => data);
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取全局数据
|
||||
/// </summary>
|
||||
/// <param name="keyName">数据名称</param>
|
||||
/// <returns></returns>
|
||||
public object? GetGlobalData(string keyName)
|
||||
{
|
||||
SereinEnv.EnvGlobalData.TryGetValue(keyName, out var data);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 运行时加载
|
||||
/// </summary>
|
||||
|
||||
@@ -455,6 +455,27 @@ namespace Serein.NodeFlow.Env
|
||||
}
|
||||
|
||||
#region 流程依赖类库的接口
|
||||
/// <summary>
|
||||
/// 添加或更新全局数据
|
||||
/// </summary>
|
||||
/// <param name="keyName">数据名称</param>
|
||||
/// <param name="data">数据集</param>
|
||||
/// <returns></returns>
|
||||
public object AddOrUpdateGlobalData(string keyName, object data)
|
||||
{
|
||||
return currentFlowEnvironment.AddOrUpdateGlobalData(keyName, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取全局数据
|
||||
/// </summary>
|
||||
/// <param name="keyName">数据名称</param>
|
||||
/// <returns></returns>
|
||||
public object GetGlobalData(string keyName)
|
||||
{
|
||||
return currentFlowEnvironment.GetGlobalData(keyName);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 运行时加载
|
||||
@@ -574,6 +595,8 @@ namespace Serein.NodeFlow.Env
|
||||
return IOC.Run(action);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
@@ -10,7 +10,19 @@ namespace Serein.NodeFlow.Env
|
||||
/// </summary>
|
||||
public static class FlowFunc
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否为基础节点
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool IsBaseNode(this NodeControlType nodeControlType)
|
||||
{
|
||||
if(nodeControlType == NodeControlType.ExpCondition
|
||||
|| nodeControlType == NodeControlType.ExpOp)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建节点
|
||||
|
||||
@@ -895,6 +895,31 @@ namespace Serein.NodeFlow.Env
|
||||
this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:LoadAllNativeLibraryOfRuning");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加或更新全局数据
|
||||
/// </summary>
|
||||
/// <param name="keyName">数据名称</param>
|
||||
/// <param name="data">数据集</param>
|
||||
/// <returns></returns>
|
||||
public object AddOrUpdateGlobalData(string keyName, object data)
|
||||
{
|
||||
this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:AddOrUpdateGlobalData");
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取全局数据
|
||||
/// </summary>
|
||||
/// <param name="keyName">数据名称</param>
|
||||
/// <returns></returns>
|
||||
public object GetGlobalData(string keyName)
|
||||
{
|
||||
this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:GetGlobalData");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,13 +241,9 @@ namespace Serein.NodeFlow
|
||||
_flipFlopCts?.Dispose();
|
||||
} // 通知所有流程上下文停止运行
|
||||
TerminateAllGlobalFlipflop(); // 确保所有触发器不再运行
|
||||
|
||||
|
||||
SereinEnv.ClearGlobalData(); // 清空全局数据缓存
|
||||
NativeDllHelper.FreeLibrarys(); // 卸载所有已加载的 Native Dll
|
||||
|
||||
//NativeDllHelper.FreeLibrarys(); // 卸载所有已加载的 Native Dll
|
||||
|
||||
|
||||
env.FlowState = RunState.Completion;
|
||||
env.FlipFlopState = RunState.Completion;
|
||||
|
||||
@@ -395,7 +391,7 @@ namespace Serein.NodeFlow
|
||||
}
|
||||
catch (FlipflopException ex)
|
||||
{
|
||||
await Console.Out.WriteLineAsync($"触发器[{singleFlipFlopNode.MethodDetails.MethodName}]因非预期异常终止。"+ex.Message);
|
||||
env.WriteLine(InfoType.ERROR,$"触发器[{singleFlipFlopNode.MethodDetails.MethodName}]因非预期异常终止。"+ex.Message);
|
||||
if (ex.Type == FlipflopException.CancelClass.CancelFlow)
|
||||
{
|
||||
break;
|
||||
@@ -403,7 +399,8 @@ namespace Serein.NodeFlow
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Console.Out.WriteLineAsync(ex.Message);
|
||||
env.WriteLine(InfoType.ERROR, $"触发器[{singleFlipFlopNode.Guid}]异常。"+ ex.Message);
|
||||
//await Console.Out.WriteLineAsync(ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
30
NodeFlow/Model/SingleGlobalDataNode.cs
Normal file
30
NodeFlow/Model/SingleGlobalDataNode.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.NodeFlow.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// 全局数据节点
|
||||
/// </summary>
|
||||
public class SingleGlobalDataNode : NodeModelBase
|
||||
{
|
||||
public SingleGlobalDataNode(IFlowEnvironment environment) : base(environment)
|
||||
{
|
||||
}
|
||||
|
||||
public override ParameterData[] GetParameterdatas()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void OnCreating()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -206,10 +206,8 @@ namespace Serein.NodeFlow.Tool
|
||||
private (NodeLibraryInfo, List<MethodDetailsInfo>) LoadDllNodeInfo(string dllFilePath)
|
||||
{
|
||||
var fileName = Path.GetFileName(dllFilePath); // 获取文件名
|
||||
|
||||
if (SereinLibraryDll.Equals(fileName))
|
||||
{
|
||||
|
||||
return LoadAssembly(typeof(IFlowEnvironment).Assembly, () => {
|
||||
//SereinEnv.PrintInfo(InfoType.WRAN, "基础模块不能卸载");
|
||||
});
|
||||
|
||||
@@ -15,13 +15,14 @@ namespace Serein.Workbench
|
||||
{
|
||||
|
||||
#if DEBUG
|
||||
if (1 == 1)
|
||||
if (1 == 0 )
|
||||
{
|
||||
string filePath;
|
||||
filePath = @"F:\临时\project\linux\project.dnf";
|
||||
filePath = @"F:\临时\project\linux\http\project.dnf";
|
||||
filePath = @"F:\临时\project\yolo flow\project.dnf";
|
||||
filePath = @"F:\临时\project\data\project.dnf";
|
||||
filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\Release\net8.0\PLCproject.dnf";
|
||||
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
|
||||
App.FlowProjectData = JsonConvert.DeserializeObject<SereinProjectData>(content);
|
||||
App.FileDataPath = System.IO.Path.GetDirectoryName(filePath)!; // filePath;//
|
||||
|
||||
@@ -578,7 +578,7 @@ namespace Serein.Workbench
|
||||
NodeControlType.Action => CreateNodeControl<ActionNodeControl, ActionNodeControlViewModel>(nodeModelBase), //typeof(ActionNodeControl),
|
||||
NodeControlType.Flipflop => CreateNodeControl<FlipflopNodeControl, FlipflopNodeControlViewModel>(nodeModelBase),
|
||||
NodeControlType.ExpCondition => CreateNodeControl<ConditionNodeControl, ConditionNodeControlViewModel>(nodeModelBase),
|
||||
NodeControlType.ExpOp => CreateNodeControl<ExpOpNodeControl, ExpOpNodeViewModel>(nodeModelBase),
|
||||
NodeControlType.ExpOp => CreateNodeControl<ExpOpNodeControl, ExpOpNodeControlViewModel>(nodeModelBase),
|
||||
NodeControlType.ConditionRegion => CreateNodeControl<ConditionRegionControl, ConditionRegionNodeControlViewModel>(nodeModelBase),
|
||||
_ => null,
|
||||
};
|
||||
@@ -2504,7 +2504,7 @@ namespace Serein.Workbench
|
||||
NodeLibraryInfo? library = projectData.Librarys[index];
|
||||
try
|
||||
{
|
||||
string targetPath = System.IO.Path.Combine(librarySavePath, library.FileName); // 目标文件夹
|
||||
string targetPath = System.IO.Path.Combine(librarySavePath, library.FilePath); // 目标文件夹
|
||||
#if WINDOWS
|
||||
string sourceFile = library.FilePath; // 源文件夹
|
||||
#else
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
<!--<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />-->
|
||||
<converters:InvertableBooleanToVisibilityConverter x:Key="InvertedBoolConverter"/>
|
||||
<!--<ResourceDictionary Source="/Serein.Workbench;Node/View/NodeExecuteJunctionControl.xaml" x:Key="NodeExecuteJunctionControl"/>-->
|
||||
|
||||
</UserControl.Resources>
|
||||
|
||||
|
||||
<Border BorderBrush="#8DE9FD" BorderThickness="4">
|
||||
<Grid>
|
||||
<Grid.ToolTip>
|
||||
@@ -24,7 +26,10 @@
|
||||
</Grid.ToolTip>
|
||||
|
||||
<!--<TextBlock Text="{Binding NodelModel.DebugSetting.IsInterrupt}}"></TextBlock>-->
|
||||
<Border x:Name="InterruptBorder" DataContext="{Binding}">
|
||||
<!--DataContext="{Binding}-->
|
||||
|
||||
|
||||
<Border x:Name="InterruptBorder" Tag="{Binding NodeModel.DebugSetting.IsInterrupt}">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<!--默认无边框-->
|
||||
@@ -32,9 +37,9 @@
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Style.Triggers>
|
||||
<!--NodeModel.DebugSetting.IsInterrupt-->
|
||||
<!--<DataTrigger Binding="{Binding DataContext.NodeModel.DebugSetting.IsInterrup, RelativeSource={RelativeSource AncestorType=UserControl}}" Value="True">-->
|
||||
<DataTrigger Binding="{Binding IsInterrupt,Mode=OneTime}" Value="True">
|
||||
<!--<DataTrigger Binding="{Binding NodeModel.DebugSetting.IsInterrup}" Value="True">-->
|
||||
<!--<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:ActionNodeControl}}, Path=DataContext.DebugSetting.IsInterrupt}" Value="True">-->
|
||||
<!--<DataTrigger Binding="{Binding DebugSetting.IsInterrupt, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Value="True">-->
|
||||
<DataTrigger Binding="{Binding Path=Tag,RelativeSource={RelativeSource Mode=Self}}" Value="True">
|
||||
<Setter Property="BorderBrush" Value="Red" />
|
||||
<Setter Property="BorderThickness" Value="2" />
|
||||
<Setter Property="Background" Value="#80000000" />
|
||||
@@ -42,8 +47,12 @@
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
|
||||
|
||||
|
||||
<Grid>
|
||||
|
||||
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
|
||||
@@ -16,7 +16,11 @@ namespace Serein.Workbench.Node.View
|
||||
{
|
||||
DataContext = viewModel;
|
||||
InitializeComponent();
|
||||
if(ExecuteJunctionControl.MyNode != null)
|
||||
{
|
||||
|
||||
ExecuteJunctionControl.MyNode.Guid = viewModel.NodeModel.Guid;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace Serein.Workbench.Node.View
|
||||
DataContext = viewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 入参控制点(可能有,可能没)
|
||||
/// </summary>
|
||||
|
||||
@@ -26,8 +26,6 @@ namespace Serein.Workbench.Node.View
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加条件控件
|
||||
/// </summary>
|
||||
|
||||
@@ -11,11 +11,11 @@ namespace Serein.Workbench.Node.View
|
||||
public ExpOpNodeControl() : base()
|
||||
{
|
||||
// 窗体初始化需要
|
||||
ViewModel = new ExpOpNodeViewModel(new SingleExpOpNode(null));
|
||||
ViewModel = new ExpOpNodeControlViewModel(new SingleExpOpNode(null));
|
||||
DataContext = ViewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
public ExpOpNodeControl(ExpOpNodeViewModel viewModel) :base(viewModel)
|
||||
public ExpOpNodeControl(ExpOpNodeControlViewModel viewModel) :base(viewModel)
|
||||
{
|
||||
DataContext = viewModel;
|
||||
InitializeComponent();
|
||||
|
||||
@@ -55,6 +55,11 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
|
||||
<!--<PackageReference Include="MySqlConnector" Version="2.4.0" />
|
||||
<PackageReference Include="SqlSugarCore" Version="5.1.4.170" />
|
||||
<PackageReference Include="SqlSugarCoreNoDrive" Version="5.1.4.171" />-->
|
||||
|
||||
<!--<PackageReference Include="LivetCask2" Version="4.0.2" />-->
|
||||
<!--<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />-->
|
||||
</ItemGroup>
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
Visibility="{Binding IsParams, Mode=OneWay,
|
||||
Converter={StaticResource InvertedBoolConverter},ConverterParameter=Normal}"
|
||||
/>
|
||||
|
||||
<ContentControl Content="{Binding}" Grid.Column="4" VerticalAlignment="Center">
|
||||
<ContentControl.Style>
|
||||
<Style TargetType="ContentControl">
|
||||
|
||||
75
Workbench/Node/View/GlobalDataControl.xaml
Normal file
75
Workbench/Node/View/GlobalDataControl.xaml
Normal file
@@ -0,0 +1,75 @@
|
||||
<local:NodeControlBase x:Class="Serein.Workbench.Node.View.GlobalDataControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Serein.Workbench.Node.View"
|
||||
xmlns:vm="clr-namespace:Serein.Workbench.Node.ViewModel"
|
||||
d:DataContext="{d:DesignInstance vm:GlobalDataNodeControlViewModel}"
|
||||
mc:Ignorable="d"
|
||||
MaxWidth="300">
|
||||
<UserControl.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVis" />
|
||||
</UserControl.Resources>
|
||||
|
||||
|
||||
<Grid>
|
||||
<Grid.ToolTip>
|
||||
<ToolTip Background="LightYellow" Foreground="Black" Content="{Binding NodeModel.MethodDetails.MethodAnotherName, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</Grid.ToolTip>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid Grid.Row="0" Background="#E7EFF5" >
|
||||
<!--<Grid Grid.Row="0" >-->
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<local:ExecuteJunctionControl Grid.Column="0" MyNode="{Binding NodeModel}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/>
|
||||
<Border Grid.Column="1" BorderThickness="1" HorizontalAlignment="Stretch">
|
||||
<TextBlock Text="全局数据" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<local:NextStepJunctionControl Grid.Column="2" MyNode="{Binding NodeModel}" x:Name="NextStepJunctionControl" HorizontalAlignment="Right" Grid.RowSpan="2"/>
|
||||
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" Background="#FEFAF4" HorizontalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="名称" Margin="2" HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1" MinWidth="50" Margin="2" Text="{Binding NodeModel.CustomData, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Center">
|
||||
</TextBox>
|
||||
<StackPanel Grid.Row="1" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<TextBlock Text="设置数据源" Margin="2" HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
|
||||
<local:ResultJunctionControl Grid.Column="2" MyNode="{Binding NodelModel}" x:Name="ResultJunctionControl" HorizontalAlignment="Right"/>
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
|
||||
|
||||
<!--<themes:MethodDetailsControl Grid.Row="1" MethodDetails="{Binding MethodDetails}" />
|
||||
<Border Grid.Row="2" Background="#EAFFD0" BorderBrush="#EAFFD0" BorderThickness="1">
|
||||
<TextBlock Text="{Binding MethodDetails.MethodTips, Converter={StaticResource TypeToStringConverter}, StringFormat=return:{0}, UpdateSourceTrigger=PropertyChanged}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
</Border>-->
|
||||
</Grid>
|
||||
</local:NodeControlBase>
|
||||
62
Workbench/Node/View/GlobalDataControl.xaml.cs
Normal file
62
Workbench/Node/View/GlobalDataControl.xaml.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using Serein.NodeFlow.Model;
|
||||
using Serein.Workbench.Node.ViewModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace Serein.Workbench.Node.View
|
||||
{
|
||||
/// <summary>
|
||||
/// UserControl1.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class GlobalDataControl : NodeControlBase, INodeJunction
|
||||
{
|
||||
|
||||
public GlobalDataControl() : base()
|
||||
{
|
||||
// 窗体初始化需要
|
||||
ViewModel = new GlobalDataNodeControlViewModel(new SingleGlobalDataNode(null));
|
||||
DataContext = ViewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public GlobalDataControl(ConditionNodeControlViewModel viewModel) : base(viewModel)
|
||||
{
|
||||
DataContext = viewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 入参控制点(可能有,可能没)
|
||||
/// </summary>
|
||||
JunctionControlBase INodeJunction.ExecuteJunction => this.ExecuteJunctionControl;
|
||||
|
||||
/// <summary>
|
||||
/// 下一个调用方法控制点(可能有,可能没)
|
||||
/// </summary>
|
||||
JunctionControlBase INodeJunction.NextStepJunction => this.NextStepJunctionControl;
|
||||
|
||||
/// <summary>
|
||||
/// 返回值控制点(可能有,可能没)
|
||||
/// </summary>
|
||||
JunctionControlBase INodeJunction.ReturnDataJunction => this.ResultJunctionControl;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 方法入参控制点(可能有,可能没)
|
||||
/// </summary>
|
||||
JunctionControlBase[] INodeJunction.ArgDataJunction => throw new NotImplementedException();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using Serein.Workbench.Node.View;
|
||||
|
||||
namespace Serein.Workbench.Node.ViewModel
|
||||
{
|
||||
public class ExpOpNodeViewModel: NodeControlViewModelBase
|
||||
public class ExpOpNodeControlViewModel: NodeControlViewModelBase
|
||||
{
|
||||
public new SingleExpOpNode NodeModel { get; }
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Serein.Workbench.Node.ViewModel
|
||||
//}
|
||||
|
||||
|
||||
public ExpOpNodeViewModel(SingleExpOpNode nodeModel) : base(nodeModel)
|
||||
public ExpOpNodeControlViewModel(SingleExpOpNode nodeModel) : base(nodeModel)
|
||||
{
|
||||
this.NodeModel = nodeModel;
|
||||
}
|
||||
18
Workbench/Node/ViewModel/GlobalDataNodeControlViewModel.cs
Normal file
18
Workbench/Node/ViewModel/GlobalDataNodeControlViewModel.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Serein.NodeFlow.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Workbench.Node.ViewModel
|
||||
{
|
||||
public class GlobalDataNodeControlViewModel : NodeControlViewModelBase
|
||||
{
|
||||
public new SingleGlobalDataNode NodelModel { get; }
|
||||
public GlobalDataNodeControlViewModel(SingleGlobalDataNode node) : base(node)
|
||||
{
|
||||
this.NodelModel = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user