2024-10-20 12:10:57 +08:00
|
|
|
|
using Serein.Library;
|
|
|
|
|
|
using Serein.Library.Api;
|
2024-12-12 20:31:50 +08:00
|
|
|
|
using Serein.Library.Utils;
|
2025-07-18 22:45:06 +08:00
|
|
|
|
using Serein.NodeFlow.Env;
|
2025-07-04 11:35:34 +08:00
|
|
|
|
using Serein.NodeFlow.Model;
|
2025-07-29 14:25:31 +08:00
|
|
|
|
using Serein.NodeFlow.Model.Nodes;
|
2024-12-12 20:31:50 +08:00
|
|
|
|
using System.Collections.Concurrent;
|
2024-12-23 23:19:10 +08:00
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
|
using System.Reflection;
|
2025-07-06 14:34:49 +08:00
|
|
|
|
using System.Text;
|
2024-10-20 12:10:57 +08:00
|
|
|
|
|
2024-12-23 23:19:10 +08:00
|
|
|
|
namespace Serein.NodeFlow
|
2024-10-20 12:10:57 +08:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 流程环境需要的扩展方法
|
|
|
|
|
|
/// </summary>
|
2025-03-20 22:54:10 +08:00
|
|
|
|
public static class FlowNodeExtension
|
2024-10-20 12:10:57 +08:00
|
|
|
|
{
|
2024-12-09 22:57:06 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 判断是否为基础节点
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public static bool IsBaseNode(this NodeControlType nodeControlType)
|
|
|
|
|
|
{
|
2024-12-23 23:19:10 +08:00
|
|
|
|
var nodeDesc = EnumHelper.GetAttribute<NodeControlType, DescriptionAttribute>(nodeControlType);
|
2025-06-01 12:21:38 +08:00
|
|
|
|
if("base".Equals(nodeDesc?.Description, StringComparison.OrdinalIgnoreCase))
|
2024-12-09 22:57:06 +08:00
|
|
|
|
{
|
2025-06-01 12:21:38 +08:00
|
|
|
|
return true;
|
2024-12-09 22:57:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2024-10-20 12:10:57 +08:00
|
|
|
|
|
2025-07-07 20:40:24 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 是否为根节点
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="node"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public static bool IsRoot(this IFlowNode node)
|
|
|
|
|
|
{
|
|
|
|
|
|
var cts = NodeStaticConfig.ConnectionTypes;
|
|
|
|
|
|
foreach (var ct in cts)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (node.PreviousNodes[ct].Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-12 20:31:50 +08:00
|
|
|
|
|
2024-10-20 12:10:57 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建节点
|
|
|
|
|
|
/// </summary>
|
2025-07-18 22:45:06 +08:00
|
|
|
|
/// <param name="envIOC">运行环境使用的IOC</param>
|
2024-10-20 12:10:57 +08:00
|
|
|
|
/// <param name="nodeControlType">节点类型</param>
|
|
|
|
|
|
/// <param name="methodDetails">方法描述</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
/// <exception cref="Exception"></exception>
|
2025-07-18 22:45:06 +08:00
|
|
|
|
public static IFlowNode CreateNode(ISereinIOC envIOC, NodeControlType nodeControlType, MethodDetails? methodDetails = null)
|
2024-10-20 12:10:57 +08:00
|
|
|
|
{
|
|
|
|
|
|
|
2024-12-12 20:31:50 +08:00
|
|
|
|
// 尝试获取需要创建的节点类型
|
2025-07-18 22:45:06 +08:00
|
|
|
|
var flowEdit = envIOC.Get<IFlowEdit>();
|
|
|
|
|
|
if (!flowEdit.NodeMVVMManagement.TryGetType(nodeControlType, out var nodeMVVM) || nodeMVVM.ModelType == null)
|
2024-10-20 12:10:57 +08:00
|
|
|
|
{
|
2024-12-12 20:31:50 +08:00
|
|
|
|
throw new Exception($"无法创建{nodeControlType}节点,节点类型尚未注册。");
|
2024-10-20 12:10:57 +08:00
|
|
|
|
}
|
2024-12-12 20:31:50 +08:00
|
|
|
|
|
2025-07-04 15:46:29 +08:00
|
|
|
|
|
2024-10-20 12:10:57 +08:00
|
|
|
|
// 生成实例
|
2025-07-04 15:46:29 +08:00
|
|
|
|
//var nodeObj = Activator.CreateInstance(nodeMVVM.ModelType, env);
|
2025-07-18 22:45:06 +08:00
|
|
|
|
var nodeObj = envIOC.CreateObject(nodeMVVM.ModelType);
|
2025-05-31 12:15:01 +08:00
|
|
|
|
if (nodeObj is not IFlowNode nodeModel)
|
2024-10-20 12:10:57 +08:00
|
|
|
|
{
|
|
|
|
|
|
throw new Exception($"无法创建目标节点类型的实例[{nodeControlType}]");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 配置基础的属性
|
|
|
|
|
|
nodeModel.ControlType = nodeControlType;
|
|
|
|
|
|
if (methodDetails == null) // 不存在方法描述时,可能是基础节点(表达式节点、条件表达式节点)
|
|
|
|
|
|
{
|
|
|
|
|
|
methodDetails = new MethodDetails();
|
|
|
|
|
|
}
|
2024-11-02 22:11:38 +08:00
|
|
|
|
var md = methodDetails.CloneOfNode(nodeModel);
|
2024-10-28 15:21:08 +08:00
|
|
|
|
nodeModel.DisplayName = md.MethodAnotherName;
|
2024-10-20 12:10:57 +08:00
|
|
|
|
nodeModel.MethodDetails = md;
|
2024-11-02 16:48:40 +08:00
|
|
|
|
nodeModel.OnCreating();
|
2024-10-20 12:10:57 +08:00
|
|
|
|
return nodeModel;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-12-21 20:47:31 +08:00
|
|
|
|
|
|
|
|
|
|
|
2024-10-20 12:10:57 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 程序集封装依赖
|
|
|
|
|
|
/// </summary>
|
2024-11-03 18:28:16 +08:00
|
|
|
|
/// <param name="libraryInfo"></param>
|
2024-10-20 12:10:57 +08:00
|
|
|
|
/// <returns></returns>
|
2025-07-28 12:16:29 +08:00
|
|
|
|
public static FlowLibraryInfo ToLibrary(this FlowLibraryInfo libraryInfo)
|
2024-10-20 12:10:57 +08:00
|
|
|
|
{
|
2025-07-28 12:16:29 +08:00
|
|
|
|
return new FlowLibraryInfo
|
2024-10-20 12:10:57 +08:00
|
|
|
|
{
|
2024-11-03 18:28:16 +08:00
|
|
|
|
AssemblyName = libraryInfo.AssemblyName,
|
|
|
|
|
|
FileName = libraryInfo.FileName,
|
|
|
|
|
|
FilePath = libraryInfo.FilePath,
|
2024-10-20 12:10:57 +08:00
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-07 20:40:24 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-08-02 22:04:13 +08:00
|
|
|
|
/*/// <summary>
|
2024-10-20 12:10:57 +08:00
|
|
|
|
/// 触发器运行后状态转为对应的后继分支类别
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="flowStateType"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
/// <exception cref="NotImplementedException"></exception>
|
2024-10-24 23:32:43 +08:00
|
|
|
|
public static ConnectionInvokeType ToContentType(this FlipflopStateType flowStateType)
|
2024-10-20 12:10:57 +08:00
|
|
|
|
{
|
|
|
|
|
|
return flowStateType switch
|
|
|
|
|
|
{
|
2024-10-24 23:32:43 +08:00
|
|
|
|
FlipflopStateType.Succeed => ConnectionInvokeType.IsSucceed,
|
|
|
|
|
|
FlipflopStateType.Fail => ConnectionInvokeType.IsFail,
|
|
|
|
|
|
FlipflopStateType.Error => ConnectionInvokeType.IsError,
|
|
|
|
|
|
FlipflopStateType.Cancel => ConnectionInvokeType.None,
|
2024-10-20 12:10:57 +08:00
|
|
|
|
_ => throw new NotImplementedException("未定义的流程状态")
|
|
|
|
|
|
};
|
2025-08-02 22:04:13 +08:00
|
|
|
|
}*/
|
2024-10-20 12:10:57 +08:00
|
|
|
|
|
2025-07-07 20:40:24 +08:00
|
|
|
|
|
|
|
|
|
|
|
2024-10-20 12:10:57 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 判断 触发器节点 是否存在上游分支
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="node"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public static bool NotExitPreviousNode(this SingleFlipflopNode node)
|
|
|
|
|
|
{
|
2024-10-24 23:32:43 +08:00
|
|
|
|
ConnectionInvokeType[] ct = [ConnectionInvokeType.IsSucceed,
|
|
|
|
|
|
ConnectionInvokeType.IsFail,
|
|
|
|
|
|
ConnectionInvokeType.IsError,
|
|
|
|
|
|
ConnectionInvokeType.Upstream];
|
|
|
|
|
|
foreach (ConnectionInvokeType ctType in ct)
|
2024-10-20 12:10:57 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (node.PreviousNodes[ctType].Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-07-06 14:34:49 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 添加代码
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="sb">字符串构建器</param>
|
|
|
|
|
|
/// <param name="retractCount">缩进次数(4个空格)</param>
|
|
|
|
|
|
/// <param name="code">要添加的代码</param>
|
2025-07-30 21:15:07 +08:00
|
|
|
|
/// <param name="isWrapping">是否换行</param>
|
2025-07-06 14:34:49 +08:00
|
|
|
|
/// <returns>字符串构建器本身</returns>
|
2025-07-07 20:40:24 +08:00
|
|
|
|
public static StringBuilder AppendCode(this StringBuilder sb,
|
2025-07-06 14:34:49 +08:00
|
|
|
|
int retractCount = 0,
|
2025-07-30 21:15:07 +08:00
|
|
|
|
string? code = null,
|
2025-07-07 20:40:24 +08:00
|
|
|
|
bool isWrapping = true)
|
2025-07-06 14:34:49 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(code))
|
|
|
|
|
|
{
|
2025-07-07 20:40:24 +08:00
|
|
|
|
string retract = new string(' ', retractCount * 4);
|
|
|
|
|
|
sb.Append(retract);
|
|
|
|
|
|
if (isWrapping)
|
|
|
|
|
|
{
|
|
|
|
|
|
sb.AppendLine(code);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
sb.Append(code);
|
|
|
|
|
|
}
|
2025-07-06 14:34:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
return sb;
|
|
|
|
|
|
}
|
2025-07-07 20:40:24 +08:00
|
|
|
|
|
2025-07-06 14:34:49 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-10-20 12:10:57 +08:00
|
|
|
|
///// <summary>
|
|
|
|
|
|
///// 从节点类型枚举中转为对应的 Model 类型
|
|
|
|
|
|
///// </summary>
|
|
|
|
|
|
///// <param name="nodeControlType"></param>
|
|
|
|
|
|
///// <returns></returns>
|
|
|
|
|
|
//public static Type? ControlTypeToModel(this NodeControlType nodeControlType)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// // 确定创建的节点类型
|
|
|
|
|
|
// Type? nodeType = nodeControlType switch
|
|
|
|
|
|
// {
|
|
|
|
|
|
// NodeControlType.Action => typeof(SingleActionNode),
|
|
|
|
|
|
// NodeControlType.Flipflop => typeof(SingleFlipflopNode),
|
|
|
|
|
|
|
|
|
|
|
|
// NodeControlType.ExpOp => typeof(SingleExpOpNode),
|
|
|
|
|
|
// NodeControlType.ExpCondition => typeof(SingleConditionNode),
|
|
|
|
|
|
// NodeControlType.ConditionRegion => typeof(CompositeConditionNode),
|
|
|
|
|
|
// _ => null
|
|
|
|
|
|
// };
|
|
|
|
|
|
// return nodeType;
|
|
|
|
|
|
//}
|
|
|
|
|
|
//public static NodeControlType ModelToControlType(this NodeControlType nodeControlType)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// var type = nodeControlType.GetType();
|
|
|
|
|
|
// NodeControlType controlType = type switch
|
|
|
|
|
|
// {
|
|
|
|
|
|
// Type when type == typeof(SingleActionNode) => NodeControlType.Action,
|
|
|
|
|
|
// Type when type == typeof(SingleFlipflopNode) => NodeControlType.Flipflop,
|
|
|
|
|
|
|
|
|
|
|
|
// Type when type == typeof(SingleExpOpNode) => NodeControlType.ExpOp,
|
|
|
|
|
|
// Type when type == typeof(SingleConditionNode) => NodeControlType.ExpCondition,
|
|
|
|
|
|
// Type when type == typeof(CompositeConditionNode) => NodeControlType.ConditionRegion,
|
|
|
|
|
|
// _ => NodeControlType.None,
|
|
|
|
|
|
// };
|
|
|
|
|
|
// return controlType;
|
|
|
|
|
|
//}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-06 14:34:49 +08:00
|
|
|
|
|
|
|
|
|
|
|
2024-10-20 12:10:57 +08:00
|
|
|
|
}
|