|
|
|
|
using DS.Module.Core.Data;
|
|
|
|
|
using DS.Module.Core.Extensions;
|
|
|
|
|
using DS.WMS.Core.Flow.Dtos;
|
|
|
|
|
using DS.WMS.Core.Flow.Entity;
|
|
|
|
|
using Mapster;
|
|
|
|
|
using Newtonsoft.Json;
|
|
|
|
|
using SqlSugar;
|
|
|
|
|
|
|
|
|
|
namespace DS.WMS.Core.Flow.Method;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
///
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class FlowRuntime
|
|
|
|
|
{
|
|
|
|
|
ISqlSugarClient db { get; set; }
|
|
|
|
|
ISqlSugarClient tenantDb { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 构造函数
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="instance"></param>
|
|
|
|
|
/// <param name="_db"></param>
|
|
|
|
|
public FlowRuntime(FlowInstance instance, ISqlSugarClient _db) : this(instance, _db, null)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 构造函数
|
|
|
|
|
/// </summary>
|
|
|
|
|
public FlowRuntime(FlowInstance instance, ISqlSugarClient _db, ISqlSugarClient? tenantDb)
|
|
|
|
|
{
|
|
|
|
|
ArgumentNullException.ThrowIfNull(instance, nameof(instance));
|
|
|
|
|
|
|
|
|
|
db = _db;
|
|
|
|
|
BusinessId = instance.BusinessId;
|
|
|
|
|
ColumnView = instance.ColumnView;
|
|
|
|
|
this.tenantDb = tenantDb;
|
|
|
|
|
|
|
|
|
|
ReadJson(instance.Content); //获取工作流模板内容的json对象;
|
|
|
|
|
|
|
|
|
|
CurrentNodeId = instance.ActivityId == "" ? StartNodeId : instance.ActivityId;
|
|
|
|
|
CurrentNodeType = GetNodeType(CurrentNodeId);
|
|
|
|
|
PreviousId = instance.PreviousId;
|
|
|
|
|
|
|
|
|
|
//会签开始节点和流程结束节点没有下一步
|
|
|
|
|
if (CurrentNodeType == 0 || CurrentNodeType == 4)
|
|
|
|
|
{
|
|
|
|
|
NextNodeId = "-1";
|
|
|
|
|
NextNodeType = -1;
|
|
|
|
|
}
|
|
|
|
|
else if (CurrentNodeType == 5)
|
|
|
|
|
{
|
|
|
|
|
NextNodeId = GetNextConditionNodeId(CurrentNode); //下一个节点
|
|
|
|
|
NextNodeType = GetNodeType(NextNodeId);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NextNodeId = GetNextNodeId(CurrentNodeId); //下一个节点
|
|
|
|
|
if (string.IsNullOrEmpty(NextNodeId) && CurrentNodeType == 3)
|
|
|
|
|
{
|
|
|
|
|
//当前节点类型为开始节点,且没有下一级节点,则认为应跳出工作流
|
|
|
|
|
ShouldSkip = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NextNodeType = GetNodeType(NextNodeId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 业务ID
|
|
|
|
|
/// </summary>
|
|
|
|
|
public long BusinessId { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 查询对象名
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string ColumnView { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 是否应跳过工作流执行
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool ShouldSkip { get; private set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 开始节点的ID
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string StartNodeId { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当前节点的ID
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string CurrentNodeId { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当前节点类型 0会签开始,1会签结束,2一般节点,开始节点,4流程运行结束
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int CurrentNodeType { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当前节点的对象
|
|
|
|
|
/// </summary>
|
|
|
|
|
public FlowChild CurrentNode => ChildNodes.First(x => x.Id == CurrentNodeId);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 下一个节点
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string NextNodeId { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 下一个节点类型 -1无法运行,0会签开始,1会签结束,2一般节点,4流程运行结束,5同级审批
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int NextNodeType { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 下一个节点对象
|
|
|
|
|
/// </summary>
|
|
|
|
|
public FlowChild? NextNode => NextNodeId != "-1" ? ChildNodes.First(x => x.Id == NextNodeId) : null;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 上一个节点
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string PreviousId { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 实例节点集合
|
|
|
|
|
/// </summary>
|
|
|
|
|
public List<FlowChild> ChildNodes { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 备注
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string? Note { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取工作流节点的字典列表:key节点id
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="schemeContentJson"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
private void ReadJson(string schemeContentJson)
|
|
|
|
|
{
|
|
|
|
|
ChildNodes = [];
|
|
|
|
|
|
|
|
|
|
var root = JsonConvert.DeserializeObject<FlowRoot>(schemeContentJson);
|
|
|
|
|
if (root.Type == FlowChild.START)
|
|
|
|
|
{
|
|
|
|
|
StartNodeId = root.Id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (root.Child.IsNotNull())
|
|
|
|
|
{
|
|
|
|
|
var parent = root.Adapt<FlowChild>();
|
|
|
|
|
ChildNodes.Add(parent);
|
|
|
|
|
GetFlowChildsByParent(parent.Id, parent);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 撤销流程,清空所有节点
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void Cancel()
|
|
|
|
|
{
|
|
|
|
|
foreach (var item in ChildNodes)
|
|
|
|
|
{
|
|
|
|
|
item.SetInfo = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void GetFlowChildsByParent(string nodeId, FlowChild parent)
|
|
|
|
|
{
|
|
|
|
|
if (parent.Type == FlowChild.Exclusive && parent.Children.IsNotNull() && parent.Children.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
foreach (var item in parent.Children)
|
|
|
|
|
{
|
|
|
|
|
ChildNodes.Add(item);
|
|
|
|
|
GetFlowChildsByParent(nodeId, item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (parent.Child.IsNotNull())
|
|
|
|
|
{
|
|
|
|
|
ChildNodes.Add(parent.Child);
|
|
|
|
|
GetFlowChildsByParent(parent.Child.Id, parent.Child);
|
|
|
|
|
}
|
|
|
|
|
// var childs = new List<FlowChild>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static List<FlowChild> GetFlowConditions(FlowChild parent)
|
|
|
|
|
{
|
|
|
|
|
var conditionNodes = new List<FlowChild>();
|
|
|
|
|
if (parent.Children != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (var item in parent.Children)
|
|
|
|
|
{
|
|
|
|
|
conditionNodes.Add(item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return conditionNodes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取下一个节点
|
|
|
|
|
/// <param name="nodeId"></param>
|
|
|
|
|
/// </summary>
|
|
|
|
|
private string? GetNextNodeId(string? nodeId = null)
|
|
|
|
|
{
|
|
|
|
|
if (nodeId == null)
|
|
|
|
|
{
|
|
|
|
|
return ChildNodes.Where(x => x.Pid == "root").First()?.Id;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (ChildNodes.Exists(x => x.Pid == nodeId))
|
|
|
|
|
{
|
|
|
|
|
var nextChild = ChildNodes.Where(x => x.Pid == nodeId).First();
|
|
|
|
|
if (nextChild.Type == FlowChild.Exclusive) //互斥条件
|
|
|
|
|
{
|
|
|
|
|
return GetNextConditionNodeId(nextChild); //下一个节点
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return nextChild.Id;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return ChildNodes.Where(x => x.Id == "end").First()?.Id;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取下一个条件节点
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="parent"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public string? GetNextConditionNodeId(FlowChild parent)
|
|
|
|
|
{
|
|
|
|
|
var conditionNodes = GetFlowConditions(parent);
|
|
|
|
|
var conditionId = string.Empty;
|
|
|
|
|
ISqlSugarClient sugarClient = tenantDb ?? db;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < conditionNodes.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
var conditionNode = conditionNodes[i];
|
|
|
|
|
|
|
|
|
|
if (i == conditionNodes.Count - 1)
|
|
|
|
|
{
|
|
|
|
|
conditionId = conditionNode.Id;
|
|
|
|
|
}
|
|
|
|
|
else if (conditionNode.UseSQL)
|
|
|
|
|
{
|
|
|
|
|
var scalar = sugarClient.Ado.GetScalar(conditionNode.SQLText,
|
|
|
|
|
new SugarParameter(nameof(BaseModel<long>.Id), BusinessId));
|
|
|
|
|
|
|
|
|
|
if (scalar != null && (scalar is int count && count > 0 || scalar is bool boolValue && boolValue))
|
|
|
|
|
{
|
|
|
|
|
conditionId = conditionNode.Id;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var nodeSection = conditionNode.Conditions;
|
|
|
|
|
var list = new List<ConditionalCollections>();
|
|
|
|
|
var conditionList = new List<KeyValuePair<WhereType, ConditionalModel>>(nodeSection.Conditions.Count);
|
|
|
|
|
|
|
|
|
|
var whereType = Enum.Parse<WhereType>(nodeSection.LogicalOperator, true);
|
|
|
|
|
foreach (var item in nodeSection.Conditions)
|
|
|
|
|
{
|
|
|
|
|
conditionList.Add(new KeyValuePair<WhereType, ConditionalModel>
|
|
|
|
|
(whereType,
|
|
|
|
|
new ConditionalModel
|
|
|
|
|
{
|
|
|
|
|
FieldName = item.Field,
|
|
|
|
|
ConditionalType = GetConditionalType(item.Operator),
|
|
|
|
|
FieldValue = item.Value
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (conditionList.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
list.Add(new ConditionalCollections
|
|
|
|
|
{
|
|
|
|
|
ConditionalList = conditionList
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var groupList = new List<KeyValuePair<WhereType, ConditionalModel>>();
|
|
|
|
|
foreach (var group in nodeSection.Groups)
|
|
|
|
|
{
|
|
|
|
|
WhereType whereType2 = Enum.Parse<WhereType>(group.LogicalOperator, true);
|
|
|
|
|
for (int j = 0; j < group.Conditions.Count; j++)
|
|
|
|
|
{
|
|
|
|
|
var item1 = group.Conditions[j];
|
|
|
|
|
groupList.Add(new KeyValuePair<WhereType, ConditionalModel>
|
|
|
|
|
(j == 0 ? whereType : whereType2,
|
|
|
|
|
new ConditionalModel
|
|
|
|
|
{
|
|
|
|
|
FieldName = item1.Field,
|
|
|
|
|
ConditionalType = GetConditionalType(item1.Operator),
|
|
|
|
|
FieldValue = item1.Value
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (groupList.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
list.Add(new ConditionalCollections
|
|
|
|
|
{
|
|
|
|
|
ConditionalList = groupList
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (list.Count == 0) //跳过默认条件
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
List<IConditionalModel> conditionalModels = [.. list];
|
|
|
|
|
var exists = sugarClient.Queryable<object>().AS(ColumnView).Where("Id=@Id", new { Id = BusinessId }).Where(conditionalModels).Any();
|
|
|
|
|
if (exists)
|
|
|
|
|
{
|
|
|
|
|
conditionId = conditionNode.Id;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var node = ChildNodes.Find(x => x.Pid == conditionId);
|
|
|
|
|
return node?.Id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取下一个节点
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="nodeId"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public FlowChild GetNextNode(string? nodeId = null)
|
|
|
|
|
{
|
|
|
|
|
if (nodeId == null)
|
|
|
|
|
return ChildNodes.Where(x => x.Pid == "root").First();
|
|
|
|
|
|
|
|
|
|
if (ChildNodes.Exists(x => x.Pid == nodeId))
|
|
|
|
|
{
|
|
|
|
|
var nextChild = ChildNodes.Where(x => x.Pid == nodeId).First();
|
|
|
|
|
if (nextChild.Type == FlowChild.Exclusive)
|
|
|
|
|
{
|
|
|
|
|
var childId = GetNextConditionNodeId(nextChild);
|
|
|
|
|
return ChildNodes.Where(x => x.Id == childId).First(); //下一个节点
|
|
|
|
|
}
|
|
|
|
|
//todo:前端组织JSON结构有误,加入临时修复代码,待前端改正后移除
|
|
|
|
|
else if (nextChild.Type == null)
|
|
|
|
|
{
|
|
|
|
|
nextChild.Id = nextChild.Type = FlowChild.END;
|
|
|
|
|
nextChild.Name = "结束";
|
|
|
|
|
Note = "JSON结构有误,检测到没有指定类型的节点";
|
|
|
|
|
return nextChild;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nextChild;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return ChildNodes.Where(x => x.Id == "end").First();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 转换FlowRoot
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public FlowRoot ToFlowRoot()
|
|
|
|
|
{
|
|
|
|
|
var root = ChildNodes.First(x => x.Id == "root");
|
|
|
|
|
|
|
|
|
|
var list = ChildNodes.Where(x => x.Id != "root").ToList();
|
|
|
|
|
var info = root.Adapt<FlowRoot>();
|
|
|
|
|
info.Child = list.First(x => x.Pid == "root");
|
|
|
|
|
UpdateChild(info.Child);
|
|
|
|
|
|
|
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UpdateChild(FlowChild parent)
|
|
|
|
|
{
|
|
|
|
|
if (parent.Type == FlowChild.Exclusive)
|
|
|
|
|
{
|
|
|
|
|
if (ChildNodes.Exists(x => x.Pid == parent.Id && x.Type != "condition"))
|
|
|
|
|
{
|
|
|
|
|
var child = ChildNodes.Where(x => x.Pid == parent.Id && x.Type != "condition").First();
|
|
|
|
|
parent.Child = child;
|
|
|
|
|
UpdateChild(child);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var childs = ChildNodes.Where(x => x.Pid == parent.Id && x.Type == "condition").ToList();
|
|
|
|
|
parent.Children = childs;
|
|
|
|
|
foreach (var item in childs)
|
|
|
|
|
{
|
|
|
|
|
UpdateChild(item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (parent.Type != FlowChild.Exclusive && ChildNodes.Exists(x => x.Pid == parent.Id))
|
|
|
|
|
{
|
|
|
|
|
var child = ChildNodes.Where(x => x.Pid == parent.Id).First();
|
|
|
|
|
parent.Child = child;
|
|
|
|
|
UpdateChild(parent.Child);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UpdateFlowChild(string nodeId, FlowChild parent)
|
|
|
|
|
{
|
|
|
|
|
// var childs = new List<FlowChild>();
|
|
|
|
|
if (parent.Type == FlowChild.Exclusive && parent.Children.IsNotNull() && parent.Children.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < parent.Children.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
if (parent.Children[0].Id == nodeId)
|
|
|
|
|
{
|
|
|
|
|
var newNode = ChildNodes.First(x => x.Id == nodeId);
|
|
|
|
|
parent.Children[0] = newNode;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (parent.Child.IsNotNull())
|
|
|
|
|
{
|
|
|
|
|
if (parent.Child.Id == nodeId)
|
|
|
|
|
{
|
|
|
|
|
var newNode = ChildNodes.First(x => x.Id == nodeId);
|
|
|
|
|
parent.Child = newNode;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取实例接下来运行的状态
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>-1无法运行,0开始,1结束,2一般节点,4流程运行结束</returns>
|
|
|
|
|
public int GetNextNodeType()
|
|
|
|
|
{
|
|
|
|
|
if (NextNodeId != "-1")
|
|
|
|
|
{
|
|
|
|
|
return GetNodeType(NextNodeId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 转换SqlSugar 条件操作符
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="conditionalType"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
private static ConditionalType GetConditionalType(string conditionalType)
|
|
|
|
|
{
|
|
|
|
|
return conditionalType switch
|
|
|
|
|
{
|
|
|
|
|
//等于
|
|
|
|
|
"equal" => ConditionalType.Equal,
|
|
|
|
|
//不等于
|
|
|
|
|
"not_equal" => ConditionalType.NoEqual,
|
|
|
|
|
//大于
|
|
|
|
|
"GreaterThan" => ConditionalType.GreaterThan,
|
|
|
|
|
//大于等于
|
|
|
|
|
"GreaterThanOrEqual" => ConditionalType.GreaterThanOrEqual,
|
|
|
|
|
//小于
|
|
|
|
|
"LessThan" => ConditionalType.LessThan,
|
|
|
|
|
//小于等于
|
|
|
|
|
"LessThanOrEqual" => ConditionalType.GreaterThanOrEqual,
|
|
|
|
|
//包含
|
|
|
|
|
"contains" => ConditionalType.In,
|
|
|
|
|
//不包含
|
|
|
|
|
"not_contain" => ConditionalType.NotIn,
|
|
|
|
|
//默认
|
|
|
|
|
_ => ConditionalType.Equal,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取节点类型 0会签开始,1会签结束,2一般节点,3开始节点,4流程运行结束
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="nodeId"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public int GetNodeType(string nodeId)
|
|
|
|
|
{
|
|
|
|
|
return ChildNodes.Where(x => x.Id == nodeId).First().Type switch
|
|
|
|
|
{
|
|
|
|
|
//会签开始节点
|
|
|
|
|
FlowChild.Approval => 0,
|
|
|
|
|
//会签结束节点
|
|
|
|
|
FlowChild.JOIN => 1,
|
|
|
|
|
//结束节点
|
|
|
|
|
FlowChild.END => 4,
|
|
|
|
|
//开始节点
|
|
|
|
|
FlowChild.START => 3,
|
|
|
|
|
//互斥条件
|
|
|
|
|
FlowChild.Exclusive => 5,
|
|
|
|
|
//互斥条件
|
|
|
|
|
FlowChild.Dynamic => 6,
|
|
|
|
|
//一般节点
|
|
|
|
|
_ => 2,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 驳回
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="rejectType">驳回类型。null:使用节点配置的驳回类型/0:前一步/1:第一步/2:指定节点,使用NodeRejectStep</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public string RejectNode(string rejectType)
|
|
|
|
|
{
|
|
|
|
|
var node = ChildNodes.Where(x => x.Id == CurrentNodeId).First();
|
|
|
|
|
if (node.SetInfo != null && string.IsNullOrEmpty(rejectType))
|
|
|
|
|
{
|
|
|
|
|
rejectType = node.SetInfo.NodeRejectType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rejectType == "0")
|
|
|
|
|
{
|
|
|
|
|
return PreviousId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rejectType == "1")
|
|
|
|
|
{
|
|
|
|
|
return GetNextNodeId(StartNodeId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return PreviousId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///<summary>
|
|
|
|
|
/// 标记节点 1通过,2不通过,3驳回
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="nodeId"></param>
|
|
|
|
|
public void MakeTagNode(string nodeId, FlowTag tag)
|
|
|
|
|
{
|
|
|
|
|
// var node = ChildNodes.First(x => x.Id == nodeId);
|
|
|
|
|
foreach (var item in ChildNodes)
|
|
|
|
|
{
|
|
|
|
|
if (item.Id == nodeId)
|
|
|
|
|
{
|
|
|
|
|
if (item.SetInfo == null)
|
|
|
|
|
{
|
|
|
|
|
item.SetInfo = new Setinfo();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
item.SetInfo.Taged = tag.Taged;
|
|
|
|
|
item.SetInfo.UserId = tag.UserId;
|
|
|
|
|
item.SetInfo.UserName = tag.UserName;
|
|
|
|
|
item.SetInfo.Description = tag.Description;
|
|
|
|
|
item.SetInfo.TagedTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 节点审核
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="nodeId">会签时,currentNodeId是会签开始节点。这个表示当前正在处理的节点</param>
|
|
|
|
|
/// <param name="tag">节点标签</param>
|
|
|
|
|
/// <returns>-1不通过,1等待,其它通过</returns>
|
|
|
|
|
public string NodeConfluence(string nodeId, FlowTag tag)
|
|
|
|
|
{
|
|
|
|
|
var forkNode = ChildNodes.First(x => x.Id == CurrentNodeId); //会签开始节点
|
|
|
|
|
FlowChild nextNode = GetNextNode(nodeId); //获取当前处理的下一个节点
|
|
|
|
|
|
|
|
|
|
int forkNumber = 0;
|
|
|
|
|
if (forkNode.AssigneeType == "user")
|
|
|
|
|
{
|
|
|
|
|
forkNumber = forkNode.Users.Count;
|
|
|
|
|
}
|
|
|
|
|
else if (forkNode.AssigneeType == "role")
|
|
|
|
|
{
|
|
|
|
|
forkNumber = forkNode.Roles.Count;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
forkNumber = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// int forkNumber = FromNodeLines[currentNodeId].Count; //直接与会签节点连接的点,即会签分支数目
|
|
|
|
|
string res = string.Empty; //记录会签的结果,默认正在会签
|
|
|
|
|
//或签
|
|
|
|
|
if (forkNode.Multi == "single") //有一个步骤通过即可
|
|
|
|
|
{
|
|
|
|
|
if (tag.Taged == (int)TagState.Ok)
|
|
|
|
|
{
|
|
|
|
|
res = nextNode.Id;
|
|
|
|
|
}
|
|
|
|
|
else if (tag.Taged == (int)TagState.No)
|
|
|
|
|
{
|
|
|
|
|
if (forkNode.SetInfo.ConfluenceNo == null)
|
|
|
|
|
{
|
|
|
|
|
forkNode.SetInfo.ConfluenceNo = 1;
|
|
|
|
|
if (forkNode.SetInfo.ConfluenceNo == forkNumber)
|
|
|
|
|
{
|
|
|
|
|
res = TagState.No.ToString("D");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (forkNode.SetInfo.ConfluenceNo == (forkNumber - 1))
|
|
|
|
|
{
|
|
|
|
|
res = TagState.No.ToString("D");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
forkNode.SetInfo.ConfluenceNo++;
|
|
|
|
|
// bool isFirst = true; //是不是从会签开始到现在第一个
|
|
|
|
|
// var preNode = GetPreNode(nodeId);
|
|
|
|
|
// while (preNode.id != forkNode.id) //反向一直到会签开始节点
|
|
|
|
|
// {
|
|
|
|
|
// if (preNode.setInfo != null && preNode.setInfo.Taged == (int) TagState.No)
|
|
|
|
|
// {
|
|
|
|
|
// isFirst = false;
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// if (isFirst)
|
|
|
|
|
// {
|
|
|
|
|
// forkNode.SetInfo.ConfluenceNo++;
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//会签
|
|
|
|
|
else //默认所有步骤通过
|
|
|
|
|
{
|
|
|
|
|
if (tag.Taged == (int)TagState.No) //只要有一个不同意,那么流程就结束
|
|
|
|
|
{
|
|
|
|
|
res = TagState.No.ToString("D");
|
|
|
|
|
}
|
|
|
|
|
else if (tag.Taged == (int)TagState.Ok)
|
|
|
|
|
{
|
|
|
|
|
//这种模式下只有坚持到【会签结束】节点之前才有意义,是否需要判定这条线所有的节点都通过,不然直接执行这个节点??
|
|
|
|
|
if (forkNode.SetInfo.ConfluenceOk == null)
|
|
|
|
|
{
|
|
|
|
|
forkNode.SetInfo.ConfluenceOk = 1;
|
|
|
|
|
|
|
|
|
|
if (forkNode.SetInfo.ConfluenceOk == forkNumber)
|
|
|
|
|
{
|
|
|
|
|
res = nextNode.Id;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//同一节点的会签,未达到所有审核人同意时,节点类型设置为5
|
|
|
|
|
NextNodeType = 5;
|
|
|
|
|
res = nodeId;
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
forkNode.SetInfo.ConfluenceOk++;
|
|
|
|
|
|
|
|
|
|
if (forkNode.SetInfo.ConfluenceOk == forkNumber) //会签成功
|
|
|
|
|
{
|
|
|
|
|
res = nextNode.Id;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//同一节点的会签,未达到所有审核人同意时,节点类型设置为5
|
|
|
|
|
NextNodeType = 5;
|
|
|
|
|
res = nodeId;
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (res == TagState.No.ToString("D"))
|
|
|
|
|
{
|
|
|
|
|
tag.Taged = (int)TagState.No;
|
|
|
|
|
MakeTagNode(nextNode.Id, tag);
|
|
|
|
|
NextNodeId = nextNode.Id;
|
|
|
|
|
NextNodeType = GetNodeType(nextNode.Id);
|
|
|
|
|
}
|
|
|
|
|
else if (!string.IsNullOrEmpty(res)) //会签结束,标记合流节点
|
|
|
|
|
{
|
|
|
|
|
tag.Taged = (int)TagState.Ok;
|
|
|
|
|
// MakeTagNode(nextNode.Id, tag);
|
|
|
|
|
NextNodeId = res;
|
|
|
|
|
NextNodeType = GetNodeType(res);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NextNodeId = nextNode.Id;
|
|
|
|
|
NextNodeType = GetNodeType(nextNode.Id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal string GetOtherUsers(FlowTag tag)
|
|
|
|
|
{
|
|
|
|
|
var forkNode = ChildNodes.First(x => x.Id == CurrentNodeId);
|
|
|
|
|
//int index = forkNode.Users.IndexOf(tag.UserId);
|
|
|
|
|
//if (index > -1 && index <= forkNode.Users.Count - 2)
|
|
|
|
|
// return forkNode.Users[index + 1];
|
|
|
|
|
|
|
|
|
|
if (!forkNode.Users.IsNullOrEmpty())
|
|
|
|
|
{
|
|
|
|
|
return string.Join(',',
|
|
|
|
|
forkNode.Users.Except([tag.UserId]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return string.Empty;
|
|
|
|
|
}
|
|
|
|
|
}
|