using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Internal; using OfficeOpenXml.FormulaParsing.Excel.Functions.Text; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Reflection; using System.Text; using System.Threading.Tasks; using VOL.Core.DBManager; using VOL.Core.EFDbContext; using VOL.Core.Extensions; using VOL.Core.Infrastructure; using VOL.Core.ManageUser; using VOL.Core.Services; using VOL.Core.Utilities; using VOL.Entity.DomainModels; using static Npgsql.PostgresTypes.PostgresCompositeType; namespace VOL.Core.WorkFlow { public static class WorkFlowManager { public static bool Exists() { return WorkFlowContainer.Exists(); } public static bool Exists(T entity) { return WorkFlowContainer.Exists() && GetAuditFlowTable(typeof(T).GetKeyProperty().GetValue(entity).ToString()) != null; } public static bool Exists(string table) { return WorkFlowContainer.Exists(table); } /// /// 获取审批的数据 /// public static async Task GetAuditFormDataAsync(string tableKey, string table) { Type type = WorkFlowContainer.GetType(table); if (type == null) { return Array.Empty(); } var obj = typeof(WorkFlowManager).GetMethod("GetFormDataAsync").MakeGenericMethod(new Type[] { type }) .Invoke(null, new object[] { tableKey, table }) as Task; return await obj; } /// /// 审批表单数据查询与数据源转换 /// /// /// /// /// public static async Task GetFormDataAsync(string tableKey, string table) where T : class { string[] fields = WorkFlowContainer.GetFormFields(table); if (fields == null || fields.Length == 0) { return Array.Empty(); } var tableOptions = await DBServerProvider.DbContext.Set().Where(c => c.TableName == table && fields.Contains(c.ColumnName)) .Select(s => new { s.ColumnName, s.ColumnCnName, s.DropNo, isDate = s.IsImage == 4 }).ToListAsync(); var condition = typeof(T).GetKeyName().CreateExpression(tableKey, Enums.LinqExpressionType.Equal); //动态分库应该查询对应的数据库 var data = await DBServerProvider.DbContext.Set().Where(condition).FirstOrDefaultAsync(); if (data==null) { Console.WriteLine($"未查到数据,表:{table},id:{tableKey}"); return Array.Empty(); } List dictionaries = new List(); var dicNos = tableOptions.Select(s => s.DropNo).ToList(); if (dicNos.Count > 0) { dictionaries = DictionaryManager.GetDictionaries(dicNos, true).ToList(); } List list = new List(); var properties = typeof(T).GetProperties(); foreach (var field in fields) { var property = properties.Where(c => c.Name == field).FirstOrDefault(); string value = property.GetValue(data)?.ToString(); var option = tableOptions.Where(c => c.ColumnName == field).FirstOrDefault(); string name = option?.ColumnCnName; if (string.IsNullOrEmpty(name)) { name = property.GetDisplayName(); } if (option == null || string.IsNullOrEmpty(value)) { list.Add(new { name, value = value ?? "" }); continue; } if (option.isDate) { value = value.GetDateTime().Value.ToString("yyyy-MM-dd"); } else if (!string.IsNullOrEmpty(option.DropNo)) { string val = dictionaries.Where(c => c.DicNo == option.DropNo).FirstOrDefault() ?.Sys_DictionaryList //这里多选的暂时没处理 ?.Where(c => c.DicValue == value)?.Select(s => s.DicName) .FirstOrDefault(); if (!string.IsNullOrEmpty(val)) { value = val; } } list.Add(new { name, value }); } return list; } public static int GetAuditStatus(string value) { return GetAuditFlowTable(value)?.AuditStatus ?? 0; } public static Sys_WorkFlowTable GetAuditFlowTable(string workTableKey) { var table = DBServerProvider.DbContext.Set() .Where(x => x.WorkTable == typeof(T).GetEntityTableName() && x.WorkTableKey == workTableKey) // .Select(s => new { s.CurrentStepId,s.AuditStatus}) .FirstOrDefault(); return table; } private static void Rewrite(T entity, Sys_WorkFlow workFlow, bool changeTableStatus) where T : class { var autditProperty = typeof(T).GetProperties().Where(x => x.Name.ToLower() == "auditstatus").FirstOrDefault(); if (autditProperty == null) { return; } string value = typeof(T).GetKeyProperty().GetValue(entity).ToString(); var dbContext = DBServerProvider.DbContext; var workTable = dbContext.Set().Where(x => x.WorkTableKey == value && x.WorkFlow_Id == workFlow.WorkFlow_Id) .AsNoTracking() .Include(x => x.Sys_WorkFlowTableStep).FirstOrDefault(); if (workTable == null || workFlow.Sys_WorkFlowStep == null || workFlow.Sys_WorkFlowStep.Count == 0) { Console.WriteLine($"未查到流程数据,id:{workFlow.WorkFlow_Id}"); return; } // workTable.CurrentOrderId = 1; //这里还未处理回退到上一个节点 //重新设置第一个节点(有可能是返回上一个节点) string startStepId = workTable.Sys_WorkFlowTableStep.Where(x => x.StepAttrType == StepType.start.ToString()) .Select(s => s.StepId).FirstOrDefault(); workTable.CurrentStepId = workTable.Sys_WorkFlowTableStep.Where(x => x.ParentId == startStepId).Select(s => s.StepId).FirstOrDefault(); workTable.AuditStatus = (int)AuditStatus.待审核; workTable.Sys_WorkFlowTableStep.ForEach(item => { item.Enable = 0; item.AuditId = null; item.Auditor = null; item.AuditDate = null; item.Remark = null; }); if (changeTableStatus) { dbContext.Entry(entity).State = EntityState.Detached; autditProperty.SetValue(entity, 0); dbContext.Entry(entity).Property(autditProperty.Name).IsModified = true; } dbContext.Entry(workTable).State = EntityState.Detached; dbContext.Update(workTable); dbContext.SaveChanges(); } /// /// 新建时写入流程 /// /// /// /// 是否重新生成流程 /// 是否修改原表的审批状态 public static void AddProcese(T entity, bool rewrite = false, bool changeTableStatus = true, Action> addWorkFlowExecuted = null) where T : class { WorkFlowTableOptions workFlow = WorkFlowContainer.GetFlowOptions(entity); //没有对应的流程信息 if (workFlow == null || workFlow.FilterList.Count == 0) { return; } workFlow.WorkTableName = WorkFlowContainer.GetName(); string workTable = typeof(T).GetEntityTableName(); ////重新生成流程 if (rewrite) { Rewrite(entity, workFlow, changeTableStatus); return; } var userInfo = UserContext.Current.UserInfo; Guid workFlowTable_Id = Guid.NewGuid(); Sys_WorkFlowTable workFlowTable = new Sys_WorkFlowTable() { WorkFlowTable_Id = workFlowTable_Id, AuditStatus = (int)AuditStatus.待审核, Enable = 1, WorkFlow_Id = workFlow.WorkFlow_Id, WorkName = workFlow.WorkName, WorkTable = workTable, WorkTableKey = typeof(T).GetKeyProperty().GetValue(entity).ToString(), WorkTableName = workFlow.WorkTableName, CreateID = userInfo.User_Id, CreateDate = DateTime.Now, Creator = userInfo.UserTrueName }; //生成流程的下一步 var steps = workFlow.FilterList.Where(x => x.StepAttrType == StepType.start.ToString()).Select(s => new Sys_WorkFlowTableStep() { Sys_WorkFlowTableStep_Id = Guid.NewGuid(), WorkFlowTable_Id = workFlowTable_Id, WorkFlow_Id = workFlow.WorkFlow_Id, StepId = s.StepId, StepName = s.StepName ?? "流程开始", StepAttrType = s.StepAttrType, NextStepId = null, ParentId = null, StepType = s.StepType, StepValue = s.StepValue, OrderId = 0, Enable = 1, CreateDate = DateTime.Now, Creator = userInfo.UserTrueName, CreateID = userInfo.User_Id }).ToList(); var entities = new List() { entity }; for (int i = 0; i < steps.Count; i++) { var item = steps[i]; //查找下一个满足条件的节点数据 FilterOptions filter = workFlow.FilterList.Where(c => c.ParentIds.Contains(item.StepId) && c.Expression != null && entities.Any(((Func)c.Expression)) ).FirstOrDefault(); //未找到满足条件的找无条件的节点 if (filter == null) { filter = workFlow.FilterList.Where(c => c.ParentIds.Contains(item.StepId) && c.Expression == null).FirstOrDefault(); } if (filter != null) { var setp = workFlow.Sys_WorkFlowStep.Where(x => x.StepId == filter.StepId).Select(s => new Sys_WorkFlowTableStep() { Sys_WorkFlowTableStep_Id = Guid.NewGuid(), WorkFlowTable_Id = workFlowTable_Id, WorkFlow_Id = s.WorkFlow_Id, StepId = s.StepId, StepName = s.StepName, StepAttrType = s.StepAttrType, NextStepId = null, ParentId = item.StepId, StepType = s.StepType, StepValue = s.StepValue, OrderId = i + 1, Enable = 1, CreateDate = DateTime.Now, }).FirstOrDefault(); //显示后续部门与角色审批人待完 //设置下个审核节点 item.NextStepId = setp.StepId; if (!steps.Any(x => x.StepId == setp.StepId)) { steps.Add(setp); } } else { //找不到满足条件的节点,直接结束流程 var end = workFlow.Sys_WorkFlowStep.Where(c => c.StepAttrType == StepType.end.ToString()).ToList(); if (end.Count > 0) { item.NextStepId = end[0].StepId; steps.Add(end.Select(s => new Sys_WorkFlowTableStep() { Sys_WorkFlowTableStep_Id = Guid.NewGuid(), WorkFlowTable_Id = workFlowTable_Id, WorkFlow_Id = s.WorkFlow_Id, StepId = s.StepId, StepName = s.StepName, StepAttrType = s.StepAttrType, NextStepId = null, ParentId = item.StepId, StepType = s.StepType, StepValue = s.StepValue, OrderId = i + 1, Enable = 1, CreateDate = DateTime.Now, }).FirstOrDefault()); i = steps.Count + 1; } } } //foreach (var setp in steps) //{ // if (setp.StepType == (int)AuditType.用户审批) // { // setp.AuditId = setp.StepValue.GetInt(); // } //} //没有满足流程的数据不走流程 int count = steps.Where(x => x.StepAttrType != StepType.start.ToString() && x.StepAttrType != StepType.end.ToString()).Count(); if (count == 0) { return; } //设置进入流程后的第一个审核节点,(开始节点的下一个节点) var nodeInfo = steps.Where(x => x.ParentId == steps[0].StepId).Select(s => new { s.StepId, s.StepName,s.StepType,s.StepValue }).FirstOrDefault(); workFlowTable.CurrentStepId = nodeInfo.StepId; workFlowTable.StepName = nodeInfo.StepName; workFlowTable.Sys_WorkFlowTableStep = steps; //写入日志 var log = new Sys_WorkFlowTableAuditLog() { Id = Guid.NewGuid(), WorkFlowTable_Id = workFlowTable.WorkFlowTable_Id, CreateDate = DateTime.Now, AuditStatus = (int)AuditStatus.待审核, Remark = $"[{userInfo.UserTrueName}]提交了数据" }; var dbContext = DBServerProvider.DbContext; dbContext.Set().Add(workFlowTable); dbContext.Set().Add(log); dbContext.SaveChanges(); if (addWorkFlowExecuted!=null) { var userIds = GetAuditUserIds(nodeInfo.StepType ?? 0, nodeInfo.StepValue); addWorkFlowExecuted.Invoke(entity, userIds); } } /// /// 审核 /// /// /// /// /// /// /// /// /// public static WebResponseContent Audit(T entity, AuditStatus status, string remark, PropertyInfo autditProperty, Func workFlowExecuting, Func, bool, WebResponseContent> workFlowExecuted, bool init = false, Action> initInvoke = null ) where T : class { WebResponseContent webResponse = new WebResponseContent(true); if (init) { if (!WorkFlowContainer.Exists()) { return webResponse; } } var dbContext = DBServerProvider.DbContext; dbContext.QueryTracking = true; ; var query = dbContext.Set(); var keyProperty = typeof(T).GetKeyProperty(); string key = keyProperty.GetValue(entity).ToString(); string workTable = typeof(T).GetEntityTableName(); Sys_WorkFlowTable workFlow = dbContext.Set() .Where(x => x.WorkTable == workTable && x.WorkTableKey == key) .Include(x => x.Sys_WorkFlowTableStep) .FirstOrDefault(); if (workFlow == null) { return webResponse.Error("未查到流程信息,请检查数据是否被删除"); } workFlow.AuditStatus = (int)status; var currentStep = workFlow.Sys_WorkFlowTableStep.Where(x => x.StepId == workFlow.CurrentStepId).FirstOrDefault(); if (currentStep == null) { return webResponse.Error($"未查到流程陈点[workFlow.CurrentStepId]信息,请检查数据是否被删除"); } Sys_WorkFlowTableStep nextStep = null; //获取下一步审核id var nextStepId = currentStep.NextStepId; nextStep = workFlow.Sys_WorkFlowTableStep.Where(x => x.StepId == nextStepId).FirstOrDefault(); var user = UserContext.Current.UserInfo; //生成审核记录 var log = new Sys_WorkFlowTableAuditLog() { Id = Guid.NewGuid(), StepId = currentStep.StepId, WorkFlowTable_Id = currentStep.WorkFlowTable_Id, WorkFlowTableStep_Id = currentStep.Sys_WorkFlowTableStep_Id, AuditDate = DateTime.Now, AuditId = user.User_Id, Auditor = user.UserTrueName, AuditResult = remark, Remark = remark, AuditStatus = (int)status, CreateDate = DateTime.Now, StepName = currentStep.StepName }; var filterOptions = WorkFlowContainer.GetFlowOptions(x => x.WorkFlow_Id == workFlow.WorkFlow_Id) .FirstOrDefault() ?.FilterList ?.Where(x => x.StepId == currentStep.StepId) ?.FirstOrDefault(); if (filterOptions != null) { //审核未通过或者驳回 if (!CheckAuditStatus(workFlow, filterOptions, currentStep, status)) { //记录日志 dbContext.Set().Add(log); string msg = null; if (AuditStatus.审核未通过 == status) { if (filterOptions.AuditRefuse == (int)AuditRefuse.返回上一节点) { msg = "审批未通过,返回上一节点"; } else if (filterOptions.AuditRefuse == (int)AuditRefuse.流程重新开始) { msg = "审批未通过,流程重新开始"; } } else if (AuditStatus.驳回 == status) { if (filterOptions.AuditBack == (int)AuditBack.返回上一节点) { msg = "审批被驳回,返回上一节点"; } else if (filterOptions.AuditBack == (int)AuditBack.流程重新开始) { msg = "审批被驳回,流程重新开始"; } } if (msg!=null) { var auditLog = new Sys_WorkFlowTableAuditLog() { Id = Guid.NewGuid(), StepId = currentStep.StepId, WorkFlowTable_Id = currentStep.WorkFlowTable_Id, WorkFlowTableStep_Id = currentStep.Sys_WorkFlowTableStep_Id, AuditDate = DateTime.Now, AuditId = user.User_Id, Auditor = user.UserTrueName, AuditResult = remark, Remark = msg, AuditStatus = (int)status, CreateDate = DateTime.Now, StepName = currentStep.StepName }; dbContext.Set().Add(auditLog); } //autditProperty.SetValue(entity, (int)status); //query.Update(entity); //修改状态 dbContext.Set().Update(workFlow); dbContext.SaveChanges(); dbContext.Entry(workFlow).State = EntityState.Detached; //发送邮件(appsettings.json配置文件里添加邮件信息) SendMail(workFlow, filterOptions, nextStep, dbContext); if (workFlowExecuted != null) { webResponse = workFlowExecuted.Invoke(entity, status, GetAuditUserIds(nextStep?.StepType ?? 0, nextStep?.StepValue), false); } return webResponse; } } if (autditProperty == null) { autditProperty = typeof(T).GetProperties().Where(s => s.Name.ToLower() == "auditstatus").FirstOrDefault(); } bool isLast = false; //更新明细记录 workFlow.Sys_WorkFlowTableStep.ForEach(x => { if (workFlow.CurrentStepId == x.StepId) { x.AuditId = user.User_Id; x.Auditor = user.UserTrueName; x.AuditDate = DateTime.Now; //如果审核拒绝或驳回并退回上一步,待完 x.AuditStatus = (int)status; x.Remark = remark; } }); //没有找到下一步审批,审核完成 if ((nextStep == null || nextStep.StepAttrType == StepType.end.ToString())) { if (status == AuditStatus.审核通过) { workFlow.CurrentStepId = "审核完成"; } else { workFlow.CurrentStepId = "流程结束"; } workFlow.AuditStatus = (int)status; //发送邮件(appsettings.json配置文件里添加邮件信息) SendMail(workFlow, filterOptions, nextStep, dbContext); autditProperty.SetValue(entity, (int)status); dbContext.Set().Update(workFlow); query.Update(entity); dbContext.Set().Add(log); dbContext.SaveChanges(); if (workFlowExecuted != null) { webResponse = workFlowExecuted.Invoke(entity, status, GetAuditUserIds(nextStep?.StepType ?? 0, nextStep?.StepValue), true); } return webResponse; } //指向下一个人审批 if (nextStep != null && status == AuditStatus.审核通过) { workFlow.CurrentStepId = nextStep.StepId; //原表显示审核中状态 autditProperty.SetValue(entity, (int)AuditStatus.审核中); workFlow.AuditStatus = (int)AuditStatus.审核中; } else { autditProperty.SetValue(entity, (int)status); } //下一个节点=null或节下一个节点为结束节点,流程结束 if (nextStep == null || workFlow.Sys_WorkFlowTableStep.Exists(c => c.StepId == nextStep.StepId && c.StepAttrType == StepType.end.ToString())) { isLast = true; } if (workFlowExecuting != null) { webResponse = workFlowExecuting.Invoke(entity, status, isLast); if (!webResponse.Status) { return webResponse; } } query.Update(entity); dbContext.Set().Update(workFlow); dbContext.Set().Add(log); dbContext.SaveChanges(); dbContext.Entry(workFlow).State = EntityState.Detached; if (workFlowExecuted != null) { webResponse = workFlowExecuted.Invoke(entity, status, GetAuditUserIds(nextStep?.StepType ?? 0, nextStep?.StepValue), isLast); } SendMail(workFlow, filterOptions, nextStep, dbContext); return webResponse; } private static bool CheckAuditStatus(Sys_WorkFlowTable workFlow, FilterOptions filterOptions, Sys_WorkFlowTableStep currentStep, AuditStatus status) { //如果审核拒绝或驳回并退回上一步,待完 //重新配置流程待完 if (status != AuditStatus.审核未通过 && status != AuditStatus.驳回) { return true; } if (filterOptions.AuditRefuse == (int)AuditRefuse.返回上一节点 || filterOptions.AuditBack == (int)AuditBack.返回上一节点) { var preStep = workFlow.Sys_WorkFlowTableStep.Where(x => x.NextStepId == currentStep.StepId && x.StepAttrType == StepType.node.ToString()).FirstOrDefault(); if (preStep != null) { preStep.AuditStatus = null; preStep.AuditId = null; preStep.AuditDate = null; preStep.Auditor = null; workFlow.CurrentStepId = preStep.StepId; workFlow.AuditStatus = (int)AuditStatus.审核中; DBServerProvider.DbContext.Update(preStep); } return false; } else if (filterOptions.AuditRefuse == (int)AuditRefuse.流程重新开始 || filterOptions.AuditBack == (int)AuditBack.流程重新开始) { //重新开始 var steps = workFlow.Sys_WorkFlowTableStep.Where(x => x.StepAttrType == StepType.node.ToString() && (x.AuditStatus >= 0)).ToList(); if (steps.Count > 0) { foreach (var item in steps) { item.AuditStatus = null; item.AuditId = null; item.AuditDate = null; item.Auditor = null; } //重新指向第一个节点 workFlow.CurrentStepId = steps.OrderBy(c => c.OrderId).Select(c => c.StepId).FirstOrDefault(); workFlow.AuditStatus = (int)AuditStatus.审核中; DBServerProvider.DbContext.UpdateRange(steps); } return false; } return true; } private static void SendMail(Sys_WorkFlowTable workFlow, FilterOptions filterOptions, Sys_WorkFlowTableStep nextStep, VOLContext dbContext) { if (filterOptions.SendMail != 1) { return; } if (nextStep == null) { nextStep = new Sys_WorkFlowTableStep() { }; } //审核发送邮件通知待完 var userIds = GetAuditUserIds(nextStep.StepType ?? 0, nextStep.StepValue); if (userIds.Count == 0) { return; } var emails = dbContext.Set() .Where(x => userIds.Contains(x.User_Id) && x.Email != null & x.Email != "").Select(s => s.Email) .ToList(); Task.Run(() => { string msg = ""; try { string title = $"有新的任务待审批:流程【{workFlow.WorkName}】,任务【{nextStep.StepName}】"; MailHelper.Send(title, title, string.Join(";", emails)); msg = $"审批流程发送邮件,流程名称:{workFlow.WorkName},流程id:{workFlow.WorkFlow_Id},步骤:{nextStep.StepName},步骤Id:{nextStep.StepId},收件人:{string.Join(";", emails)}"; Logger.AddAsync(msg); } catch (Exception ex) { msg += "邮件发送异常:"; Logger.AddAsync(msg, ex.Message + ex.StackTrace); } }); } /// /// 获取审批人的id /// /// /// private static List GetAuditUserIds(int stepType, string nextId = null) { List userIds = new List(); if (stepType == 0 || string.IsNullOrEmpty(nextId)) { return userIds; } if (stepType == (int)AuditType.角色审批) { int roleId = nextId.GetInt(); userIds = DBServerProvider.DbContext.Set().Where(s => s.Role_Id == roleId).Take(50).Select(s => s.User_Id).ToList(); } else if (stepType == (int)AuditType.部门审批) { Guid departmentId = nextId.GetGuid() ?? Guid.Empty; userIds = DBServerProvider.DbContext.Set().Where(s => s.DepartmentId == departmentId && s.Enable == 1).Take(50).Select(s => s.UserId).ToList(); } else { return nextId.Split(",").Select(c => c.GetInt()).ToList(); } return userIds; } } }