/// <summary> /// 构造函数 /// </summary> /// <param name="engineContext">流程引擎上下文</param> /// <param name="processInst">流程实例</param> /// <param name="activityInst">活动实例</param> public ActivityContext(ProcessInst processInst, ActivityInst activityInst) { this.ProcessInst = processInst; this.ActivityInst = activityInst; }
/// <summary> /// 构造函数 /// </summary> /// <param name="engineContext">流程引擎上下文</param> /// <param name="processInst">流程实例</param> /// <param name="activityInst">活动实例</param> /// <param name="workItem">工作项</param> public WorkItemContext(ProcessInst processInst, ActivityInst activityInst, WorkItem workItem) { this.ProcessInst = processInst; this.ActivityInst = activityInst; this.WorkItem = workItem; }
public void SkipToActivity(IUser user, ActivityInst srcActInst, Activity destActivity) { throw new NotImplementedException(); }
/// <summary> /// 获取一个流程实例 /// </summary> /// <param name="processInstID">流程实例ID</param> /// <returns></returns> private ProcessInst GetToRunProcessInst(string processInstID, IUser user) { ProcessInst processInst = Persistence.GetProcessInst(processInstID); ProcessDefine processDefine = GetProcessDefine(processInst.ProcessDefID); string processDefID = processInst.ProcessDefID; //如果流程还未启动,产生一个活动实例 if (processInst.CurrentState == (short)ProcessInstStatus.NoStart) { Activity srcActivity = processDefine.StartActivity; ActivityInst srcActInst = Persistence.GetActivityInsts(processInstID, srcActivity.ID, ActivityInstStatus.Compeleted)[0]; IList<Activity> destActivities = Persistence.GetOutActivities(processDefID, srcActivity.ID); UnitOfWork.ExecuteWithTrans<ProcessInst>(() => { foreach (var destActivity in destActivities) { DateTime startTime = DateTime.Now.AddSeconds(-1); ActivityInst destActInst = new ActivityInst() { ActivityDefID = destActivity.ID, CurrentState = (short)ActivityInstStatus.NoStart, ID = IdGenerator.NewComb().ToString(), CreateTime = startTime, Description = destActivity.Description, EndTime = WFUtil.MaxDate, Name = destActivity.Name, ProcessInstID = processInstID, RollbackFlag = 0, StartTime = startTime, SubProcessInstID = string.Empty, Type = (short)destActivity.ActivityType.Cast<ActivityType>(ActivityType.ManualActivity) }; Domain.Transition transition = new Domain.Transition() { ID = IdGenerator.NewComb().ToString(), DestActID = destActivity.ID, DestActInstID = destActInst.ID, DestActInstName = destActInst.Name, DestActName = destActivity.Name, ProcessInstID = processInstID, ProcessInstName = processInst.Name, SrcActID = srcActivity.ID, SrcActInstID = srcActInst.ID, SrcActInstName = srcActInst.Name, SrcActName = srcActivity.Name, TransTime = startTime }; TransControl transControl = new TransControl() { ID = IdGenerator.NewComb().ToString(), DestActID = destActivity.ID, DestActName = destActivity.Name, ProcessInstID = processInst.ID, SrcActID = srcActivity.ID, SrcActName = srcActivity.Name, TransTime = startTime, TransWeight = 100 }; if (destActivity is ManualActivity) { ManualActivity ma = destActivity as ManualActivity; WorkItem wi = new WorkItem() { ID = IdGenerator.NewComb().ToString(), ActionMask = string.Empty, ActionURL = ma.CustomURL.SpecifyURL, ActivityInstID = destActInst.ID, ActivityInstName = destActInst.Name, AllowAgent = (short)(ma.AllowAgent ? 1 : 0), BizState = (short)WorkItemBizStatus.Common, CreateTime = startTime, Creator = user.ID, CreatorName = user.Name, CurrentState = (short)WorkItemStatus.WaitExecute, Description = destActInst.Description, EndTime = WFUtil.MaxDate, Executor = string.Empty, ExecutorName = string.Empty, IsTimeOut = 0, Name = destActInst.Name, Participant = string.Empty, ProcessID = processDefID, ProcessInstID = processInst.ID, ProcessInstName = processInst.Name, ProcessName = processDefine.Name, RemindTime = WFUtil.MaxDate, RootProcessInstID = string.Empty, StartTime = startTime, TimeOutTime = WFUtil.MaxDate, Type = destActInst.Type }; //foreach (var participantor in ma.Participant.Participantors) //{ // Domain.Participant participant = new Domain.Participant() // { // ID = IdGenerator.NewComb().ToString(), // CreateTime = createTime, // DelegateType = (short)DelegateType.Sponsor, // Name = participantor.Name, // ParticipantID = participantor.ID, // ParticipantIndex = participantor.SortOrder, // ParticipantType = (short)participantor.ParticipantorType.Cast<ParticipantorType>(ParticipantorType.Person), // PartiInType = (short)PartiInType.Exe, // WorkItemID = wi.ID, // WorkItemState = (short)wi.CurrentState // }; // repository.SaveOrUpdate(participant); //} Domain.Participant participant = new Domain.Participant() { ID = IdGenerator.NewComb().ToString(), CreateTime = startTime, DelegateType = (short)DelegateType.Sponsor, Name = user.Name, ParticipantID = user.ID, ParticipantIndex = 1, ParticipantType = (short)ParticipantorType.Person, PartiInType = (short)PartiInType.Exe, WorkItemID = wi.ID, WorkItemState = (short)wi.CurrentState }; repository.SaveOrUpdate(participant); repository.SaveOrUpdate(wi); } srcActInst.CurrentState = (short)ActivityInstStatus.Compeleted; repository.SaveOrUpdate(srcActInst); repository.SaveOrUpdate(destActInst); repository.SaveOrUpdate(transition); repository.SaveOrUpdate(transControl); } }); } return processInst; }
/// <summary> /// 创建流程实例 /// </summary> /// <param name="processDefID">流程定义ID</param> /// <param name="parentProcessDefID">父流程ID</param> /// <param name="parentActivityID">父活动ID</param> /// <returns></returns> public string CreateAProcess(string processDefID, string parentProcessDefID, string parentActivityID) { ProcessDef processDef = repository.GetDomain<ProcessDef>(processDefID); if (processDef == null) { WFUtil.HandleException(new MessageException() { PromptMessage = string.Format("ID={0}的流程不存在", processDefID), Source = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName, }); return string.Empty; } if (processDef.CurrentState == (short)ProcessStatus.Candidate) { WFUtil.HandleException(new MessageException() { PromptMessage = string.Format("ID={0}的流程还未发布,不能创建流程", processDefID), Source = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName, }); return string.Empty; } DateTime startTime = DateTime.Now.AddSeconds(-2); ProcessDefine define = GetProcessDefine(processDefID); ProcessInst processInst = new ProcessInst() { ID = IdGenerator.NewComb().ToString(), ProcessDefID = processDefID, CreateTime = DateTime.Now, Creator = WFUtil.User.ID, CurrentState = (short)ProcessInstStatus.NoStart, IsTimeOut = 0, Name = processDef.Text, Description = processDef.Description, ParentProcessID = parentProcessDefID, ParentActivityID = parentActivityID, StartTime = startTime, EndTime = WFUtil.MaxDate, FinalTime = WFUtil.MaxDate, LimitTime = WFUtil.MaxDate, ProcessDefName = processDef.Text, ProcessVersion = processDef.Version, RemindTime = WFUtil.MaxDate, TimeOutTime = WFUtil.MaxDate }; Activity ad = Persistence.GetStartActivity(processDefID); ActivityInst activityInst = new ActivityInst() { ID = IdGenerator.NewComb().ToString(), ActivityDefID = ad.ID, CreateTime = DateTime.Now, CurrentState = (short)ActivityInstStatus.Compeleted, Description = ad.Description, EndTime = WFUtil.MaxDate, Name = string.Format("启动{0}", processDef.Text), ProcessInstID = processInst.ID, RollbackFlag = 0, StartTime = startTime, SubProcessInstID = string.Empty, Type = (short)ActivityType.StartActivity }; UnitOfWork.ExecuteWithTrans<ProcessInst>(() => { repository.SaveOrUpdate(processInst); repository.SaveOrUpdate(activityInst); if (processDef.IsActive != 1) { processDef.IsActive = 1; repository.SaveOrUpdate(processDef); } }); return processInst.ID; }
/// <summary> /// 回退流程到某个活动 /// 说明:将当前活动实例回退到,某个目标活动。 /// 具体步骤: /// 1、寻找目标活动实例。 /// 2、将目标活动及后续已完成的活动实例及工作项终止。 /// 3、终止当前活动实例及工作项。(注:为记录当前执行人再终止一次) /// 4、重新启动可退回活动。 /// </summary> /// <param name="user"></param> /// <param name="srcActInst"></param> /// <param name="destActivity"></param> public void RollbackActivity(IUser user, ActivityInst srcActInst, Activity destActivity) { var destActInst = repository.Query<ActivityInst>().FirstOrDefault(ai => ai.ProcessInstID == srcActInst.ProcessInstID && ai.RollbackFlag == 0 && ai.ActivityDefID == destActivity.ID); if (destActInst != null) { DateTime createTime = DateTime.Now; UnitOfWork.ExecuteWithTrans<ProcessDef>(() => { //终止destActivity所有的后续已执行的的活动实例 TerminateSelfAndOutActivity(destActInst.ProcessInstID, destActivity); //将当前活动实例的工作项终止(将终止人设为当前用户) var workItems = Persistence.GetWorkItems(srcActInst.ID); foreach (var wi in workItems) { wi.CurrentState = (short)WorkItemStatus.Terminated; wi.ExecutorName = user.Name; wi.Executor = user.ID; wi.ExecuteTime = createTime; log.Info(string.Format("终止工作项{0}-{1}", wi.ID, wi.Name)); repository.SaveOrUpdate(wi); } //将当前活动实例终止 srcActInst.CurrentState = (short)ActivityInstStatus.Terminated; srcActInst.RollbackFlag = 1; srcActInst.EndTime = createTime; log.Info(string.Format("终止活动实例{0}-{1}", srcActInst.ID, srcActInst.Name)); repository.SaveOrUpdate(srcActInst); //将目标活动实例的工作项重置为待执行 workItems = Persistence.GetWorkItems(destActInst.ID); foreach (var wi in workItems) { wi.CurrentState = (short)WorkItemStatus.WaitExecute; //wi.ExecutorName = user.Name; //wi.Executor = user.ID; // wi.ExecuteTime = null;// DateTime.MaxValue; log.Info(string.Format("启动工作项{0}-{1}", wi.ID, wi.Name)); repository.SaveOrUpdate(wi); } //将目标活动实例状态置为未开始 destActInst.CurrentState = (short)ActivityInstStatus.NoStart; destActInst.RollbackFlag = 0; log.Info(string.Format("启动活动实例{0}-{1}", destActInst.ID, destActInst.Name)); repository.SaveOrUpdate(destActInst); ProcessInst processInst = repository.GetDomain<ProcessInst>(srcActInst.ProcessInstID); Domain.Transition transition = new Domain.Transition() { ID = IdGenerator.NewComb().ToString(), DestActID = destActivity.ID, DestActInstID = destActInst.ID, DestActInstName = destActInst.Name, DestActName = destActivity.Name, ProcessInstID = srcActInst.ProcessInstID, ProcessInstName = processInst.Name, SrcActID = srcActInst.ActivityDefID, SrcActInstID = srcActInst.ID, SrcActInstName = srcActInst.Name, SrcActName = srcActInst.Name, TransTime = createTime }; repository.SaveOrUpdate(transition); TransControl transControl = new TransControl() { ID = IdGenerator.NewComb().ToString(), DestActID = destActivity.ID, DestActName = destActivity.Name, ProcessInstID = srcActInst.ProcessInstID, SrcActID = srcActInst.ActivityDefID, SrcActName = srcActInst.Name, TransTime = createTime, TransWeight = 100 }; repository.SaveOrUpdate(transControl); }); } }
private void UpdateActivityInstAndRoute(ActivityInst activityInst) { IList<WorkItem> workItems = Persistence.GetWorkItems(activityInst.ID); ActivityInstStatus newStatus = ActivityInstStatus.NoStart; bool allCompleted = true; foreach (WorkItem ti in workItems) { switch (ti.CurrentState.Cast<WorkItemStatus>(WorkItemStatus.WaitExecute)) { case WorkItemStatus.WaitExecute: allCompleted = false; break; case WorkItemStatus.Suspended: allCompleted = false; break; case WorkItemStatus.Executing: allCompleted = false; if (newStatus == ActivityInstStatus.NoStart) newStatus = ActivityInstStatus.Running; break; case WorkItemStatus.Compeleted: if (newStatus == ActivityInstStatus.NoStart || newStatus == ActivityInstStatus.Running) newStatus = ActivityInstStatus.Running; break; case WorkItemStatus.Canceled: break; case WorkItemStatus.Terminated: break; } } if (allCompleted) newStatus = ActivityInstStatus.Compeleted; if (activityInst.CurrentState != (short)newStatus) { activityInst.CurrentState = (short)newStatus; Persistence.UpdateActivityInstStatus(activityInst.ID, newStatus); waiting = true; } if (allCompleted) { newStatus = ActivityInstStatus.Compeleted; RouteActivityInst(activityInst); } }
private bool HandlerAutoActivity(string processDefID, Activity srcActivity, Activity destActivity, ActivityInst destActInst) { DateTime createTime = DateTime.Now; AutoActivity autoActivity = destActivity as AutoActivity; ManualActivity manualActivity = srcActivity as ManualActivity; string actionURL = null; if (manualActivity != null && manualActivity.CustomURL != null) actionURL = manualActivity.CustomURL.SpecifyURL; WorkItem wi = new WorkItem() { ID = IdGenerator.NewComb().ToString(), ActionMask = string.Empty, ActivityInstID = destActInst.ID, ActivityInstName = destActInst.Name, BizState = (short)WorkItemBizStatus.Common, CreateTime = createTime, Creator = WFUtil.User.ID, CreatorName = WFUtil.User.Name, CurrentState = (short)WorkItemStatus.Executing, Description = destActInst.Description, EndTime = WFUtil.MaxDate, Executor = string.Empty, ExecutorName = string.Empty, IsTimeOut = 0, Name = destActInst.Name, Participant = "AgileEAP.Workflow", ProcessID = processDefID, ProcessInstID = destActInst.ProcessInstID, ProcessInstName = Context.ProcessInst.Name, ProcessName = Context.ProcessDefine.Name, RemindTime = WFUtil.MaxDate, RootProcessInstID = string.Empty, StartTime = createTime, TimeOutTime = WFUtil.MaxDate, Type = destActInst.Type, ActionURL = actionURL }; bool isCompeleted = false; //如果自动处理完成并返回true,完成工作项,并路由到下一活动 if (DefaultExecutor.Execute(string.Format("{0}-{1}-{2}", Context.ProcessDefine.ID, Context.ProcessDefine.Version, destActivity.ID), wi)) { wi.CurrentState = (short)WorkItemStatus.Compeleted; Persistence.Repository.SaveOrUpdate(wi); RouteActivityInst(destActInst); isCompeleted = true; } else { wi.CurrentState = (short)WorkItemStatus.Suspended; Persistence.Repository.SaveOrUpdate(wi); isCompeleted = false; } return isCompeleted; }
/// <summary> /// 产生迁移活动 /// </summary> /// <param name="srcActInst"></param> public void RouteActivityInst(ActivityInst srcActInst) { Activity srcActivity = Context.ProcessDefine.Activities.FirstOrDefault(a => a.ID == srcActInst.ActivityDefID); IList<Activity> activateActivities = GetActivateActivities(Context.ProcessInst.ProcessDefID, srcActInst); string processInstID = Context.ProcessInst.ID; string processDefID = Context.ProcessInst.ProcessDefID; UnitOfWork.ExecuteWithTrans<WorkItem>(() => { foreach (var destActivity in activateActivities) { DateTime createTime = DateTime.Now; ActivityInst destActInst = new ActivityInst() { ActivityDefID = destActivity.ID, CurrentState = (short)(destActivity.ActivityType == ActivityType.EndActivity || destActivity.ActivityType == ActivityType.AutoActivity ? ActivityInstStatus.Compeleted : ActivityInstStatus.NoStart), ID = IdGenerator.NewComb().ToString(), CreateTime = createTime, Description = destActivity.Description, EndTime = WFUtil.MaxDate, Name = destActivity.Name, ProcessInstID = processInstID, RollbackFlag = 0, StartTime = createTime, SubProcessInstID = string.Empty, Type = (short)destActivity.ActivityType.Cast<ActivityType>(ActivityType.ManualActivity) }; Domain.Transition transition = new Domain.Transition() { ID = IdGenerator.NewComb().ToString(), DestActID = destActivity.ID, DestActInstID = destActInst.ID, DestActInstName = destActInst.Name, DestActName = destActivity.Name, ProcessInstID = processInstID, ProcessInstName = Context.ProcessInst.Name, SrcActID = srcActivity.ID, SrcActInstID = srcActInst.ID, SrcActInstName = srcActInst.Name, SrcActName = srcActivity.Name, TransTime = createTime }; TransControl transControl = new TransControl() { ID = IdGenerator.NewComb().ToString(), DestActID = destActivity.ID, DestActName = destActivity.Name, ProcessInstID = processInstID, SrcActID = srcActivity.ID, SrcActName = srcActivity.Name, TransTime = createTime, TransWeight = 100 }; //srcActInst.CurrentState = (short)ActivityInstStatus.Compeleted; if (destActivity is ManualActivity) { #region ManualActivityHandler ManualActivity ma = destActivity as ManualActivity; WorkItem wi = new WorkItem() { ID = IdGenerator.NewComb().ToString(), ActionMask = string.Empty, ActionURL = ma.CustomURL.SpecifyURL, ActivityInstID = destActInst.ID, ActivityInstName = destActInst.Name, AllowAgent = (short)(ma.AllowAgent ? 1 : 0), BizState = (short)WorkItemBizStatus.Common, CreateTime = createTime, Creator = WFUtil.User.ID, CreatorName = WFUtil.User.Name, CurrentState = (short)WorkItemStatus.WaitExecute, Description = destActInst.Description, EndTime = WFUtil.MaxDate, Executor = string.Empty, ExecutorName = string.Empty, IsTimeOut = 0, Name = destActInst.Name, Participant = Persistence.GetParticipant(processDefID, destActivity.ID), ProcessID = processDefID, ProcessInstID = processInstID, ProcessInstName = Context.ProcessInst.Name, ProcessName = Context.ProcessDefine.Name, RemindTime = WFUtil.MaxDate, RootProcessInstID = string.Empty, StartTime = createTime, TimeOutTime = WFUtil.MaxDate, Type = destActInst.Type, //ExecuteTime = null, }; IList<Participantor> participantors = assignParticipant == null ? ma.Participant.Participantors : new List<Participantor> { assignParticipant() }; foreach (var participantor in participantors) { Domain.Participant participant = new Domain.Participant() { ID = IdGenerator.NewComb().ToString(), CreateTime = createTime, DelegateType = (short)DelegateType.Sponsor, Name = participantor.Name, ParticipantID = participantor.ID, ParticipantIndex = participantor.SortOrder, ParticipantType = (short)participantor.ParticipantorType.Cast<ParticipantorType>(ParticipantorType.Person), PartiInType = (short)PartiInType.Exe, WorkItemID = wi.ID, WorkItemState = (short)wi.CurrentState }; Persistence.Repository.SaveOrUpdate(participant); } Persistence.Repository.SaveOrUpdate(wi); #endregion } else if (destActivity is AutoActivity) { if (!HandlerAutoActivity(processDefID, srcActivity, destActivity, destActInst)) destActInst.CurrentState = (short)ActivityInstStatus.Suspended; } srcActInst.CurrentState = (short)ActivityInstStatus.Compeleted; Persistence.Repository.SaveOrUpdate(srcActInst); Persistence.Repository.SaveOrUpdate(destActInst); Persistence.Repository.SaveOrUpdate(transition); Persistence.Repository.SaveOrUpdate(transControl); } }); }
/// <summary> /// 获取待运行活动 /// </summary> /// <param name="processDefID"></param> /// <param name="srcActInst"></param> /// <returns></returns> public IList<Activity> GetActivateActivities(string processDefID, ActivityInst srcActInst) { IList<Definition.Transition> transitions = Persistence.GetOutTransitions(processDefID, srcActInst.ActivityDefID); Activity srcActDef = Persistence.GetActivity(processDefID, srcActInst.ActivityDefID); IList<Activity> activateActivities = new List<Activity>(); Activity defaultActivity = null; foreach (var transition in transitions) { //IDictionary<string, object> parameters = new Dictionary<string, object>(); //parameters.SafeAdd("money", 1000); //parameters.SafeAdd("number", 4); //Context.Parameters = parameters; ////engine.SetParameter(":money", 1000); //transition.Expression = "return @money-100>0&&@number<10;"; //new Regex(@"[^@@](?<p>@\w+)");对@@value,不表示变量;Regex(@"@\w*")以@开头的表示变量。 string expression = transition.Expression; try { bool expressionResult = string.IsNullOrWhiteSpace(expression); if (!expressionResult) { var prefix = WFUtil.ExpressionVariablePrefix; Regex regex = new Regex(string.Format(@"{0}\w*", prefix)); MatchCollection matches = regex.Matches(expression.Replace(string.Format("{0}{0}", prefix), "###")); JintEngine engine = new JintEngine(); if (matches != null && Context.Parameters != null) { foreach (Match match in matches) { string variable = match.Value.TrimStart(prefix); if (Context.Parameters.ContainsKey(variable)) engine.SetParameter(variable, Context.Parameters[variable]); } } expression = expression.Replace(string.Format("{0}{0}", prefix), "###").Replace(prefix.ToString(), "").Replace("###", prefix.ToString()); expressionResult = (bool)engine.Run(expression); } Activity destActivity = Persistence.GetActivity(processDefID, transition.DestActivity); //记住默认活动 if (transition.IsDefault) defaultActivity = destActivity; if (expressionResult && CanActivateActiviy(srcActInst.ProcessInstID, destActivity)) { activateActivities.SafeAdd(destActivity); } } catch (Exception ex) { WFUtil.HandleException(new WFException(typeof(ProcessRuntime).FullName, string.Format("计算表达式{0}出错", expression), ex)); throw; } } if (activateActivities.Count == 0 && defaultActivity != null && CanActivateActiviy(srcActInst.ProcessInstID, defaultActivity)) { activateActivities.Add(defaultActivity); } return activateActivities; }
public IList<WorkItem> GetExecutingWorkItems(ActivityInst activityInst) { return Persistence.GetWorkItems(activityInst.ID).Where(w => w.CurrentState == (short)WorkItemStatus.Executing).ToList(); }