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.

713 lines
22 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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;
}
}