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.

547 lines
16 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.

// <summary>
// 一个正在运行中的流程实例
//</summary>
// ***********************************************************************
using Magic.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
namespace Magic.FlowCenter.Entity;
/// <summary>
/// 流程运行类
/// </summary>
public class FlowRuntime
{
/// <summary>
/// 构造函数
/// </summary>
public FlowRuntime(FlcFlowinstance instance)
{
var schemeContentJson = instance.SchemeContent.ToObject<Flow>();//获取工作流模板内容的json对象;
InitFlow(schemeContentJson);
currentNodeId = (string.IsNullOrEmpty(instance.ActivityId)? startNodeId : instance.ActivityId);
currentNodeType = GetNodeType(currentNodeId);
FrmData = instance.FrmData;
previousId = GetPreviousNodeId(currentNodeId);
flowInstanceId = instance.Id;
//会签开始节点和流程结束节点没有下一步
if (currentNodeType == 0 || currentNodeType == 4)
{
nextNodeId = "-1";
nextNodeType = -1;
}
else
{
nextNodeId = GetNextNodeId();//下一个节点
nextNodeType = GetNodeType(nextNodeId);
}
}
#region 私有方法
/// <summary>
/// 获取工作流信息
/// </summary>
/// <param name="schemeContentJson"></param>
/// <returns></returns>
private void InitFlow(Flow schemeContentJson)
{
flow = schemeContentJson;
InitLines(schemeContentJson);
InitNodes(schemeContentJson);
}
/// <summary>
/// 获取工作流节点的字典列表:key节点id
/// </summary>
/// <param name="schemeContentJson"></param>
/// <returns></returns>
private void InitNodes(Flow schemeContentJson)
{
Nodes = new Dictionary<string, FlowNode>();
foreach (var item in schemeContentJson.nodeList)
{
var node = item;
if (!Nodes.ContainsKey(node.id))
{
Nodes.Add(node.id, node);
}
if (node.type == FlowNode.START)
{
this.startNodeId = node.id;
}
}
}
private void InitLines(Flow schemeContentJson)
{
Lines = new List<FlowLine>();
FromNodeLines = new Dictionary<string, List<FlowLine>>();
ToNodeLines = new Dictionary<string, List<FlowLine>>();
foreach (var item in schemeContentJson.linkList)
{
var line = item;
Lines.Add(line);
if (!FromNodeLines.ContainsKey(line.sourceId))
{
List<FlowLine> d = new List<FlowLine> { line };
FromNodeLines.Add(line.sourceId, d);
}
else
{
FromNodeLines[line.sourceId].Add(line);
}
if (!ToNodeLines.ContainsKey(line.targetId))
{
List<FlowLine> d = new List<FlowLine> { line };
ToNodeLines.Add(line.targetId, d);
}
else
{
ToNodeLines[line.targetId].Add(line);
}
}
}
/// <summary>
/// 获取下一个节点
/// </summary>
private string GetNextNodeId(string nodeId = null)
{
var lines = nodeId == null ? FromNodeLines[currentNodeId] : FromNodeLines[nodeId];
if (lines.Count == 0)
{
throw new Exception("无法寻找到下一个节点");
}
if (string.IsNullOrEmpty(FrmData)) return lines[0].targetId;
FrmData = FrmData.ToLower();//统一转小写
var frmDataJson = FrmData.ToJObject();//获取数据内容
foreach (var l in lines)
{
if (l.Compares==null)
{
l.Compares = new List<DataCompare>();
}
if (l.Compares.Count>0 &&l.Compare(frmDataJson))
{
return l.targetId;
}
}
return lines[0].targetId;
}
/// <summary>
/// 获取上一个节点
/// </summary>
private string GetPreviousNodeId(string nodeId = null)
{
try
{
var lines = nodeId == null ? ToNodeLines[currentNodeId] : ToNodeLines[nodeId];
if (lines.Count == 0)
{
return string.Empty;
}
if (FrmData == "") return lines[0].sourceId;
FrmData = FrmData.ToLower();//统一转小写
var frmDataJson = FrmData.ToJObject();//获取数据内容
foreach (var l in lines)
{
if (l.Compares == null)
{
l.Compares = new List<DataCompare>();
}
if (l.Compares.Count > 0 && l.Compare(frmDataJson))
{
return l.sourceId;
}
}
return lines[0].sourceId;
}
catch (Exception)
{
return string.Empty;
}
}
#endregion 私有方法
#region 共有方法
/// <summary>
/// 获取下一个节点
/// </summary>
/// <param name="nodeId"></param>
/// <returns></returns>
public FlowNode GetNextNode(string nodeId = null)
{
return Nodes[GetNextNodeId(nodeId)];
}
/// <summary>
/// 获取实例接下来运行的状态
/// </summary>
/// <returns>-1无法运行,0会签开始,1会签结束,2一般节点,4流程运行结束</returns>
public int GetNextNodeType()
{
if (nextNodeId != "-1")
{
return GetNodeType(nextNodeId);
}
return -1;
}
/// <summary>
/// 获取节点类型 0会签开始,1会签结束,2一般节点,开始节点,4流程运行结束
/// </summary>
/// <param name="nodeId"></param>
/// <returns></returns>
public int GetNodeType(string nodeId)
{
switch (Nodes[nodeId].type)
{
//会签开始节点
case FlowNode.FORK:
return 0;
//会签结束节点
case FlowNode.JOIN:
return 1;
//结束节点
case FlowNode.END:
return 4;
//开始节点
case FlowNode.START:
return 3;
default:
return 2;
}
}
/// <summary>
/// 删除节点
/// </summary>
/// <param name="nodeId"></param>
public void RemoveNode(string nodeId)
{
var node = Nodes[nodeId];
if (node != null && node.setInfo != null)
{
node.setInfo.Taged = null;
node.setInfo.UserName = null;
node.setInfo.UserId = null;
node.setInfo.Description = null;
node.setInfo.TagedTime = null;
}
}
/// <summary>
/// 删除全部节点
/// </summary>
public void RemoveNodes()
{
foreach (var item in Nodes)
{
var node = item.Value;
if (node != null && node.setInfo != null)
{
node.setInfo.Taged = null;
node.setInfo.UserName = null;
node.setInfo.UserId = null;
node.setInfo.Description = null;
node.setInfo.TagedTime = null;
}
}
}
/// <summary>
/// 节点会签审核
/// </summary>
/// <param name="nodeId">会签时currentNodeId是会签开始节点。这个表示当前正在处理的节点</param>
/// <param name="tag"></param>
/// <returns>-1不通过,1等待,其它通过</returns>
public string NodeConfluence(string nodeId, Tag tag)
{
var forkNode = Nodes[currentNodeId]; //会签开始节点
FlowNode nextNode = GetNextNode(nodeId); //获取当前处理的下一个节点
int forkNumber = FromNodeLines[currentNodeId].Count; //直接与会签节点连接的点,即会签分支数目
string res =string.Empty; //记录会签的结果,默认正在会签
if (forkNode.setInfo.NodeConfluenceType == "one") //有一个步骤通过即可
{
if (tag.Taged == (int) TagState.Ok)
{
if (nextNode.type == FlowNode.JOIN) //下一个节点是会签结束,则该线路结束
{
res = GetNextNodeId(nextNode.id);
}
}
else if(tag.Taged ==(int) TagState.No)
{
if (forkNode.setInfo.ConfluenceNo == null)
{
forkNode.setInfo.ConfluenceNo = 1;
}
else if (forkNode.setInfo.ConfluenceNo == (forkNumber - 1))
{
res = TagState.No.ToString("D");
}
else
{
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 (nextNode.type == FlowNode.JOIN) //这种模式下只有坚持到【会签结束】节点之前才有意义,是否需要判定这条线所有的节点都通过,不然直接执行这个节点??
{
if (forkNode.setInfo.ConfluenceOk == null)
{
forkNode.setInfo.ConfluenceOk = 1;
}
else if (forkNode.setInfo.ConfluenceOk == (forkNumber - 1)) //会签成功
{
res = GetNextNodeId(nextNode.id);
}
else
{
forkNode.setInfo.ConfluenceOk++;
}
}
}
}
if (res == TagState.No.ToString("D"))
{
tag.Taged = (int) TagState.No;
MakeTagNode(nextNode.id, tag);
}
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;
}
/// <summary>
/// 获取上一个节点
/// </summary>
/// <param name="nodeId"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private FlowNode GetPreNode(string nodeId = null)
{
var lines = nodeId == null ? ToNodeLines[currentNodeId] : ToNodeLines[nodeId];
if (lines.Count == 0)
{
throw new Exception("无法找到上一个点");
}
return Nodes[lines[0].sourceId];
}
/// <summary>
/// 驳回
/// </summary>
/// <param name="rejectType">驳回类型。null:使用节点配置的驳回类型/0:前一步/1:第一步/2指定节点使用NodeRejectStep</param>
/// <returns></returns>
public string RejectNode(string rejectType)
{
dynamic node = Nodes[currentNodeId];
if (node.setInfo != null && string.IsNullOrEmpty(rejectType))
{
rejectType = node.setInfo.NodeRejectType;
}
if (rejectType == "0")
{
return previousId;
}
if (rejectType == "1")
{
return startNodeId;
}
return previousId;
}
///<summary>
/// 标记节点1通过2不通过3驳回
/// </summary>
/// <param name="nodeId"></param>
public void MakeTagNode(string nodeId, Tag tag)
{
foreach (var item in Nodes)
{
if (item.Key == nodeId)
{
if (item.Value.setInfo == null)
{
item.Value.setInfo = new Setinfo();
}
item.Value.setInfo.Taged = tag.Taged;
item.Value.setInfo.UserId = tag.UserId;
item.Value.setInfo.UserName = tag.UserName;
item.Value.setInfo.Description = tag.Description;
item.Value.setInfo.TagedTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm");
break;
}
}
}
/// <summary>
/// 获取流程
/// </summary>
/// <returns></returns>
public Flow ToSchemeObj()
{
flow.linkList = Lines;
flow.nodeList = Nodes.Select(u => u.Value).ToList();
return flow;
}
/// <summary>
/// 通知三方系统,节点执行情况
/// </summary>
public void NotifyThirdParty(HttpClient client, Tag tag)
{
if (currentNode.setInfo == null || string.IsNullOrEmpty(currentNode.setInfo.ThirdPartyUrl))
{
return;
}
var postData = new
{
flowInstanceId,
nodeName=currentNode.name,
nodeId = currentNodeId,
userId = tag.UserId,
userName = tag.UserName,
result=tag.Taged, //1通过;2不通过3驳回
description = tag.Description,
execTime = tag.TagedTime,
isFinish = currentNodeType == 4
};
HttpContent httpContent = new StringContent(postData.ToJsonString(), Encoding.UTF8);
httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
client.PostAsync(currentNode.setInfo.ThirdPartyUrl, httpContent);
}
#endregion 共有方法
#region 属性
/// <summary>
/// 流程
/// </summary>
public Flow flow { get; set; }
/// <summary>
/// 运行实例的Id
/// </summary>
public long flowInstanceId { get; 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 FlowNode currentNode => Nodes[currentNodeId];
/// <summary>
/// 下一个节点
/// </summary>
public string nextNodeId { get; set; }
/// <summary>
/// 下一个节点类型 -1无法运行,0会签开始,1会签结束,2一般节点,4流程运行结束
/// </summary>
/// <value>The type of the next node.</value>
public int nextNodeType { get; set; }
/// <summary>
/// 下一个节点对象
/// </summary>
public FlowNode nextNode => Nodes[nextNodeId];
/// <summary>
/// 上一个节点
/// </summary>
public string previousId { get; set; }
/// <summary>
/// 实例节点集合
/// </summary>
public Dictionary<string, FlowNode> Nodes { get; set; }
/// <summary>
/// 流程实例中所有的线段
/// </summary>
public List<FlowLine> Lines { get; set; }
/// <summary>
/// 从节点发出的线段集合
/// </summary>
public Dictionary<string, List<FlowLine>> FromNodeLines { get; set; }
/// <summary>
/// 到达节点的线段集合
/// </summary>
public Dictionary<string, List<FlowLine>> ToNodeLines { get; set; }
/// <summary>
/// 表单数据
/// </summary>
public string FrmData { get; set; }
#endregion 属性
}