WorkflowStep.cs 8.5 KB

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