534 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			534 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						||
using System.Collections.Generic;
 | 
						||
using System.Data;
 | 
						||
using System.Linq;
 | 
						||
using APT.BaseData.Domain.Entities;
 | 
						||
using APT.Infrastructure.Core;
 | 
						||
using Newtonsoft.Json;
 | 
						||
using Newtonsoft.Json.Linq;
 | 
						||
 | 
						||
namespace APT.BaseData.Domain.ApiModel
 | 
						||
{
 | 
						||
    public class FlowRuntime
 | 
						||
    {
 | 
						||
        private FlowRuntimeModel _runtimeModel = null;
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 构造函数
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="currentNodeId">当前节点</param>
 | 
						||
        /// <param name="frmData">表单数据</param>
 | 
						||
        /// <param name="instance"></param>
 | 
						||
        public FlowRuntime(T_PF_FLOW_INSTANCE instance, object entity)
 | 
						||
        {
 | 
						||
            _runtimeModel = new FlowRuntimeModel();
 | 
						||
            dynamic schemeContentJson = JsonConvert.DeserializeObject(instance.SchemeContent);//获取工作流模板内容的json对象;
 | 
						||
            _runtimeModel.frmData = string.Empty;
 | 
						||
            _runtimeModel.schemeContentJson = schemeContentJson;//模板流程json对象
 | 
						||
            _runtimeModel.nodes = GetNodes(schemeContentJson);//节点集合
 | 
						||
            _runtimeModel.lines = GetFromLines(schemeContentJson);//线条集合
 | 
						||
            _runtimeModel.currentNodeId = (instance.ActivityId == "" ? _runtimeModel.startNodeId : instance.ActivityId);
 | 
						||
            _runtimeModel.currentNodeType = GetNodeType(_runtimeModel.currentNodeId);
 | 
						||
 | 
						||
            //会签开始节点和流程结束节点没有下一步
 | 
						||
            if (_runtimeModel.currentNodeType == 0 || _runtimeModel.currentNodeType == 4)
 | 
						||
            {
 | 
						||
                _runtimeModel.nextNodeId = "-1";
 | 
						||
                _runtimeModel.nextNodeType = -1;
 | 
						||
            }
 | 
						||
            else
 | 
						||
            {
 | 
						||
                _runtimeModel.nextNodeId = GetNextNodeId(_runtimeModel.frmData, entity);//下一个节点
 | 
						||
                _runtimeModel.nextNodeType = GetNodeType(_runtimeModel.nextNodeId);
 | 
						||
            }
 | 
						||
 | 
						||
            _runtimeModel.previousId = instance.PreviousId;
 | 
						||
            _runtimeModel.flowInstanceId = instance.ID.ToString();
 | 
						||
 | 
						||
        }
 | 
						||
 | 
						||
        #region 私有方法
 | 
						||
        /// <summary>
 | 
						||
        /// 获取工作流节点的字典列表:key节点id
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="schemeContentJson"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        private Dictionary<string, FlowNode> GetNodes(dynamic schemeContentJson)
 | 
						||
        {
 | 
						||
            Dictionary<string, FlowNode> 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);
 | 
						||
                }
 | 
						||
                if (node.type == FlowNode.START)
 | 
						||
                {
 | 
						||
                    this._runtimeModel.startNodeId = node.id;
 | 
						||
                }
 | 
						||
            }
 | 
						||
            return nodes;
 | 
						||
        }
 | 
						||
        /// <summary>
 | 
						||
        /// 获取工作流节点及以节点为出发点的流程
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="schemeContentJson"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        private Dictionary<string, List<FlowLine>> GetFromLines(dynamic schemeContentJson)
 | 
						||
        {
 | 
						||
            Dictionary<string, List<FlowLine>> lines = new Dictionary<string, List<FlowLine>>();
 | 
						||
            foreach (JObject item in schemeContentJson.lines)
 | 
						||
            {
 | 
						||
                var line = JsonConvert.DeserializeObject<FlowLine>(item.ToString());
 | 
						||
                if (!lines.ContainsKey(line.from))
 | 
						||
                {
 | 
						||
                    List<FlowLine> d = new List<FlowLine> { line };
 | 
						||
                    lines.Add(line.from, d);
 | 
						||
                }
 | 
						||
                else
 | 
						||
                {
 | 
						||
                    lines[line.from].Add(line);
 | 
						||
                }
 | 
						||
            }
 | 
						||
            return lines;
 | 
						||
        }
 | 
						||
        /// <summary>
 | 
						||
        /// 获取工作流节点的入口流程列表
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="schemeContentJson"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        private Dictionary<string, List<FlowLine>> GetToLines(dynamic schemeContentJson)
 | 
						||
        {
 | 
						||
            Dictionary<string, List<FlowLine>> lines = new Dictionary<string, List<FlowLine>>();
 | 
						||
            foreach (JObject item in schemeContentJson.lines)
 | 
						||
            {
 | 
						||
                var line = item.ToObject<FlowLine>();
 | 
						||
                if (!lines.ContainsKey(line.to))
 | 
						||
                {
 | 
						||
                    List<FlowLine> d = new List<FlowLine> { line };
 | 
						||
                    lines.Add(line.to, d);
 | 
						||
                }
 | 
						||
                else
 | 
						||
                {
 | 
						||
                    lines[line.to].Add(line);
 | 
						||
                }
 | 
						||
            }
 | 
						||
            return lines;
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 获取下一个节点
 | 
						||
        /// </summary>
 | 
						||
        private string GetNextNodeId(string frmData, object entity, string nodeId = null)
 | 
						||
        {
 | 
						||
            List<FlowLine> LineList = null;
 | 
						||
            if (nodeId == null)
 | 
						||
            {
 | 
						||
                LineList = runtimeModel.lines[runtimeModel.currentNodeId];
 | 
						||
            }
 | 
						||
            else
 | 
						||
            {
 | 
						||
                LineList = runtimeModel.lines[nodeId];
 | 
						||
            }
 | 
						||
            if (LineList.Count == 1)  //只有一条流程
 | 
						||
            {
 | 
						||
                return LineList[0].to;
 | 
						||
            }
 | 
						||
            else if (LineList.Count > 1)
 | 
						||
            {
 | 
						||
                foreach (var line in LineList)
 | 
						||
                {
 | 
						||
                    bool isMarch = true;
 | 
						||
                    if (line.setInfo == null || line.setInfo.Rules == null)
 | 
						||
                        return line.to;
 | 
						||
                    foreach (var rule in line.setInfo.Rules)
 | 
						||
                    {
 | 
						||
                        var type = entity.GetType();
 | 
						||
                        var field = type.GetProperty(rule.Field);
 | 
						||
                        var value = field.GetValue(entity).ToString();
 | 
						||
                        if (rule.Operate == FilterOperate.Equal)
 | 
						||
                        {
 | 
						||
                            if (value != rule.Value.ToString())
 | 
						||
                            {
 | 
						||
                                isMarch = false;
 | 
						||
                                break;
 | 
						||
                            }
 | 
						||
                        }
 | 
						||
                        else if (rule.Operate == FilterOperate.NotEqual)
 | 
						||
                        {
 | 
						||
                            if (value == rule.Value.ToString())
 | 
						||
                            {
 | 
						||
                                isMarch = false;
 | 
						||
                                break;
 | 
						||
                            }
 | 
						||
                        }
 | 
						||
                        else if (rule.Operate == FilterOperate.GreaterThan)
 | 
						||
                        {
 | 
						||
                            var dVal = double.Parse(value);
 | 
						||
                            var rVal = double.Parse(rule.Value.ToString());
 | 
						||
                            if (dVal <= rVal)
 | 
						||
                            {
 | 
						||
                                isMarch = false;
 | 
						||
                                break;
 | 
						||
                            }
 | 
						||
                        }
 | 
						||
                        else if (rule.Operate == FilterOperate.GreaterThanOrEqual)
 | 
						||
                        {
 | 
						||
                            var dVal = double.Parse(value);
 | 
						||
                            var rVal = double.Parse(rule.Value.ToString());
 | 
						||
                            if (dVal < rVal)
 | 
						||
                            {
 | 
						||
                                isMarch = false;
 | 
						||
                                break;
 | 
						||
                            }
 | 
						||
                        }
 | 
						||
                        else if (rule.Operate == FilterOperate.LessThan)
 | 
						||
                        {
 | 
						||
                            var dVal = double.Parse(value);
 | 
						||
                            var rVal = double.Parse(rule.Value.ToString());
 | 
						||
                            if (dVal >= rVal)
 | 
						||
                            {
 | 
						||
                                isMarch = false;
 | 
						||
                                break;
 | 
						||
                            }
 | 
						||
                        }
 | 
						||
                        else if (rule.Operate == FilterOperate.LessThanOrEqual)
 | 
						||
                        {
 | 
						||
                            var dVal = double.Parse(value);
 | 
						||
                            var rVal = double.Parse(rule.Value.ToString());
 | 
						||
                            if (dVal > rVal)
 | 
						||
                            {
 | 
						||
                                isMarch = false;
 | 
						||
                                break;
 | 
						||
                            }
 | 
						||
                        }
 | 
						||
                        else if (rule.Operate == FilterOperate.StartsWith)
 | 
						||
                        {
 | 
						||
 | 
						||
                            if (!value.StartsWith(rule.Value.ToString()))
 | 
						||
                            {
 | 
						||
                                isMarch = false;
 | 
						||
                                break;
 | 
						||
                            }
 | 
						||
                        }
 | 
						||
                        else if (rule.Operate == FilterOperate.EndsWith)
 | 
						||
                        {
 | 
						||
                            if (!value.EndsWith(rule.Value.ToString()))
 | 
						||
                            {
 | 
						||
                                isMarch = false;
 | 
						||
                                break;
 | 
						||
                            }
 | 
						||
                        }
 | 
						||
                        else if (rule.Operate == FilterOperate.Contains)
 | 
						||
                        {
 | 
						||
                            if (!value.Contains(rule.Value.ToString()))
 | 
						||
                            {
 | 
						||
                                isMarch = false;
 | 
						||
                                break;
 | 
						||
                            }
 | 
						||
                        }
 | 
						||
                    }
 | 
						||
                    if (isMarch)
 | 
						||
                    {
 | 
						||
                        return line.to;
 | 
						||
                    }
 | 
						||
                }
 | 
						||
            }
 | 
						||
 | 
						||
            if (frmData != "")  //有分支的情况
 | 
						||
            {
 | 
						||
                frmData = frmData.ToLower();//统一转小写
 | 
						||
                foreach (var item in LineList)//轮训该节点所有连接的线路
 | 
						||
                {
 | 
						||
                    return item.to;
 | 
						||
                }
 | 
						||
            }
 | 
						||
            return "-1";//表示寻找不到节点
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 通过节点Id获取下一个节点Id
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="nodeId"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        public string GetNextNode(string nodeId)
 | 
						||
        {
 | 
						||
            string frmData = "";
 | 
						||
 | 
						||
            //     frmData = GetNodeFrmData(_getFrmData, nodeId);
 | 
						||
 | 
						||
            return GetNextNodeId(frmData,null, nodeId);
 | 
						||
        }
 | 
						||
        #endregion
 | 
						||
 | 
						||
        #region 工作流实例流转API
 | 
						||
        /// <summary>
 | 
						||
        /// 工作流实例运行信息
 | 
						||
        /// </summary>
 | 
						||
        /// <returns></returns>
 | 
						||
        public FlowRuntimeModel runtimeModel
 | 
						||
        {
 | 
						||
            get { return _runtimeModel; }
 | 
						||
        }
 | 
						||
        /// <summary>
 | 
						||
        /// 获取实例接下来运行的状态
 | 
						||
        /// </summary>
 | 
						||
        /// <returns>-1无法运行,0会签开始,1会签结束,2一般节点,4流程运行结束</returns>
 | 
						||
        public int GetNextNodeType()
 | 
						||
        {
 | 
						||
            if (_runtimeModel.nextNodeId != "-1")
 | 
						||
            {
 | 
						||
                return GetNodeType(_runtimeModel.nextNodeId);
 | 
						||
 | 
						||
            }
 | 
						||
            return -1;
 | 
						||
        }
 | 
						||
        /// <summary>
 | 
						||
        /// 获取节点类型 0会签开始,1会签结束,2一般节点,开始节点,4流程运行结束
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="nodeId"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        public int GetNodeType(string nodeId)
 | 
						||
        {
 | 
						||
            if (_runtimeModel.nodes[nodeId].type == FlowNode.FORK)//会签开始节点
 | 
						||
            {
 | 
						||
                return 0;
 | 
						||
            }
 | 
						||
            else if (_runtimeModel.nodes[nodeId].type == FlowNode.JOIN)//会签结束节点
 | 
						||
            {
 | 
						||
                return 1;
 | 
						||
            }
 | 
						||
            else if (_runtimeModel.nodes[nodeId].type == FlowNode.END)//结束节点
 | 
						||
            {
 | 
						||
                return 4;
 | 
						||
            }
 | 
						||
            else if (_runtimeModel.nodes[nodeId].type == FlowNode.START)//开始节点
 | 
						||
            {
 | 
						||
                return 3;
 | 
						||
            }
 | 
						||
            else
 | 
						||
            {
 | 
						||
                return 2;
 | 
						||
            }
 | 
						||
        }
 | 
						||
        /// <summary>
 | 
						||
        /// 获取会签下面需要审核的ID列表
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="forknodeId">会签开始节点</param>
 | 
						||
        /// <returns></returns>
 | 
						||
        public List<string> GetCountersigningNodeIdList(string forknodeId)
 | 
						||
        {
 | 
						||
            return _runtimeModel.lines[forknodeId].Select(item => item.to).ToList();
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 节点会签审核 
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="nodeId"></param>
 | 
						||
        /// <param name="tag"></param>
 | 
						||
        /// <returns>-1不通过,1等待,其它通过</returns>
 | 
						||
        public string NodeConfluence(string nodeId, Tag tag)
 | 
						||
        {
 | 
						||
            string res = "-1";
 | 
						||
            string joinNodeId = GetNextNode(nodeId); //获取回签的合流节点
 | 
						||
 | 
						||
            if (joinNodeId == "-1")
 | 
						||
            {
 | 
						||
                throw (new Exception("寻找不到会签下合流节点"));
 | 
						||
            }
 | 
						||
 | 
						||
            Dictionary<string, List<FlowLine>> toLines = GetToLines(_runtimeModel.schemeContentJson);
 | 
						||
            int allnum = toLines[joinNodeId].Count;   //总会签数量
 | 
						||
 | 
						||
            int i = 0;
 | 
						||
            foreach (var item in _runtimeModel.schemeContentJson.nodes)
 | 
						||
            {
 | 
						||
                if (item.id != joinNodeId)
 | 
						||
                {
 | 
						||
                    i++;
 | 
						||
                    continue;
 | 
						||
                }
 | 
						||
 | 
						||
                if (string.IsNullOrEmpty(item.setInfo.NodeConfluenceType)) //默认所有步骤通过  
 | 
						||
                {
 | 
						||
                    if (tag.Taged == 1)
 | 
						||
                    {
 | 
						||
                        if (item.setInfo.ConfluenceOk == null)
 | 
						||
                        {
 | 
						||
                            _runtimeModel.schemeContentJson.nodes[i].setInfo.ConfluenceOk = 1;
 | 
						||
                            res = "1";
 | 
						||
                        }
 | 
						||
                        else if (item.setInfo.ConfluenceOk == (allnum - 1))  //会签成功
 | 
						||
                        {
 | 
						||
                            res = GetNextNode(joinNodeId);
 | 
						||
                            if (res == "-1")
 | 
						||
                            {
 | 
						||
                                throw (new Exception("会签成功寻找不到下一个节点"));
 | 
						||
                            }
 | 
						||
                        }
 | 
						||
                        else
 | 
						||
                        {
 | 
						||
                            _runtimeModel.schemeContentJson.nodes[i].setInfo.ConfluenceOk = int.Parse(_runtimeModel.schemeContentJson.nodes[i].setInfo.ConfluenceOk) + 1;
 | 
						||
                            res = "1";
 | 
						||
                        }
 | 
						||
                    }
 | 
						||
                }
 | 
						||
                //else if (item.setInfo.NodeConfluenceType == "1") //1一个步骤通过即可
 | 
						||
                //{
 | 
						||
                //    if (tag.Taged == 1)
 | 
						||
                //    {
 | 
						||
                //        res = GetNextNodeId(nextNodeId);
 | 
						||
                //        if (res == "-1")
 | 
						||
                //        {
 | 
						||
                //            throw (new Exception("会签成功寻找不到下一个节点"));
 | 
						||
                //        }
 | 
						||
                //    }
 | 
						||
                //    else
 | 
						||
                //    {
 | 
						||
                //        if (item.setInfo.ConfluenceNo == null)
 | 
						||
                //        {
 | 
						||
                //            _runtimeModel.schemeContentJson.nodes[i].setInfo.ConfluenceNo = 1;
 | 
						||
                //            res = "1";
 | 
						||
                //        }
 | 
						||
                //        else if (item.setInfo.ConfluenceNo == (allnum - 1))
 | 
						||
                //        {
 | 
						||
                //            res = "-1";
 | 
						||
                //        }
 | 
						||
                //        else
 | 
						||
                //        {
 | 
						||
                //            _runtimeModel.schemeContentJson.nodes[i].setInfo.ConfluenceNo++;
 | 
						||
                //            res = "1";
 | 
						||
                //        }
 | 
						||
                //    }
 | 
						||
                //}
 | 
						||
            }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
            if (res == "-1")
 | 
						||
            {
 | 
						||
                tag.Taged = -1;
 | 
						||
                MakeTagNode(joinNodeId, tag);
 | 
						||
            }
 | 
						||
            else if (res != "1") //这时res是会签结束节点后面的一个节点
 | 
						||
            {
 | 
						||
                tag.Taged = 1;
 | 
						||
                MakeTagNode(joinNodeId, tag);
 | 
						||
                _runtimeModel.nextNodeId = res;
 | 
						||
                _runtimeModel.nextNodeType = GetNodeType(res);
 | 
						||
            }
 | 
						||
            else
 | 
						||
            {
 | 
						||
                _runtimeModel.nextNodeId = joinNodeId;
 | 
						||
                _runtimeModel.nextNodeType = GetNodeType(joinNodeId);
 | 
						||
            }
 | 
						||
            return res;
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 驳回节点0"前一步"1"第一步"2"某一步" 3"不处理"
 | 
						||
        /// </summary>
 | 
						||
        /// <returns></returns>
 | 
						||
        public string RejectNode()
 | 
						||
        {
 | 
						||
            return RejectNode(_runtimeModel.currentNodeId);
 | 
						||
        }
 | 
						||
 | 
						||
        public string RejectNode(string nodeId)
 | 
						||
        {
 | 
						||
            dynamic node = _runtimeModel.nodes[nodeId];
 | 
						||
            if (node.setInfo != null)
 | 
						||
            {
 | 
						||
                if (node.setInfo.NodeRejectType == "0")
 | 
						||
                {
 | 
						||
                    return _runtimeModel.previousId;
 | 
						||
                }
 | 
						||
                if (node.setInfo.NodeRejectType == "1")
 | 
						||
                {
 | 
						||
                    return _runtimeModel.startNodeId;
 | 
						||
                }
 | 
						||
                if (node.setInfo.NodeRejectType == "2")
 | 
						||
                {
 | 
						||
                    return node.setInfo.NodeRejectStep;
 | 
						||
                }
 | 
						||
                return "";
 | 
						||
            }
 | 
						||
            return _runtimeModel.previousId;
 | 
						||
        }
 | 
						||
        ///<summary>
 | 
						||
        /// 标记节点1通过,-1不通过,0驳回
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="nodeId"></param>
 | 
						||
        public void MakeTagNode(string nodeId, Tag tag)
 | 
						||
        {
 | 
						||
            int i = 0;
 | 
						||
            foreach (var item in _runtimeModel.schemeContentJson.nodes)
 | 
						||
            {
 | 
						||
                if (item.id == nodeId)
 | 
						||
                {
 | 
						||
                    var setInfo = _runtimeModel.schemeContentJson.nodes[i].setInfo;
 | 
						||
                    if (setInfo != null)
 | 
						||
                    {
 | 
						||
                        setInfo.Taged = tag.Taged;
 | 
						||
                        setInfo.UserId = tag.UserId;
 | 
						||
                        setInfo.UserName = tag.UserName;
 | 
						||
                        setInfo.Description = tag.Description;
 | 
						||
                        setInfo.TagedTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm");
 | 
						||
                    }
 | 
						||
                    break;
 | 
						||
                }
 | 
						||
                i++;
 | 
						||
            }
 | 
						||
        }
 | 
						||
 | 
						||
        ///<summary>
 | 
						||
        /// 清空节点状态
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="nodeId"></param>
 | 
						||
        public void ClearTagNode(string nodeId)
 | 
						||
        {
 | 
						||
            int i = 0;
 | 
						||
            foreach (var item in _runtimeModel.schemeContentJson.nodes)
 | 
						||
            {
 | 
						||
                if (item.id == nodeId)
 | 
						||
                {
 | 
						||
                    var setInfo = _runtimeModel.schemeContentJson.nodes[i].setInfo;
 | 
						||
                    if (setInfo != null)
 | 
						||
                    {
 | 
						||
                        setInfo.Taged ="";
 | 
						||
                        setInfo.UserId = "";
 | 
						||
                        setInfo.UserName = "";
 | 
						||
                        setInfo.Description = "";
 | 
						||
                        setInfo.TagedTime = "";
 | 
						||
                    }
 | 
						||
                    break;
 | 
						||
                }
 | 
						||
                i++;
 | 
						||
            }
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 获取节点是否允许修改
 | 
						||
        /// 
 | 
						||
        /// </summary>
 | 
						||
        /// <returns>0-不可编辑 1-可编辑</returns>
 | 
						||
        public int GetNodePermitEditable(string nodeId)
 | 
						||
        {
 | 
						||
            if (string.IsNullOrEmpty(nodeId)) return 0;
 | 
						||
            FlowNode node = null;
 | 
						||
            if (_runtimeModel.nodes.TryGetValue(nodeId, out node))
 | 
						||
            {
 | 
						||
                if (node.setInfo != null)
 | 
						||
                {
 | 
						||
                    if (!string.IsNullOrEmpty(node.setInfo.NodeEditable))
 | 
						||
                        return Convert.ToInt32(node.setInfo.NodeEditable);
 | 
						||
                }
 | 
						||
            }
 | 
						||
            return 0;
 | 
						||
        }
 | 
						||
    }
 | 
						||
    #endregion
 | 
						||
}
 | 
						||
 |