using Serein.Library; using Serein.Library.Api; using System.Dynamic; namespace Serein.NodeFlow.Model.Nodes { /// /// Expression Operation - 表达式操作 /// [NodeProperty(ValuePath = NodeValuePath.Node)] public partial class SingleGlobalDataNode : NodeModelBase { /// /// 全局数据的Key名称 /// [PropertyInfo(IsNotification = true)] private string _keyName; } /// /// 全局数据节点 /// public partial class SingleGlobalDataNode : NodeModelBase, INodeContainer { string INodeContainer.Guid => this.Guid; /// /// 全局数据节点是基础节点 /// public override bool IsBase => true; /// /// 数据源只允许放置1个节点。 /// public override int MaxChildrenCount => 1; public SingleGlobalDataNode(IFlowEnvironment environment) : base(environment) { } /// /// 数据来源的节点 /// public IFlowNode? DataNode { get; private set; } = null; /// /// 有节点被放置 /// /// /// public bool PlaceNode(IFlowNode nodeModel) { if(nodeModel.ControlType is not (NodeControlType.Action or NodeControlType.Script)) { SereinEnv.WriteLine(InfoType.INFO, "放置在全局数据必须是有返回值的[Action]节点,[Script]节点。"); return false; } if (nodeModel.MethodDetails?.ReturnType is null || nodeModel.MethodDetails.ReturnType == typeof(void)) { SereinEnv.WriteLine(InfoType.INFO, "放置在全局数据必须是有返回值的[Action]节点,[Script]节点。"); return false; } if(DataNode is null) { // 放置节点 nodeModel.ContainerNode = this; ChildrenNode.Add(nodeModel); DataNode = nodeModel; MethodDetails.IsAsync = nodeModel.MethodDetails.IsAsync; MethodDetails.ReturnType = nodeModel.MethodDetails.ReturnType; return true; } else if (DataNode.Guid != nodeModel.Guid) { Env.FlowEdit.TakeOutNodeToContainer(DataNode.CanvasDetails.Guid, DataNode.Guid); Env.FlowEdit.PlaceNodeToContainer(this.CanvasDetails.Guid, nodeModel.Guid, this.Guid); return false; } return false; } public bool TakeOutNode(IFlowNode nodeModel) { if (ChildrenNode.Contains(nodeModel)) { ChildrenNode.Remove(nodeModel); nodeModel.ContainerNode = null; DataNode = null; return true; } else { return false; } } public async void TakeOutAll() { foreach (var nodeModel in ChildrenNode) { nodeModel.Env.FlowEdit.TakeOutNodeToContainer(nodeModel.CanvasDetails.Guid, nodeModel.Guid); } DataNode = null; } /// /// 设置全局数据 /// /// /// public override async Task ExecutingAsync(IFlowContext context, CancellationToken token) { if (token.IsCancellationRequested) return new FlowResult(this.Guid, context); if (string.IsNullOrEmpty(KeyName)) { context.NextOrientation = ConnectionInvokeType.IsError; SereinEnv.WriteLine(InfoType.ERROR, $"全局数据的KeyName不能为空[{this.Guid}]"); return new FlowResult(this.Guid, context); } if (DataNode is null) { context.NextOrientation = ConnectionInvokeType.IsError; SereinEnv.WriteLine(InfoType.ERROR, $"全局数据节点没有设置数据来源[{this.Guid}]"); return new FlowResult(this.Guid, context); } try { var result = await DataNode.ExecutingAsync(context, token); SereinEnv.AddOrUpdateFlowGlobalData(KeyName, result.Value); return result; } catch (Exception ex) { context.NextOrientation = ConnectionInvokeType.IsError; context.ExceptionOfRuning = ex; return new FlowResult(this.Guid, context); } } /// /// 保存全局变量的数据 /// /// /// public override NodeInfo SaveCustomData(NodeInfo nodeInfo) { dynamic data = new ExpandoObject(); data.KeyName = KeyName; // 变量名称 nodeInfo.CustomData = data; return nodeInfo; } /// /// 加载全局变量的数据 /// /// public override void LoadCustomData(NodeInfo nodeInfo) { KeyName = nodeInfo.CustomData?.KeyName; } /* /// /// 需要移除数据节点 /// public override void Remove() { if (DataNode is null) { return; } // 移除数据节点 _ = this.Env.RemoveNodeAsync(DataNode.CanvasDetails.Guid, DataNode.Guid); }*/ } }