2024-12-24 11:01:45 +08:00
|
|
|
|
using Infrastructure;
|
2024-03-06 21:55:21 +08:00
|
|
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
|
using OpenAuth.Repository.Domain;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Net.Http;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using Castle.Core.Internal;
|
2024-12-24 11:01:45 +08:00
|
|
|
|
using Infrastructure.Const;
|
2025-01-09 17:11:11 +08:00
|
|
|
|
using Infrastructure.Extensions;
|
2024-12-24 17:39:06 +08:00
|
|
|
|
using Infrastructure.Extensions.AutofacManager;
|
|
|
|
|
using Infrastructure.Helpers;
|
|
|
|
|
using OpenAuth.App.Interface;
|
2025-01-09 17:11:11 +08:00
|
|
|
|
using OpenAuth.App.Request;
|
2024-12-24 17:39:06 +08:00
|
|
|
|
using SqlSugar;
|
2024-03-06 21:55:21 +08:00
|
|
|
|
|
|
|
|
|
namespace OpenAuth.App.Flow
|
|
|
|
|
{
|
2024-12-24 11:01:45 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 一个正在运行中的流程实例
|
|
|
|
|
/// <para>该类只能通过new实例化,禁止通过容器获取</para>
|
|
|
|
|
/// </summary>
|
2024-03-06 21:55:21 +08:00
|
|
|
|
public class FlowRuntime
|
|
|
|
|
{
|
|
|
|
|
public FlowRuntime(FlowInstance instance)
|
|
|
|
|
{
|
2025-01-15 10:46:50 +08:00
|
|
|
|
flowInstance = instance;
|
2024-11-05 16:25:36 +08:00
|
|
|
|
dynamic schemeContentJson = instance.SchemeContent.ToJson(); //获取工作流模板内容的json对象;
|
2024-03-06 21:55:21 +08:00
|
|
|
|
|
|
|
|
|
InitLines(schemeContentJson);
|
|
|
|
|
InitNodes(schemeContentJson);
|
|
|
|
|
|
2024-12-13 09:48:07 +08:00
|
|
|
|
currentNodeId = instance.ActivityId == "" ? startNodeId : instance.ActivityId;
|
2024-03-06 21:55:21 +08:00
|
|
|
|
currentNodeType = GetNodeType(currentNodeId);
|
|
|
|
|
FrmData = instance.FrmData;
|
|
|
|
|
title = schemeContentJson.title;
|
2024-11-05 16:25:36 +08:00
|
|
|
|
initNum = schemeContentJson.initNum ?? 0;
|
2024-03-06 21:55:21 +08:00
|
|
|
|
previousId = instance.PreviousId;
|
|
|
|
|
flowInstanceId = instance.Id;
|
|
|
|
|
|
|
|
|
|
//会签开始节点和流程结束节点没有下一步
|
|
|
|
|
if (currentNodeType == 0 || currentNodeType == 4)
|
|
|
|
|
{
|
|
|
|
|
nextNodeId = "-1";
|
|
|
|
|
nextNodeType = -1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-11-05 16:25:36 +08:00
|
|
|
|
nextNodeId = GetNextNodeId(); //下一个节点
|
2024-03-06 21:55:21 +08:00
|
|
|
|
nextNodeType = GetNodeType(nextNodeId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region 私有方法
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取工作流节点的字典列表:key节点id
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="schemeContentJson"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
private void InitNodes(dynamic schemeContentJson)
|
|
|
|
|
{
|
|
|
|
|
Nodes = new Dictionary<string, FlowNode>();
|
|
|
|
|
foreach (JObject item in schemeContentJson.nodes)
|
|
|
|
|
{
|
|
|
|
|
var node = item.ToObject<FlowNode>();
|
|
|
|
|
if (!Nodes.ContainsKey(node.id))
|
|
|
|
|
{
|
|
|
|
|
Nodes.Add(node.id, node);
|
|
|
|
|
}
|
2024-11-05 16:25:36 +08:00
|
|
|
|
|
2024-03-06 21:55:21 +08:00
|
|
|
|
if (node.type == FlowNode.START)
|
|
|
|
|
{
|
|
|
|
|
this.startNodeId = node.id;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void InitLines(dynamic schemeContentJson)
|
|
|
|
|
{
|
|
|
|
|
Lines = new List<FlowLine>();
|
|
|
|
|
FromNodeLines = new Dictionary<string, List<FlowLine>>();
|
|
|
|
|
ToNodeLines = new Dictionary<string, List<FlowLine>>();
|
|
|
|
|
foreach (JObject item in schemeContentJson.lines)
|
|
|
|
|
{
|
|
|
|
|
var line = item.ToObject<FlowLine>();
|
|
|
|
|
Lines.Add(line);
|
|
|
|
|
|
|
|
|
|
if (!FromNodeLines.ContainsKey(line.from))
|
|
|
|
|
{
|
|
|
|
|
List<FlowLine> d = new List<FlowLine> { line };
|
|
|
|
|
FromNodeLines.Add(line.from, d);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
FromNodeLines[line.from].Add(line);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ToNodeLines.ContainsKey(line.to))
|
|
|
|
|
{
|
|
|
|
|
List<FlowLine> d = new List<FlowLine> { line };
|
|
|
|
|
ToNodeLines.Add(line.to, d);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ToNodeLines[line.to].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 (FrmData == "" || FrmData == "{}") return lines[0].to;
|
|
|
|
|
|
2024-11-05 16:25:36 +08:00
|
|
|
|
FrmData = FrmData.ToLower(); //统一转小写
|
|
|
|
|
var frmDataJson = FrmData.ToJObject(); //获取数据内容
|
2024-03-06 21:55:21 +08:00
|
|
|
|
|
|
|
|
|
foreach (var l in lines)
|
|
|
|
|
{
|
2024-12-13 09:48:07 +08:00
|
|
|
|
if (!l.Compares.IsNullOrEmpty() && l.Compare(frmDataJson))
|
2024-03-06 21:55:21 +08:00
|
|
|
|
{
|
|
|
|
|
return l.to;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return lines[0].to;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion 私有方法
|
|
|
|
|
|
|
|
|
|
#region 共有方法
|
|
|
|
|
|
|
|
|
|
//获取下一个节点
|
|
|
|
|
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);
|
|
|
|
|
}
|
2024-11-05 16:25:36 +08:00
|
|
|
|
|
2024-03-06 21:55:21 +08:00
|
|
|
|
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">会签时,currentNodeId是会签开始节点。这个表示当前正在处理的节点</param>
|
|
|
|
|
/// <param name="tag"></param>
|
|
|
|
|
/// <returns>-1不通过,1等待,其它通过</returns>
|
2025-01-09 17:11:11 +08:00
|
|
|
|
public string NodeConfluence(HttpClient httpClient, Tag tag)
|
2024-03-06 21:55:21 +08:00
|
|
|
|
{
|
2025-01-09 17:11:11 +08:00
|
|
|
|
var user = AutofacContainerModule.GetService<IAuth>().GetCurrentUser().User;
|
|
|
|
|
//会签时的【当前节点】一直是会签开始节点
|
|
|
|
|
//TODO: 标记会签节点的状态,这个地方感觉怪怪的
|
|
|
|
|
MakeTagNode(currentNodeId, tag);
|
|
|
|
|
|
|
|
|
|
string canCheckId = ""; //寻找当前登录用户可审核的节点Id
|
|
|
|
|
foreach (string fromForkStartNodeId in FromNodeLines[currentNodeId]
|
|
|
|
|
.Select(u => u.to))
|
|
|
|
|
{
|
|
|
|
|
var fromForkStartNode = Nodes[fromForkStartNodeId]; //与会前开始节点直接连接的节点
|
|
|
|
|
canCheckId = GetOneForkLineCanCheckNodeId(fromForkStartNode, tag);
|
|
|
|
|
if (!string.IsNullOrEmpty(canCheckId)) break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (canCheckId == "")
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("审核异常,找不到审核节点");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var content =
|
|
|
|
|
$"{user.Account}-{DateTime.Now:yyyy-MM-dd HH:mm}审批了【{Nodes[canCheckId].name}】" +
|
|
|
|
|
$"结果:{(tag.Taged == 1 ? "同意" : "不同意")},备注:{tag.Description}";
|
2025-01-13 14:56:47 +08:00
|
|
|
|
SaveOperationHis(content);
|
2025-01-09 17:11:11 +08:00
|
|
|
|
|
|
|
|
|
MakeTagNode(canCheckId, tag); //标记审核节点状态
|
|
|
|
|
|
2024-11-05 16:25:36 +08:00
|
|
|
|
var forkNode = Nodes[currentNodeId]; //会签开始节点
|
2025-01-09 17:11:11 +08:00
|
|
|
|
FlowNode nextNode = GetNextNode(canCheckId); //获取当前处理的下一个节点
|
2024-03-06 21:55:21 +08:00
|
|
|
|
|
2024-11-05 16:25:36 +08:00
|
|
|
|
int forkNumber = FromNodeLines[currentNodeId].Count; //直接与会签节点连接的点,即会签分支数目
|
|
|
|
|
string res = string.Empty; //记录会签的结果,默认正在会签
|
2024-03-06 21:55:21 +08:00
|
|
|
|
if (forkNode.setInfo.NodeConfluenceType == "one") //有一个步骤通过即可
|
|
|
|
|
{
|
2024-11-05 16:25:36 +08:00
|
|
|
|
if (tag.Taged == (int)TagState.Ok)
|
2024-03-06 21:55:21 +08:00
|
|
|
|
{
|
2024-11-05 16:25:36 +08:00
|
|
|
|
if (nextNode.type == FlowNode.JOIN) //下一个节点是会签结束,则该线路结束
|
2024-03-06 21:55:21 +08:00
|
|
|
|
{
|
|
|
|
|
res = GetNextNodeId(nextNode.id);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-11-05 16:25:36 +08:00
|
|
|
|
else if (tag.Taged == (int)TagState.No)
|
2024-03-06 21:55:21 +08:00
|
|
|
|
{
|
|
|
|
|
if (forkNode.setInfo.ConfluenceNo == null)
|
|
|
|
|
{
|
|
|
|
|
forkNode.setInfo.ConfluenceNo = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (forkNode.setInfo.ConfluenceNo == (forkNumber - 1))
|
|
|
|
|
{
|
|
|
|
|
res = TagState.No.ToString("D");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-11-05 16:25:36 +08:00
|
|
|
|
bool isFirst = true; //是不是从会签开始到现在第一个
|
2025-01-09 17:11:11 +08:00
|
|
|
|
var preNode = GetPreNode(canCheckId);
|
2024-03-06 21:55:21 +08:00
|
|
|
|
while (preNode.id != forkNode.id) //反向一直到会签开始节点
|
|
|
|
|
{
|
2024-11-05 16:25:36 +08:00
|
|
|
|
if (preNode.setInfo != null && preNode.setInfo.Taged == (int)TagState.No)
|
2024-03-06 21:55:21 +08:00
|
|
|
|
{
|
|
|
|
|
isFirst = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isFirst)
|
|
|
|
|
{
|
|
|
|
|
forkNode.setInfo.ConfluenceNo++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else //默认所有步骤通过
|
|
|
|
|
{
|
2024-11-05 16:25:36 +08:00
|
|
|
|
if (tag.Taged == (int)TagState.No) //只要有一个不同意,那么流程就结束
|
2024-03-06 21:55:21 +08:00
|
|
|
|
{
|
|
|
|
|
res = TagState.No.ToString("D");
|
|
|
|
|
}
|
2024-11-05 16:25:36 +08:00
|
|
|
|
else if (tag.Taged == (int)TagState.Ok)
|
2024-03-06 21:55:21 +08:00
|
|
|
|
{
|
2024-11-05 16:25:36 +08:00
|
|
|
|
if (nextNode.type == FlowNode.JOIN) //这种模式下只有坚持到【会签结束】节点之前才有意义,是否需要判定这条线所有的节点都通过,不然直接执行这个节点??
|
2024-03-06 21:55:21 +08:00
|
|
|
|
{
|
|
|
|
|
if (forkNode.setInfo.ConfluenceOk == null)
|
|
|
|
|
{
|
|
|
|
|
forkNode.setInfo.ConfluenceOk = 1;
|
|
|
|
|
}
|
2024-11-05 16:25:36 +08:00
|
|
|
|
else if (forkNode.setInfo.ConfluenceOk == (forkNumber - 1)) //会签成功
|
2024-03-06 21:55:21 +08:00
|
|
|
|
{
|
|
|
|
|
res = GetNextNodeId(nextNode.id);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
forkNode.setInfo.ConfluenceOk++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (res == TagState.No.ToString("D"))
|
|
|
|
|
{
|
2024-11-05 16:25:36 +08:00
|
|
|
|
tag.Taged = (int)TagState.No;
|
2024-03-06 21:55:21 +08:00
|
|
|
|
MakeTagNode(nextNode.id, tag);
|
|
|
|
|
}
|
|
|
|
|
else if (!string.IsNullOrEmpty(res)) //会签结束,标记合流节点
|
|
|
|
|
{
|
2024-11-05 16:25:36 +08:00
|
|
|
|
tag.Taged = (int)TagState.Ok;
|
2024-03-06 21:55:21 +08:00
|
|
|
|
MakeTagNode(nextNode.id, tag);
|
|
|
|
|
nextNodeId = res;
|
|
|
|
|
nextNodeType = GetNodeType(res);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
nextNodeId = nextNode.id;
|
|
|
|
|
nextNodeType = GetNodeType(nextNode.id);
|
|
|
|
|
}
|
2024-11-05 16:25:36 +08:00
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(res)) //会签结束节点配置了回调,则发起通知
|
|
|
|
|
{
|
|
|
|
|
NotifyThirdParty(httpClient, nextNode, tag);
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-06 21:55:21 +08:00
|
|
|
|
return res;
|
|
|
|
|
}
|
2024-11-05 16:25:36 +08:00
|
|
|
|
|
2024-03-06 21:55:21 +08:00
|
|
|
|
//获取上一个节点
|
|
|
|
|
private FlowNode GetPreNode(string nodeId = null)
|
|
|
|
|
{
|
|
|
|
|
var lines = nodeId == null ? ToNodeLines[currentNodeId] : ToNodeLines[nodeId];
|
|
|
|
|
if (lines.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("无法找到上一个点");
|
|
|
|
|
}
|
2024-11-05 16:25:36 +08:00
|
|
|
|
|
2024-03-06 21:55:21 +08:00
|
|
|
|
return Nodes[lines[0].from];
|
|
|
|
|
}
|
2025-01-09 17:11:11 +08:00
|
|
|
|
|
2024-03-06 21:55:21 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 驳回
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
2025-01-15 10:46:50 +08:00
|
|
|
|
public void RejectNode(HttpClient client, VerificationReq reqest)
|
2024-03-06 21:55:21 +08:00
|
|
|
|
{
|
2025-01-15 10:46:50 +08:00
|
|
|
|
//默认驳回到指定节点
|
|
|
|
|
string rejectNode = reqest.NodeRejectStep;
|
|
|
|
|
|
|
|
|
|
//如果不是指定到节点
|
|
|
|
|
if (string.IsNullOrEmpty(rejectNode))
|
2024-03-06 21:55:21 +08:00
|
|
|
|
{
|
2025-01-15 10:46:50 +08:00
|
|
|
|
string rejectType = reqest.NodeRejectType;
|
|
|
|
|
dynamic node = Nodes[currentNodeId];
|
|
|
|
|
if (node.setInfo != null && string.IsNullOrEmpty(reqest.NodeRejectType))
|
|
|
|
|
{
|
|
|
|
|
rejectType = node.setInfo.NodeRejectType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rejectType == "0") //前一步
|
|
|
|
|
{
|
|
|
|
|
rejectNode = previousId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rejectType == "1") //第一步
|
|
|
|
|
{
|
|
|
|
|
rejectNode = GetNextNodeId(startNodeId);
|
|
|
|
|
}
|
2024-03-06 21:55:21 +08:00
|
|
|
|
}
|
2024-11-05 16:25:36 +08:00
|
|
|
|
|
2025-01-15 10:46:50 +08:00
|
|
|
|
var user = AutofacContainerModule.GetService<IAuth>().GetCurrentUser().User;
|
|
|
|
|
var tag = new Tag
|
2024-03-06 21:55:21 +08:00
|
|
|
|
{
|
2025-01-15 10:46:50 +08:00
|
|
|
|
Description = reqest.VerificationOpinion,
|
|
|
|
|
Taged = (int)TagState.Reject,
|
|
|
|
|
UserId = user.Id,
|
|
|
|
|
UserName = user.Name
|
|
|
|
|
};
|
2024-11-05 16:25:36 +08:00
|
|
|
|
|
2025-01-15 10:46:50 +08:00
|
|
|
|
MakeTagNode(currentNodeId, tag);
|
|
|
|
|
flowInstance.IsFinish = FlowInstanceStatus.Rejected; //4表示驳回(需要申请者重新提交表单)
|
|
|
|
|
if (rejectNode != "")
|
2024-03-06 21:55:21 +08:00
|
|
|
|
{
|
2025-01-15 10:46:50 +08:00
|
|
|
|
flowInstance.PreviousId = flowInstance.ActivityId;
|
|
|
|
|
flowInstance.ActivityId = rejectNode;
|
|
|
|
|
flowInstance.ActivityType = GetNodeType(rejectNode);
|
|
|
|
|
flowInstance.ActivityName = Nodes[rejectNode].name;
|
|
|
|
|
flowInstance.MakerList =
|
|
|
|
|
GetNodeMarkers(Nodes[rejectNode], flowInstance.CreateUserId);
|
|
|
|
|
SaveTransitionHis();
|
2024-03-06 21:55:21 +08:00
|
|
|
|
}
|
2024-11-05 16:25:36 +08:00
|
|
|
|
|
2025-01-15 10:46:50 +08:00
|
|
|
|
flowInstance.SchemeContent = JsonHelper.Instance.Serialize(ToSchemeObj());
|
|
|
|
|
|
|
|
|
|
var sugarClient = AutofacContainerModule.GetService<ISqlSugarClient>();
|
|
|
|
|
sugarClient.Updateable(flowInstance).ExecuteCommand();
|
|
|
|
|
|
|
|
|
|
SaveOperationHis(
|
|
|
|
|
$"{user.Account}-{DateTime.Now.ToString("yyyy-MM-dd HH:mm")}驳回了【{currentNode.name}】");
|
|
|
|
|
|
|
|
|
|
NotifyThirdParty(client, currentNode, tag);
|
2024-03-06 21:55:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 撤销流程,清空所有节点
|
|
|
|
|
/// </summary>
|
2025-01-15 10:46:50 +08:00
|
|
|
|
public void ReCall(RecallFlowInstanceReq request)
|
2024-03-06 21:55:21 +08:00
|
|
|
|
{
|
|
|
|
|
foreach (var item in Nodes)
|
|
|
|
|
{
|
|
|
|
|
item.Value.setInfo = null;
|
|
|
|
|
}
|
2025-01-15 10:46:50 +08:00
|
|
|
|
|
|
|
|
|
flowInstance.IsFinish = FlowInstanceStatus.Draft;
|
|
|
|
|
flowInstance.PreviousId = flowInstance.ActivityId;
|
|
|
|
|
flowInstance.ActivityId = startNodeId;
|
|
|
|
|
flowInstance.ActivityType = GetNodeType(startNodeId);
|
|
|
|
|
flowInstance.ActivityName = Nodes[startNodeId].name;
|
|
|
|
|
flowInstance.MakerList = GetNodeMarkers(Nodes[startNodeId], flowInstance.CreateUserId);
|
|
|
|
|
|
|
|
|
|
SaveTransitionHis();
|
|
|
|
|
|
|
|
|
|
var sugarClient = AutofacContainerModule.GetService<ISqlSugarClient>();
|
|
|
|
|
sugarClient.Updateable(flowInstance).ExecuteCommand();
|
|
|
|
|
|
|
|
|
|
SaveOperationHis($"【撤回】备注:{request.Description}");
|
|
|
|
|
|
|
|
|
|
sugarClient.Ado.CommitTran();
|
2024-03-06 21:55:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///<summary>
|
|
|
|
|
/// 标记节点1通过,-1不通过,0驳回
|
|
|
|
|
/// </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)
|
|
|
|
|
{
|
2024-11-05 16:25:36 +08:00
|
|
|
|
item.Value.setInfo = new Setinfo();
|
2024-03-06 21:55:21 +08:00
|
|
|
|
}
|
2024-11-05 16:25:36 +08:00
|
|
|
|
|
2024-03-06 21:55:21 +08:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public object ToSchemeObj()
|
|
|
|
|
{
|
|
|
|
|
return new
|
|
|
|
|
{
|
|
|
|
|
title = this.title,
|
|
|
|
|
initNum = this.initNum,
|
|
|
|
|
lines = Lines,
|
|
|
|
|
nodes = Nodes.Select(u => u.Value),
|
|
|
|
|
areas = new string[0]
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-13 14:56:47 +08:00
|
|
|
|
public void SaveOperationHis(string userId, string userName, string opHis)
|
2025-01-09 17:11:11 +08:00
|
|
|
|
{
|
|
|
|
|
FlowInstanceOperationHistory flowInstanceOperationHistory = new FlowInstanceOperationHistory
|
|
|
|
|
{
|
|
|
|
|
InstanceId = flowInstanceId,
|
2025-01-13 14:56:47 +08:00
|
|
|
|
CreateUserId = userId,
|
|
|
|
|
CreateUserName = userName,
|
2025-01-09 17:11:11 +08:00
|
|
|
|
CreateDate = DateTime.Now,
|
2025-01-13 14:56:47 +08:00
|
|
|
|
Content = opHis
|
2025-01-09 17:11:11 +08:00
|
|
|
|
}; //操作记录
|
|
|
|
|
|
|
|
|
|
var SugarClient = AutofacContainerModule.GetService<ISqlSugarClient>();
|
|
|
|
|
SugarClient.Insertable(flowInstanceOperationHistory).ExecuteCommand();
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-13 14:56:47 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 添加工作流实例操作记录
|
|
|
|
|
/// <para>操作人为当前的登录用户</para>
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="opHis"></param>
|
|
|
|
|
public void SaveOperationHis(string opHis)
|
|
|
|
|
{
|
|
|
|
|
var user = AutofacContainerModule.GetService<IAuth>().GetCurrentUser().User;
|
|
|
|
|
SaveOperationHis(user.Id, user.Name, opHis);
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-24 11:01:45 +08:00
|
|
|
|
/// <summary>
|
2024-12-24 17:39:06 +08:00
|
|
|
|
/// 保存本次扭转记录
|
2024-12-24 11:01:45 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
2024-12-24 17:39:06 +08:00
|
|
|
|
public void SaveTransitionHis()
|
2024-12-24 11:01:45 +08:00
|
|
|
|
{
|
2024-12-24 17:39:06 +08:00
|
|
|
|
var user = AutofacContainerModule.GetService<IAuth>().GetCurrentUser().User;
|
|
|
|
|
var SugarClient = AutofacContainerModule.GetService<ISqlSugarClient>();
|
|
|
|
|
var transitionHistory = new FlowInstanceTransitionHistory
|
2024-12-24 11:01:45 +08:00
|
|
|
|
{
|
|
|
|
|
InstanceId = flowInstanceId,
|
|
|
|
|
CreateUserId = user.Id,
|
|
|
|
|
CreateUserName = user.Name,
|
|
|
|
|
FromNodeId = currentNodeId,
|
|
|
|
|
FromNodeName = currentNode.name,
|
|
|
|
|
FromNodeType = currentNodeType,
|
|
|
|
|
ToNodeId = nextNodeId,
|
|
|
|
|
ToNodeName = nextNode?.name,
|
|
|
|
|
ToNodeType = nextNodeType,
|
|
|
|
|
IsFinish = nextNodeType == 4 ? FlowInstanceStatus.Finished : FlowInstanceStatus.Running,
|
|
|
|
|
TransitionSate = 0
|
2025-01-09 17:11:11 +08:00
|
|
|
|
};
|
|
|
|
|
|
2024-12-24 17:39:06 +08:00
|
|
|
|
SugarClient.Insertable(transitionHistory).ExecuteCommand();
|
2024-12-24 11:01:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-06 21:55:21 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 通知三方系统,节点执行情况
|
|
|
|
|
/// </summary>
|
2024-11-05 16:25:36 +08:00
|
|
|
|
public void NotifyThirdParty(HttpClient client, FlowNode node, Tag tag)
|
2024-03-06 21:55:21 +08:00
|
|
|
|
{
|
2024-11-05 16:25:36 +08:00
|
|
|
|
if (node.setInfo == null || string.IsNullOrEmpty(node.setInfo.ThirdPartyUrl))
|
2024-03-06 21:55:21 +08:00
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var postData = new
|
|
|
|
|
{
|
|
|
|
|
flowInstanceId,
|
2024-11-05 16:25:36 +08:00
|
|
|
|
nodeName = node.name,
|
|
|
|
|
nodeId = node.id,
|
2024-03-06 21:55:21 +08:00
|
|
|
|
userId = tag.UserId,
|
|
|
|
|
userName = tag.UserName,
|
2024-11-05 16:25:36 +08:00
|
|
|
|
result = tag.Taged, //1:通过;2:不通过;3驳回
|
2024-03-06 21:55:21 +08:00
|
|
|
|
description = tag.Description,
|
|
|
|
|
execTime = tag.TagedTime,
|
2024-11-05 16:25:36 +08:00
|
|
|
|
isFinish = node.type == FlowNode.END
|
2024-03-06 21:55:21 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using (HttpContent httpContent = new StringContent(JsonHelper.Instance.Serialize(postData), Encoding.UTF8))
|
|
|
|
|
{
|
2024-11-05 16:25:36 +08:00
|
|
|
|
httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
|
|
|
|
|
client.PostAsync(node.setInfo.ThirdPartyUrl, httpContent);
|
2024-03-06 21:55:21 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-08 15:01:17 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 撤销当前节点的审批
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void UndoVerification()
|
|
|
|
|
{
|
|
|
|
|
// 已结束的流程不能撤销
|
|
|
|
|
if (flowInstance.IsFinish == FlowInstanceStatus.Finished
|
|
|
|
|
|| flowInstance.IsFinish == FlowInstanceStatus.Rejected)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("流程已结束,不能撤销");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(Nodes[previousId].type == FlowNode.START)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("没有任何审批,不能撤销!你可以删除或召回这个流程");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 恢复到上一个节点
|
|
|
|
|
currentNodeId = flowInstance.PreviousId;
|
|
|
|
|
flowInstance.ActivityId = currentNodeId;
|
|
|
|
|
flowInstance.ActivityType = GetNodeType(currentNodeId);
|
|
|
|
|
flowInstance.ActivityName = Nodes[currentNodeId].name;
|
|
|
|
|
//向前查找ActivityId的前一个结点,即连线指向ActivityId的节点
|
|
|
|
|
flowInstance.PreviousId = GetPreNode().id;
|
|
|
|
|
flowInstance.MakerList = GetNodeMarkers(Nodes[currentNodeId]);
|
|
|
|
|
|
|
|
|
|
// 清除当前节点的审批状态
|
|
|
|
|
currentNode.setInfo.Taged = null;
|
|
|
|
|
currentNode.setInfo.UserId = "";
|
|
|
|
|
currentNode.setInfo.UserName = "";
|
|
|
|
|
currentNode.setInfo.Description = "";
|
|
|
|
|
currentNode.setInfo.TagedTime = "";
|
|
|
|
|
|
|
|
|
|
//删除当前节点的扭转记录
|
|
|
|
|
var user = AutofacContainerModule.GetService<IAuth>().GetCurrentUser().User;
|
|
|
|
|
var SugarClient = AutofacContainerModule.GetService<ISqlSugarClient>();
|
|
|
|
|
SugarClient.Deleteable<FlowInstanceTransitionHistory>().Where(u => u.InstanceId == flowInstanceId && u.CreateUserId == user.Id && u.FromNodeId == currentNodeId).ExecuteCommand();
|
|
|
|
|
|
|
|
|
|
//删除当前节点的审批记录(只删除最新的一条)
|
|
|
|
|
var latestRecord = SugarClient.Queryable<FlowInstanceOperationHistory>()
|
|
|
|
|
.Where(u => u.InstanceId == flowInstanceId && u.CreateUserId == user.Id)
|
|
|
|
|
.OrderByDescending(u => u.CreateDate)
|
|
|
|
|
.First();
|
|
|
|
|
if (latestRecord != null)
|
|
|
|
|
{
|
|
|
|
|
SugarClient.Deleteable<FlowInstanceOperationHistory>()
|
|
|
|
|
.Where(u => u.Id == latestRecord.Id)
|
|
|
|
|
.ExecuteCommand();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-06 21:55:21 +08:00
|
|
|
|
#endregion 共有方法
|
|
|
|
|
|
2024-12-24 17:39:06 +08:00
|
|
|
|
#region 获取节点审批人
|
2025-01-09 17:11:11 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 寻找下一步的执行人
|
|
|
|
|
/// 一般用于本节点审核完成后,修改流程实例的当前执行人,可以做到通知等功能
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public string GetNextMakers(NodeDesignateReq request = null)
|
|
|
|
|
{
|
|
|
|
|
string makerList = "";
|
|
|
|
|
if (nextNodeId == "-1")
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("无法寻找到下一个节点");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nextNodeType == 0) //如果是会签节点
|
|
|
|
|
{
|
|
|
|
|
makerList = GetForkNodeMakers(nextNodeId);
|
|
|
|
|
}
|
|
|
|
|
else if (nextNode.setInfo.NodeDesignate == Setinfo.RUNTIME_SPECIAL_ROLE)
|
|
|
|
|
{
|
|
|
|
|
//如果是运行时指定角色
|
|
|
|
|
if (nextNode.setInfo.NodeDesignate != request.NodeDesignateType)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("前端提交的节点权限类型异常,请检查流程");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var revelanceApp = AutofacContainerModule.GetService<RevelanceManagerApp>();
|
|
|
|
|
var users = revelanceApp.Get(Define.USERROLE, false, request.NodeDesignates);
|
|
|
|
|
makerList = GenericHelpers.ArrayToString(users, makerList);
|
|
|
|
|
}
|
|
|
|
|
else if (nextNode.setInfo.NodeDesignate == Setinfo.RUNTIME_SPECIAL_USER)
|
|
|
|
|
{
|
|
|
|
|
//如果是运行时指定用户
|
|
|
|
|
if (nextNode.setInfo.NodeDesignate != request.NodeDesignateType)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("前端提交的节点权限类型异常,请检查流程");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
makerList = GenericHelpers.ArrayToString(request.NodeDesignates, makerList);
|
|
|
|
|
}
|
|
|
|
|
else if (nextNode.setInfo.NodeDesignate == Setinfo.RUNTIME_PARENT
|
|
|
|
|
|| nextNode.setInfo.NodeDesignate == Setinfo.RUNTIME_MANY_PARENTS)
|
|
|
|
|
{
|
|
|
|
|
//如果是上一节点执行人的直属上级或连续多级直属上级
|
|
|
|
|
if (nextNode.setInfo.NodeDesignate != request.NodeDesignateType)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("前端提交的节点权限类型异常,请检查流程");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//当创建流程时,肯定执行的开始节点,登录用户就是创建用户
|
|
|
|
|
//当审批流程时,能进到这里,表明当前登录用户已经有审批当前节点的权限,完全可以直接用登录用户的直接上级
|
|
|
|
|
var userManagerApp = AutofacContainerModule.GetService<UserManagerApp>();
|
|
|
|
|
var user = AutofacContainerModule.GetService<IAuth>().GetCurrentUser().User;
|
|
|
|
|
var parentId = userManagerApp.GetParent(user.Id);
|
|
|
|
|
if (StringExtension.IsNullOrEmpty(parentId))
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("无法找到当前用户的直属上级");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
makerList = GenericHelpers.ArrayToString(new[] { parentId }, makerList);
|
|
|
|
|
}
|
|
|
|
|
else if (nextNode.setInfo.NodeDesignate == Setinfo.RUNTIME_CHAIRMAN)
|
|
|
|
|
{
|
|
|
|
|
//如果是发起人的部门负责人
|
|
|
|
|
if (nextNode.setInfo.NodeDesignate != request.NodeDesignateType)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("前端提交的节点权限类型异常,请检查流程");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var orgManagerApp = AutofacContainerModule.GetService<OrgManagerApp>();
|
|
|
|
|
var chairmanIds = orgManagerApp.GetChairmanId(nextNode.setInfo.NodeDesignateData.orgs);
|
|
|
|
|
makerList = GenericHelpers.ArrayToString(chairmanIds, makerList);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
makerList = GetNodeMarkers(nextNode);
|
|
|
|
|
if (string.IsNullOrEmpty(makerList))
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("无法寻找到节点的审核者,请查看流程设计是否有问题!");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return makerList;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2024-12-24 17:39:06 +08:00
|
|
|
|
/// 计算节点执行人
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="node"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public string GetNodeMarkers(FlowNode node, string flowinstanceCreateUserId = "")
|
|
|
|
|
{
|
|
|
|
|
string makerList = "";
|
|
|
|
|
if (node.type == FlowNode.START && (!string.IsNullOrEmpty(flowinstanceCreateUserId))) //如果是开始节点,通常情况下是驳回到开始了
|
|
|
|
|
{
|
|
|
|
|
makerList = flowinstanceCreateUserId;
|
|
|
|
|
}
|
|
|
|
|
else if (node.setInfo != null)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrEmpty(node.setInfo.NodeDesignate) ||
|
|
|
|
|
node.setInfo.NodeDesignate == Setinfo.ALL_USER) //所有成员
|
|
|
|
|
{
|
|
|
|
|
makerList = "1";
|
|
|
|
|
}
|
|
|
|
|
else if (node.setInfo.NodeDesignate == Setinfo.SPECIAL_USER) //指定成员
|
|
|
|
|
{
|
|
|
|
|
makerList = GenericHelpers.ArrayToString(node.setInfo.NodeDesignateData.users, makerList);
|
|
|
|
|
}
|
|
|
|
|
else if (node.setInfo.NodeDesignate == Setinfo.SPECIAL_ROLE) //指定角色
|
|
|
|
|
{
|
|
|
|
|
var revelanceApp = AutofacContainerModule.GetService<RevelanceManagerApp>();
|
|
|
|
|
var users = revelanceApp.Get(Define.USERROLE, false, node.setInfo.NodeDesignateData.roles);
|
|
|
|
|
makerList = GenericHelpers.ArrayToString(users, makerList);
|
|
|
|
|
}
|
|
|
|
|
else if (node.setInfo.NodeDesignate == Setinfo.RUNTIME_SPECIAL_ROLE
|
|
|
|
|
|| node.setInfo.NodeDesignate == Setinfo.RUNTIME_SPECIAL_USER)
|
|
|
|
|
{
|
|
|
|
|
//如果是运行时选定的用户,则暂不处理。由上个节点审批时选定
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else //如果没有设置节点信息,默认所有人都可以审核
|
|
|
|
|
{
|
|
|
|
|
makerList = "1";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return makerList;
|
|
|
|
|
}
|
2025-01-09 17:11:11 +08:00
|
|
|
|
|
2024-12-24 17:39:06 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 会签时,获取一条会签分支上面是否有用户可审核的节点
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="fromForkStartNode"></param>
|
|
|
|
|
/// <param name="tag"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public string GetOneForkLineCanCheckNodeId(FlowNode fromForkStartNode, Tag tag)
|
|
|
|
|
{
|
|
|
|
|
string canCheckId = "";
|
|
|
|
|
var node = fromForkStartNode;
|
|
|
|
|
do //沿一条分支线路执行,直到遇到会签结束节点
|
|
|
|
|
{
|
|
|
|
|
var makerList = GetNodeMarkers(node);
|
|
|
|
|
|
|
|
|
|
if (node.setInfo.Taged == null && !string.IsNullOrEmpty(makerList) &&
|
|
|
|
|
makerList.Split(',').Any(one => tag.UserId == one))
|
|
|
|
|
{
|
|
|
|
|
canCheckId = node.id;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
node = GetNextNode(node.id);
|
|
|
|
|
} while (node.type != FlowNode.JOIN);
|
|
|
|
|
|
|
|
|
|
return canCheckId;
|
|
|
|
|
}
|
2025-01-09 17:11:11 +08:00
|
|
|
|
|
2024-12-24 17:39:06 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取会签开始节点的所有可执行者
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="forkNodeId">会签开始节点</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public string GetForkNodeMakers(string forkNodeId)
|
|
|
|
|
{
|
|
|
|
|
string makerList = "";
|
|
|
|
|
foreach (string fromForkStartNodeId in FromNodeLines[forkNodeId].Select(u => u.to))
|
|
|
|
|
{
|
|
|
|
|
var fromForkStartNode = Nodes[fromForkStartNodeId]; //与会签开始节点直接连接的节点
|
|
|
|
|
if (makerList != "")
|
|
|
|
|
{
|
|
|
|
|
makerList += ",";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
makerList += GetOneForkLineMakers(fromForkStartNode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return makerList;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取会签一条线上的审核者,该审核者应该是已审核过的节点的下一个人
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="fromForkStartNode">与会签开始节点直接连接的节点</param>
|
|
|
|
|
private string GetOneForkLineMakers(FlowNode fromForkStartNode)
|
|
|
|
|
{
|
|
|
|
|
string markers = "";
|
|
|
|
|
var node = fromForkStartNode;
|
|
|
|
|
do //沿一条分支线路执行,直到遇到第一个没有审核的节点
|
|
|
|
|
{
|
|
|
|
|
if (node.setInfo != null && node.setInfo.Taged != null)
|
|
|
|
|
{
|
|
|
|
|
if (node.type != FlowNode.FORK && node.setInfo.Taged != (int)TagState.Ok) //如果节点是不同意或驳回,则不用再找了
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
node = GetNextNode(node.id); //下一个节点
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var marker = GetNodeMarkers(node);
|
|
|
|
|
if (marker == "")
|
|
|
|
|
{
|
|
|
|
|
throw new Exception($"节点{node.name}没有审核者,请检查!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (marker == "1")
|
|
|
|
|
{
|
|
|
|
|
throw new Exception($"节点{node.name}是会签节点,不能用所有人,请检查!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (markers != "")
|
|
|
|
|
{
|
|
|
|
|
markers += ",";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
markers += marker;
|
|
|
|
|
break;
|
|
|
|
|
} while (node.type != FlowNode.JOIN);
|
|
|
|
|
|
|
|
|
|
return markers;
|
|
|
|
|
}
|
2025-01-09 17:11:11 +08:00
|
|
|
|
|
2024-12-24 17:39:06 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
2024-03-06 21:55:21 +08:00
|
|
|
|
#region 属性
|
|
|
|
|
|
2025-01-15 10:46:50 +08:00
|
|
|
|
private FlowInstance flowInstance { get; set; }
|
|
|
|
|
|
2024-12-24 11:01:45 +08:00
|
|
|
|
private string title { get; set; }
|
2024-03-06 21:55:21 +08:00
|
|
|
|
|
2024-12-24 11:01:45 +08:00
|
|
|
|
private int initNum { get; set; }
|
2024-03-06 21:55:21 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 运行实例的Id
|
|
|
|
|
/// </summary>
|
2024-12-24 11:01:45 +08:00
|
|
|
|
private string flowInstanceId { get; set; }
|
2025-01-13 14:56:47 +08:00
|
|
|
|
|
2025-01-09 17:11:11 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 上一个节点
|
|
|
|
|
/// </summary>
|
|
|
|
|
private string previousId { get; set; }
|
2025-01-15 10:46:50 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 实例节点集合
|
|
|
|
|
/// </summary>
|
|
|
|
|
private Dictionary<string, FlowNode> Nodes { get; set; }
|
2025-01-13 14:56:47 +08:00
|
|
|
|
|
2025-01-09 17:11:11 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 流程实例中所有的线段
|
|
|
|
|
/// </summary>
|
|
|
|
|
private List<FlowLine> Lines { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 从节点发出的线段集合
|
|
|
|
|
/// </summary>
|
|
|
|
|
private Dictionary<string, List<FlowLine>> FromNodeLines { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 到达节点的线段集合
|
|
|
|
|
/// </summary>
|
|
|
|
|
private Dictionary<string, List<FlowLine>> ToNodeLines { get; set; }
|
2025-01-13 14:56:47 +08:00
|
|
|
|
|
2025-01-09 17:11:11 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当前节点类型 0会签开始,1会签结束,2一般节点,开始节点,4流程运行结束
|
|
|
|
|
/// </summary>
|
|
|
|
|
private int currentNodeType { get; set; }
|
2025-01-13 14:56:47 +08:00
|
|
|
|
|
2025-01-09 17:11:11 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 表单数据
|
|
|
|
|
/// </summary>
|
|
|
|
|
private string FrmData { get; set; }
|
2024-03-06 21:55:21 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 开始节点的ID
|
|
|
|
|
/// </summary>
|
2025-01-15 10:46:50 +08:00
|
|
|
|
private string startNodeId { get; set; }
|
2024-03-06 21:55:21 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当前节点的ID
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string currentNodeId { 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>
|
2024-11-05 16:25:36 +08:00
|
|
|
|
public FlowNode nextNode => nextNodeId != "-1" ? Nodes[nextNodeId] : null;
|
2024-03-06 21:55:21 +08:00
|
|
|
|
|
|
|
|
|
#endregion 属性
|
|
|
|
|
}
|
2020-10-22 14:59:36 +08:00
|
|
|
|
}
|