WorkflowStep.cs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. using Hotline.File;
  2. using Hotline.Share.Dtos;
  3. using Hotline.Share.Dtos.FlowEngine;
  4. using Hotline.Share.Dtos.FlowEngine.Definition;
  5. using Hotline.Share.Dtos.FlowEngine.Workflow;
  6. using Hotline.Share.Enums.FlowEngine;
  7. using SqlSugar;
  8. using XF.Domain.Entities;
  9. using XF.Domain.Exceptions;
  10. namespace Hotline.FlowEngine.Workflows;
  11. public class WorkflowStep : StepBasicEntity
  12. {
  13. [Navigate(NavigateType.ManyToOne, nameof(WorkflowId))]
  14. public Workflow Workflow { get; set; }
  15. [Navigate(NavigateType.OneToOne, nameof(Id),
  16. nameof(Workflows.WorkflowTrace.StepId))]
  17. public WorkflowTrace WorkflowTrace { get; set; }
  18. //[Navigate(NavigateType.OneToMany, nameof(WorkflowStepHandler.WorkflowStepId))]
  19. //public List<WorkflowStepHandler> StepHandlers { get; set; }
  20. #region Method
  21. /// <summary>
  22. /// 是否处于会签流程中(不包含顶层发起会签节点)
  23. /// </summary>
  24. public bool IsInCountersign() => CountersignPosition != ECountersignPosition.None;
  25. ///// <summary>
  26. ///// 是否发起过会签
  27. ///// </summary>
  28. //public bool HasStartedCountersign() => !string.IsNullOrEmpty(StartCountersignId);
  29. ///// <summary>
  30. ///// 接办
  31. ///// </summary>
  32. //public void Accept(string userId, string? userName, string orgId, string? orgName, string? orgAreaCode,
  33. // string? orgAreaName)
  34. //{
  35. // AcceptorId = userId;
  36. // AcceptorName = userName;
  37. // AcceptorOrgId = orgId;
  38. // AcceptorOrgName = orgName;
  39. // AcceptorOrgAreaCode = orgAreaCode;
  40. // AcceptorOrgAreaName = orgAreaName;
  41. // AcceptTime = DateTime.Now;
  42. // Status = EWorkflowStepStatus.WaitForHandle;
  43. //}
  44. ///// <summary>
  45. ///// 节点办理完成
  46. ///// </summary>
  47. //public void Handle(
  48. // string userId, string? userName,
  49. // string orgId, string? orgName,
  50. // string? orgAreaCode, string? orgAreaName,
  51. // bool orgIsCenter, string opinion, string nextStepCode)
  52. //{
  53. // base.Handle(userId, userName, orgId, orgName, orgAreaCode, orgAreaName, orgIsCenter, opinion);
  54. // if (!IsInCountersign()
  55. // && InstanceMode is EInstanceMode.Config
  56. // && StepType is not EStepType.End)
  57. // {
  58. // var step = NextSteps.FirstOrDefault(d => d.Code == nextStepCode);
  59. // if (step != null)
  60. // step.Selected = true;
  61. // }
  62. //}
  63. /// <summary>
  64. /// 会签结束
  65. /// </summary>
  66. public void CountersignEnd() => IsStartedCountersignEnd = true;
  67. //public void CreateCountersignSteps(List<WorkflowStep> nextSteps) =>
  68. // CountersignSteps = nextSteps
  69. // .Select(d => new CountersignStep { StepId = d.Id })
  70. // .ToList();
  71. /// <summary>
  72. /// step设置为可接办状态
  73. /// </summary>
  74. public void SetAssigned() => Status = EWorkflowStepStatus.WaitForAccept;
  75. ///// <summary>
  76. ///// 依据当前节点获取下一节点会签状态
  77. ///// </summary>
  78. ///// <returns></returns>
  79. //public ECountersignPosition GetNextStepCountersignPosition() =>
  80. // IsStartCountersign
  81. // ? ECountersignPosition.Multi
  82. // : IsInCountersign()
  83. // ? ECountersignPosition.Single
  84. // : ECountersignPosition.None;
  85. public bool IsCenter() => BusinessType is EBusinessType.Seat or EBusinessType.Send;
  86. public bool IsOrg() => BusinessType is EBusinessType.Department;
  87. /// <summary>
  88. /// 重置节点,只清除办理痕迹(退回场景/依据会签开始节点复制会签汇总节点,将上一级节点重置等待重新办理)
  89. /// </summary>
  90. public void Reset()
  91. {
  92. HandleTime = null;
  93. AcceptorId = null;
  94. AcceptorName = null;
  95. AcceptorOrgId = null;
  96. AcceptorOrgName = null;
  97. AcceptorOrgAreaCode = null;
  98. AcceptorOrgAreaName = null;
  99. AcceptTime = null;
  100. IsStartCountersign = false;
  101. NextSteps.ForEach(d => d.Selected = false);
  102. }
  103. /// <summary>
  104. /// 重置办理参数
  105. /// </summary>
  106. public void ResetParameters()
  107. {
  108. NextHandlers = new();
  109. NextMainHandler = null;
  110. NextStepCode = null;
  111. BackToCountersignEnd = false;
  112. IsSms = false;
  113. Opinion = null;
  114. FileJson = new();
  115. IsStartCountersign = false;
  116. }
  117. ///// <summary>
  118. ///// 发起会签节点发起的会签是否全都办理完成
  119. ///// </summary>
  120. ///// <returns></returns>
  121. //public bool StartedCountersignHasAllHandled()
  122. //{
  123. // //if (!HasStartedCountersign())
  124. // // throw new UserFriendlyException("该节点未发起会签");
  125. // //outer属于特殊会签
  126. // return CountersignSteps.All(d => d.Completed);
  127. //}
  128. /// <summary>
  129. /// 动态实例化节点是否应该终止
  130. /// </summary>
  131. /// <returns></returns>
  132. public bool DynamicShouldTerminal() => !string.IsNullOrEmpty(NextStepCode) && TerminalDynamicMark == NextStepCode;
  133. /// <summary>
  134. /// 是否是顶级会签汇总节点
  135. /// </summary>
  136. public bool IsTopCountersignEndStep(string? topCountersignStepId)
  137. {
  138. // if (string.IsNullOrEmpty(topCountersignStepId))
  139. // throw new UserFriendlyException($"无效顶级会签节点编号,wfId: {WorkflowId}");
  140. return IsCountersignEndStep
  141. && !string.IsNullOrEmpty(topCountersignStepId)
  142. && CountersignStartStepId == topCountersignStepId;
  143. }
  144. //public WorkflowStepHandler?
  145. // FindActualHandler(ICollection<string> roles, string? userId = null, string? orgId = null) =>
  146. // StepHandlers.FirstOrDefault(d => d.IsHandler(roles, userId, orgId));
  147. //public WorkflowStepHandler? GetActualHandler() =>
  148. // StepHandlers.FirstOrDefault(d => d.IsActualHandler);
  149. public bool IsCanHandle(string userId, string orgId, string[] roleIds)
  150. {
  151. if(Status is EWorkflowStepStatus.Handled) return false;
  152. return FlowAssignType switch
  153. {
  154. EFlowAssignType.Org => !string.IsNullOrEmpty(HandlerOrgId) && HandlerOrgId == orgId,
  155. EFlowAssignType.User => !string.IsNullOrEmpty(HandlerId) && HandlerId == userId,
  156. EFlowAssignType.Role => !string.IsNullOrEmpty(RoleId) && roleIds.Contains(RoleId),
  157. EFlowAssignType.OrgAndRole => !string.IsNullOrEmpty(HandlerOrgId) && HandlerOrgId == orgId && !string.IsNullOrEmpty(RoleId) && roleIds.Contains(RoleId),
  158. _ => throw new ArgumentOutOfRangeException()
  159. };
  160. }
  161. #endregion
  162. }
  163. /*
  164. 获取开始节点下一步待选节点:
  165. 是否属于多次实例化配置(dynamic动态实例化配置:结合办理人动态生成待办节点)
  166. t:无需检查是否到结束标识,所以按配置的重复实例化策略结合当前操作人生成待办节点,如:生成x级部门办理,下一接口再选具体部门
  167. f:开始节点配置的下一节点集合
  168. 获取开始节点所选下一步节点的具体参数:
  169. 是否属于多次实例化配置
  170. t:所选x级部门返回对应办理对象集合(具体部门)
  171. f:按模板配置返回办理对象集合
  172. 获取待办节点下一步待选节点:
  173. 是否属于多次实例化配置(无需检查definetion,直接找到当前待办节点获取参数(需要的参数冗余至待办节点上))
  174. t:检查是否到结束标识(检查当前办理节点的办理对象与结束标识(orglevel:int)是否一致)
  175. t:返回配置的下一节点(看作单次实例化,当前节点已办完)//definitionId,stepCodes,按配置走
  176. f:按配置的重复实例化策略结合当前操作人,生成如:{x:X级部门办理},{0:中心办理},最高级最多只能到中心,按动态策略走,动态策略枚举
  177. 是否处于会签中
  178. t:按会签策略的下一级 + 上一级(isCSEnd会签汇总节点标记),并对上一级选项打上标记,如:{x:X级部门办理},{0:中心办理},按动态策略走,动态策略枚举
  179. f:按照definition(按配置走)
  180. 返回当前节点的配置下一步
  181. 获取下一步的具体参数:
  182. 检查模式
  183. 按动态策略:依据当前操作人、动态类型枚举 查询对应待选部门
  184. 按配置策略:原有实现方案
  185. start:
  186. check配置是否允许当前用户发起
  187. next: (nextStepCode/x, userId[]/orgId[],dto.other)
  188. check该不该当前用户办(handlers,all不需要check)
  189. 办理当前节点
  190. 创建后面节点
  191. 是否动态实例化
  192. t:检查是否到结束标识(参数orgId==mark?)
  193. t:(参数时stepcode)按配置创建
  194. f:(参数是x级部门)按动态实例化策略创建
  195. 是否处于会签中
  196. t: 是否返回上一级汇总 (isCSEnd)
  197. t: 1.update上一级的会签完成情况[]
  198. 2.如果会签全完成,创建新的待办汇总节点(IsCountersignSummaryStep = true)?更新发起节点状态?thk
  199. f: 创建新的下一步节点
  200. */