using Hotline.File; using Hotline.Share.Dtos; using Hotline.Share.Dtos.FlowEngine; using Hotline.Share.Dtos.FlowEngine.Definition; using Hotline.Share.Dtos.FlowEngine.Workflow; using Hotline.Share.Enums.FlowEngine; using SqlSugar; using XF.Domain.Entities; using XF.Domain.Exceptions; namespace Hotline.FlowEngine.Workflows; public class WorkflowStep : StepBasicEntity { [Navigate(NavigateType.ManyToOne, nameof(WorkflowId))] public Workflow Workflow { get; set; } [Navigate(NavigateType.OneToOne, nameof(Id), nameof(Workflows.WorkflowTrace.StepId))] public WorkflowTrace WorkflowTrace { get; set; } //[Navigate(NavigateType.OneToMany, nameof(WorkflowStepHandler.WorkflowStepId))] //public List StepHandlers { get; set; } #region Method /// /// 是否处于会签流程中(不包含顶层发起会签节点) /// public bool IsInCountersign() => CountersignPosition != ECountersignPosition.None; ///// ///// 是否发起过会签 ///// //public bool HasStartedCountersign() => !string.IsNullOrEmpty(StartCountersignId); ///// ///// 接办 ///// //public void Accept(string userId, string? userName, string orgId, string? orgName, string? orgAreaCode, // string? orgAreaName) //{ // AcceptorId = userId; // AcceptorName = userName; // AcceptorOrgId = orgId; // AcceptorOrgName = orgName; // AcceptorOrgAreaCode = orgAreaCode; // AcceptorOrgAreaName = orgAreaName; // AcceptTime = DateTime.Now; // Status = EWorkflowStepStatus.WaitForHandle; //} ///// ///// 节点办理完成 ///// //public void Handle( // string userId, string? userName, // string orgId, string? orgName, // string? orgAreaCode, string? orgAreaName, // bool orgIsCenter, string opinion, string nextStepCode) //{ // base.Handle(userId, userName, orgId, orgName, orgAreaCode, orgAreaName, orgIsCenter, opinion); // if (!IsInCountersign() // && InstanceMode is EInstanceMode.Config // && StepType is not EStepType.End) // { // var step = NextSteps.FirstOrDefault(d => d.Code == nextStepCode); // if (step != null) // step.Selected = true; // } //} /// /// 会签结束 /// public void CountersignEnd() => IsStartedCountersignEnd = true; /// /// 开启会签 /// public void StartCountersign(string startCountersignId) { IsStartCountersign = true; StartCountersignId = startCountersignId; IsStartedCountersignEnd = false; } //public void CreateCountersignSteps(List nextSteps) => // CountersignSteps = nextSteps // .Select(d => new CountersignStep { StepId = d.Id }) // .ToList(); /// /// step设置为可接办状态 /// public void SetAssigned() => Status = EWorkflowStepStatus.WaitForAccept; ///// ///// 依据当前节点获取下一节点会签状态 ///// ///// //public ECountersignPosition GetNextStepCountersignPosition() => // IsStartCountersign // ? ECountersignPosition.Multi // : IsInCountersign() // ? ECountersignPosition.Single // : ECountersignPosition.None; public bool IsCenter() => BusinessType is EBusinessType.Center or EBusinessType.Send; public bool IsOrg() => BusinessType is EBusinessType.Department; /// /// 重置节点,只清除办理痕迹(退回场景/依据会签开始节点复制会签汇总节点,将上一级节点重置等待重新办理) /// public void Reset() { HandleTime = null; AcceptorId = null; AcceptorName = null; AcceptorOrgId = null; AcceptorOrgName = null; AcceptorOrgAreaCode = null; AcceptorOrgAreaName = null; AcceptTime = null; IsStartCountersign = false; NextSteps.ForEach(d => d.Selected = false); } /// /// 重置办理参数 /// public void ResetParameters() { NextHandlers = new(); NextMainHandler = null; NextStepCode = null; BackToCountersignEnd = false; IsSms = false; Opinion = null; FileJson = new(); StepExpiredTime = null; } ///// ///// 发起会签节点发起的会签是否全都办理完成 ///// ///// //public bool StartedCountersignHasAllHandled() //{ // //if (!HasStartedCountersign()) // // throw new UserFriendlyException("该节点未发起会签"); // //outer属于特殊会签 // return CountersignSteps.All(d => d.Completed); //} /// /// 动态实例化节点是否应该终止 /// /// public bool DynamicShouldTerminal() => !string.IsNullOrEmpty(NextStepCode) && TerminalDynamicMark == NextStepCode; /// /// 是否是顶级会签汇总节点 /// public bool IsTopCountersignEndStep(string? topCountersignStepId) { if (string.IsNullOrEmpty(topCountersignStepId)) throw new UserFriendlyException($"无效顶级会签节点编号,wfId: {WorkflowId}"); return IsCountersignEndStep && CountersignStartStepId == topCountersignStepId; } //public WorkflowStepHandler? // FindActualHandler(ICollection roles, string? userId = null, string? orgId = null) => // StepHandlers.FirstOrDefault(d => d.IsHandler(roles, userId, orgId)); //public WorkflowStepHandler? GetActualHandler() => // StepHandlers.FirstOrDefault(d => d.IsActualHandler); public FlowStepHandler GetWorkflowStepHandler() { switch (FlowAssignType) { case EFlowAssignType.Org: return new FlowStepHandler { Key = HandlerOrgId, Value = HandlerOrgName, OrgId = HandlerOrgId, OrgName = HandlerOrgName }; case EFlowAssignType.User: return new FlowStepHandler { Key = HandlerId, Value = HandlerName, UserId = HandlerId, Username = HandlerName, OrgId = HandlerOrgId, OrgName = HandlerOrgName }; case EFlowAssignType.Role: return new FlowStepHandler { Key = RoleId, Value = RoleName, RoleId = RoleId, RoleName = RoleName, }; default: throw new ArgumentOutOfRangeException(); } } public bool IsCanHandle(string userId, string orgId, string[] roleIds) { if(Status is EWorkflowStepStatus.Handled) return false; return FlowAssignType switch { EFlowAssignType.Org => !string.IsNullOrEmpty(HandlerOrgId) && HandlerOrgId == orgId, EFlowAssignType.User => !string.IsNullOrEmpty(HandlerId) && HandlerId == userId, EFlowAssignType.Role => !string.IsNullOrEmpty(RoleId) && roleIds.Contains(RoleId), _ => throw new ArgumentOutOfRangeException() }; } #endregion } /* 获取开始节点下一步待选节点: 是否属于多次实例化配置(dynamic动态实例化配置:结合办理人动态生成待办节点) t:无需检查是否到结束标识,所以按配置的重复实例化策略结合当前操作人生成待办节点,如:生成x级部门办理,下一接口再选具体部门 f:开始节点配置的下一节点集合 获取开始节点所选下一步节点的具体参数: 是否属于多次实例化配置 t:所选x级部门返回对应办理对象集合(具体部门) f:按模板配置返回办理对象集合 获取待办节点下一步待选节点: 是否属于多次实例化配置(无需检查definetion,直接找到当前待办节点获取参数(需要的参数冗余至待办节点上)) t:检查是否到结束标识(检查当前办理节点的办理对象与结束标识(orglevel:int)是否一致) t:返回配置的下一节点(看作单次实例化,当前节点已办完)//definitionId,stepCodes,按配置走 f:按配置的重复实例化策略结合当前操作人,生成如:{x:X级部门办理},{0:中心办理},最高级最多只能到中心,按动态策略走,动态策略枚举 是否处于会签中 t:按会签策略的下一级 + 上一级(isCSEnd会签汇总节点标记),并对上一级选项打上标记,如:{x:X级部门办理},{0:中心办理},按动态策略走,动态策略枚举 f:按照definition(按配置走) 返回当前节点的配置下一步 获取下一步的具体参数: 检查模式 按动态策略:依据当前操作人、动态类型枚举 查询对应待选部门 按配置策略:原有实现方案 start: check配置是否允许当前用户发起 next: (nextStepCode/x, userId[]/orgId[],dto.other) check该不该当前用户办(handlers,all不需要check) 办理当前节点 创建后面节点 是否动态实例化 t:检查是否到结束标识(参数orgId==mark?) t:(参数时stepcode)按配置创建 f:(参数是x级部门)按动态实例化策略创建 是否处于会签中 t: 是否返回上一级汇总 (isCSEnd) t: 1.update上一级的会签完成情况[] 2.如果会签全完成,创建新的待办汇总节点(IsCountersignSummaryStep = true)?更新发起节点状态?thk f: 创建新的下一步节点 */