You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

718 lines
22 KiB
C#

using DS.Module.Core.Data;
10 months ago
using DS.Module.Core.Extensions;
using DS.WMS.Core.Flow.Dtos;
using DS.WMS.Core.Flow.Entity;
using Mapster;
using Newtonsoft.Json;
using SqlSugar;
10 months ago
namespace DS.WMS.Core.Flow.Method;
/// <summary>
///
/// </summary>
public class FlowRuntime
10 months ago
{
readonly ISqlSugarClient db;
readonly ISqlSugarClient? tenantDb;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="instance"></param>
/// <param name="_db"></param>
public FlowRuntime(FlowInstance instance, ISqlSugarClient _db) : this(instance, _db, null)
6 months ago
{
}
10 months ago
/// <summary>
/// 构造函数
/// </summary>
public FlowRuntime(FlowInstance instance, ISqlSugarClient _db, ISqlSugarClient? tenantDb)
{
ArgumentNullException.ThrowIfNull(instance, nameof(instance));
db = _db;
this.tenantDb = tenantDb;
InstanceId = instance.Id;
BusinessId = instance.BusinessId;
ColumnView = instance.ColumnView;
ReadJson(instance.Content); //获取工作流模板内容的json对象;
10 months ago
CurrentNodeId = instance.ActivityId == "" ? StartNodeId : instance.ActivityId;
10 months ago
CurrentNodeType = GetNodeType(CurrentNodeId);
PreviousId = instance.PreviousId;
//会签开始节点和流程结束节点没有下一步
if (CurrentNodeType == 0 || CurrentNodeType == 4)
10 months ago
{
NextNodeId = "-1";
NextNodeType = -1;
}
else if (CurrentNodeType == 5)
{
NextNodeId = GetNextConditionNodeId(CurrentNode); //下一个节点
NextNodeType = GetNodeType(NextNodeId);
}
10 months ago
else
{
NextNodeId = GetNextNodeId(CurrentNodeId); //下一个节点
if (string.IsNullOrEmpty(NextNodeId) && CurrentNodeType == 3)
{
//当前节点类型为开始节点,且没有下一级节点,则认为应跳出工作流
ShouldSkip = true;
}
else
{
NextNodeType = GetNodeType(NextNodeId);
}
10 months ago
}
}
/// <summary>
/// 当前实例ID
/// </summary>
public long InstanceId { get; set; }
/// <summary>
/// 业务ID
/// </summary>
public long BusinessId { get; set; }
10 months ago
/// <summary>
/// 查询对象名
/// </summary>
public string? ColumnView { get; set; }
10 months ago
/// <summary>
/// 是否应跳过工作流执行
10 months ago
/// </summary>
public bool ShouldSkip { get; private set; }
10 months ago
/// <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);
10 months ago
/// <summary>
/// 下一个节点
/// </summary>
public string? NextNodeId { get; set; }
10 months ago
/// <summary>
/// 下一个节点类型 -1无法运行,0会签开始,1会签结束,2一般节点,4流程运行结束,5同级审批
10 months ago
/// </summary>
public int NextNodeType { get; set; }
/// <summary>
/// 下一个节点对象
/// </summary>
public FlowChild? NextNode => NextNodeId != "-1" ? ChildNodes.First(x => x.Id == NextNodeId) : null;
10 months ago
/// <summary>
/// 上一个节点
/// </summary>
public string PreviousId { get; set; }
/// <summary>
/// 实例节点集合
/// </summary>
public List<FlowChild> ChildNodes { get; set; }
/// <summary>
/// 备注
/// </summary>
public string? Note { get; set; }
10 months ago
/// <summary>
/// 获取工作流节点的字典列表:key节点id
/// </summary>
/// <param name="schemeContentJson"></param>
/// <returns></returns>
private void ReadJson(string schemeContentJson)
10 months ago
{
ChildNodes = [];
10 months ago
var root = JsonConvert.DeserializeObject<FlowRoot>(schemeContentJson);
if (root.Type == FlowChild.START)
{
StartNodeId = root.Id;
10 months ago
}
if (root.Child.IsNotNull())
{
10 months ago
var parent = root.Adapt<FlowChild>();
ChildNodes.Add(parent);
GetFlowChildsByParent(parent.Id, parent);
10 months ago
}
}
/// <summary>
/// 撤销流程,清空所有节点
/// </summary>
public void Cancel()
{
foreach (var item in ChildNodes)
{
item.SetInfo = null;
}
}
private void GetFlowChildsByParent(string nodeId, FlowChild parent)
10 months ago
{
if (parent.Type == FlowChild.Exclusive && parent.Children.IsNotNull() && parent.Children.Count > 0)
{
foreach (var item in parent.Children)
10 months ago
{
ChildNodes.Add(item);
10 months ago
GetFlowChildsByParent(nodeId, item);
}
}
10 months ago
if (parent.Child.IsNotNull())
{
10 months ago
ChildNodes.Add(parent.Child);
GetFlowChildsByParent(parent.Child.Id, parent.Child);
10 months ago
}
// var childs = new List<FlowChild>();
10 months ago
}
private static List<FlowChild> GetFlowConditions(FlowChild parent)
10 months ago
{
var conditionNodes = new List<FlowChild>();
if (parent.Children != null)
10 months ago
{
foreach (var item in parent.Children)
{
conditionNodes.Add(item);
}
}
10 months ago
return conditionNodes;
}
10 months ago
10 months ago
/// <summary>
/// 获取下一个节点
/// <param name="nodeId"></param>
/// </summary>
private string? GetNextNodeId(string? nodeId = null)
10 months ago
{
if (nodeId == null)
{
return ChildNodes.Where(x => x.Pid == "root").First()?.Id;
10 months ago
}
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)
10 months ago
{
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);
6 months ago
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
})
);
}
6 months ago
if (conditionList.Count > 0)
{
list.Add(new ConditionalCollections
{
ConditionalList = conditionList
});
6 months ago
}
var groupList = new List<KeyValuePair<WhereType, ConditionalModel>>();
foreach (var group in nodeSection.Groups)
6 months ago
{
WhereType whereType2 = Enum.Parse<WhereType>(group.LogicalOperator, true);
for (int j = 0; j < group.Conditions.Count; j++)
6 months ago
{
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
})
);
6 months ago
}
}
6 months ago
if (groupList.Count > 0)
{
list.Add(new ConditionalCollections
6 months ago
{
ConditionalList = groupList
});
}
6 months ago
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;
}
10 months ago
}
10 months ago
}
var node = ChildNodes.Find(x => x.Pid == conditionId);
return node?.Id;
10 months ago
}
10 months ago
/// <summary>
/// 获取下一个节点
/// </summary>
/// <param name="nodeId"></param>
/// <returns></returns>
public FlowChild GetNextNode(string? nodeId = null)
10 months ago
{
if (nodeId == null)
return ChildNodes.Where(x => x.Pid == "root").First();
if (ChildNodes.Exists(x => x.Pid == nodeId))
10 months ago
{
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();
10 months ago
}
}
/// <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;
}
}
}
10 months ago
/// <summary>
/// 获取实例接下来运行的状态
/// </summary>
/// <returns>-1无法运行,0开始,1结束,2一般节点,4流程运行结束</returns>
public int GetNextNodeType()
{
if (NextNodeId != "-1")
{
return GetNodeType(NextNodeId);
}
10 months ago
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,
};
}
10 months ago
/// <summary>
/// 获取节点类型 0会签开始,1会签结束,2一般节点,3开始节点,4流程运行结束
10 months ago
/// </summary>
/// <param name="nodeId"></param>
/// <returns></returns>
public int GetNodeType(string? nodeId)
10 months ago
{
return ChildNodes.Where(x => x.Id == nodeId).First()?.Type switch
10 months ago
{
//会签开始节点
FlowChild.Approval => 0,
10 months ago
//会签结束节点
FlowChild.JOIN => 1,
10 months ago
//结束节点
FlowChild.END => 4,
10 months ago
//开始节点
FlowChild.START => 3,
//互斥条件
FlowChild.Exclusive => 5,
10 months ago
//一般节点
_ => 2,
};
10 months ago
}
/// <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();
10 months ago
if (node.SetInfo != null && string.IsNullOrEmpty(rejectType))
{
rejectType = node.SetInfo.NodeRejectType;
}
10 months ago
if (rejectType == "0")
{
return PreviousId;
}
10 months ago
if (rejectType == "1")
{
return GetNextNodeId(StartNodeId);
}
return PreviousId;
}
10 months ago
///<summary>
/// 标记节点 1通过2不通过3驳回
10 months ago
/// </summary>
/// <param name="nodeId"></param>
public void MakeTagNode(string nodeId, FlowTag tag)
10 months ago
{
// var node = ChildNodes.First(x => x.Id == nodeId);
foreach (var item in ChildNodes)
10 months ago
{
if (item.Id == nodeId)
10 months ago
{
if (item.SetInfo == null)
10 months ago
{
item.SetInfo = new Setinfo();
10 months ago
}
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");
10 months ago
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;
}
10 months ago
}