using Serein.Library; using Serein.Library.Api; using Serein.Script; using System.Dynamic; using System.Linq.Expressions; namespace Serein.NodeFlow.Model.Nodes { /// /// 条件节点(用于条件控件) /// [FlowDataProperty(ValuePath = NodeValuePath.Node, IsNodeImp = true)] public partial class SingleConditionNode : NodeModelBase { /// /// 是否为自定义参数 /// [DataInfo(IsNotification = true)] private bool _isExplicitData; /// /// 自定义参数值 /// [DataInfo(IsNotification = true)] private string? _explicitData; /// /// 条件表达式 /// [DataInfo(IsNotification = true)] private string _expression; } public partial class SingleConditionNode : NodeModelBase { /// /// 条件表达式节点是基础节点 /// public override bool IsBase => true; /// /// 表达式参数索引 /// private const int INDEX_EXPRESSION = 0; /// /// 条件节点构造函数 /// /// public SingleConditionNode(IFlowEnvironment environment):base(environment) { this.IsExplicitData = false; this.ExplicitData = string.Empty; this.Expression = "PASS"; } /// /// 创建节点时调用的方法 /// public override void OnCreating() { // 这里的这个参数是为了方便使用入参控制点,参数无意义 var pd = new ParameterDetails[1]; pd[INDEX_EXPRESSION] = new ParameterDetails { Index = INDEX_EXPRESSION, Name = nameof(Expression), IsExplicitData = false, DataValue = string.Empty, DataType = typeof(string), ExplicitType = typeof(string), ArgDataSourceNodeGuid = string.Empty, ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData, NodeModel = this, //Convertor = null, InputType = ParameterValueInputType.Input, Items = null, Description = "条件节点入参控制点" }; this.MethodDetails.ParameterDetailss = [..pd]; } /// /// 导出方法信息 /// /// /// public override NodeInfo SaveCustomData(NodeInfo nodeInfo) { dynamic data = new ExpandoObject(); data.Expression = Expression ?? ""; data.ExplicitData = ExplicitData ?? ""; data.IsExplicitData = IsExplicitData; nodeInfo.CustomData = data; return nodeInfo; } /// /// 加载自定义数据 /// /// public override void LoadCustomData(NodeInfo nodeInfo) { this.Expression = nodeInfo.CustomData?.Expression ?? ""; this.ExplicitData = nodeInfo.CustomData?.ExplicitData ?? ""; this.IsExplicitData = nodeInfo.CustomData?.IsExplicitData ?? false; } /// /// 重写节点的方法执行 /// /// /// /// public override async Task ExecutingAsync(IFlowContext context, CancellationToken token) { if (token.IsCancellationRequested) { return FlowResult.Fail(this.Guid, context, "流程已通过token取消"); } // 接收上一节点参数or自定义参数内容 object? parameter; object? result = null; if (!IsExplicitData) { // 使用自动取参 var pd = MethodDetails.ParameterDetailss[INDEX_EXPRESSION]; var hasNode = context.Env.TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var argSourceNode); if (!hasNode) { /*context.NextOrientation = ConnectionInvokeType.IsError; return new FlowResult(this.Guid, context);*/ parameter = null; } else { if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData) { result = context.GetFlowData(argSourceNode.Guid).Value; // 使用自定义节点的参数 } else if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke) { CancellationTokenSource cts = new CancellationTokenSource(); var nodeResult = await argSourceNode.ExecutingAsync(context, cts.Token); result = nodeResult.Value; cts?.Cancel(); cts?.Dispose(); } else { result = context.TransmissionData(this.Guid).Value; // 条件节点透传上一节点的数据 } parameter = result; // 使用上一节点的参数 } } else { var exp = ExplicitData?.ToString(); if (!string.IsNullOrWhiteSpace(exp) && exp.StartsWith("@Get", StringComparison.OrdinalIgnoreCase)) { parameter = GetValueExpressionAsync(context, result, exp); } else { parameter = ExplicitData; // 使用自定义的参数 } } bool judgmentResult = false; try { judgmentResult = await ConditionExpressionAsync(context, parameter, Expression); //judgmentResult = SereinConditionParser.To(parameter, Expression); context.NextOrientation = judgmentResult ? ConnectionInvokeType.IsSucceed : ConnectionInvokeType.IsFail; } catch (Exception ex) { context.NextOrientation = ConnectionInvokeType.IsError; context.ExceptionOfRuning = ex; } SereinEnv.WriteLine(InfoType.INFO, $"{Expression} -> " + context.NextOrientation); //return result; return FlowResult.OK(this.Guid, context, parameter); } /// /// 解析取值表达式 /// private SereinScript getValueScript; private string getValueExpression; private async Task GetValueExpressionAsync(IFlowContext flowContext, object? data, string expression) { var dataName = nameof(data); if (!expression.Equals(getValueExpression)) { getValueExpression = expression; getValueScript = new SereinScript(); var dataType = data is null ? typeof(object) : data.GetType(); if (expression[0..4].Equals("@get", StringComparison.CurrentCultureIgnoreCase)) { getValueExpression = expression[4..]; // 表达式默认包含 “.” getValueExpression = $"return {dataName}{expression};"; } else { // 表达式默认包含 “.” getValueExpression = $"return {getValueExpression};"; } var resultType = getValueScript.ParserScript(getValueExpression, new Dictionary { { dataName, dataType}, }); } IScriptInvokeContext scriptContext = new ScriptInvokeContext(); scriptContext.SetVarValue(dataName, data); var result = await getValueScript.InterpreterAsync(scriptContext); return result; } /// /// 解析条件 /// private SereinScript conditionScript; private string conditionExpression; private async Task ConditionExpressionAsync(IFlowContext flowContext, object? data, string expression) { var dataName = nameof(data); if (!expression.Equals(conditionExpression)) { conditionExpression = expression.Trim(); conditionScript = new SereinScript(); var dataType = data is null ? typeof(object) : data.GetType(); if (expression[0] == '.') { // 对象取值 conditionExpression = $"return {dataName}{conditionExpression};"; } else { // 直接表达式 conditionExpression = $"return {dataName}.{conditionExpression};"; } var resultType = conditionScript.ParserScript(conditionExpression, new Dictionary { { dataName, dataType}, }); } IScriptInvokeContext scriptContext = new ScriptInvokeContext(); scriptContext.SetVarValue(dataName, data); var result = await conditionScript.InterpreterAsync(scriptContext); if(result is bool @bool) { return @bool; } else { flowContext.NextOrientation = ConnectionInvokeType.IsError; return false; } } } }