VberWorkflowManager.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. using Abp;
  2. using Abp.Dependency;
  3. using Abp.Domain.Repositories;
  4. using Abp.Domain.Services;
  5. using Abp.Domain.Uow;
  6. using Abp.Json;
  7. using Abp.UI;
  8. using System.Collections.Generic;
  9. using System.Linq;
  10. using System.Threading.Tasks;
  11. using VberZero.Workflow.DesignInfo;
  12. using VberZero.Workflow.StepBodies;
  13. using WorkflowCore.Interface;
  14. using WorkflowCore.Models;
  15. using WorkflowCore.Models.DefinitionStorage.v1;
  16. using WorkflowCore.Services.DefinitionStorage;
  17. namespace VberZero.Workflow;
  18. public class VberWorkflowManager : DomainService, IVberWorkflowManager, ITransientDependency
  19. {
  20. protected readonly WorkflowStepBodyManager _workflowStepBodyManager;
  21. protected IWorkflowHost _workflowHost;
  22. protected readonly IWorkflowController _workflowService;
  23. protected readonly IWorkflowRegistry _registry;
  24. public IVberPersistenceProvider PersistenceProvider { get; }
  25. protected readonly ISearchIndex _searchService;
  26. protected readonly IDefinitionLoader _definitionLoader;
  27. protected readonly IRepository<WorkflowDefinitionInfo, string> _workflowDefinitionRepository;
  28. protected IReadOnlyCollection<VberWorkflowStepBody> _stepBodies;
  29. public IQueryable<WorkflowDefinitionInfo> WorkflowDefinitions => _workflowDefinitionRepository.GetAll();
  30. public VberWorkflowManager(WorkflowStepBodyManager workflowStepBodyManager, IWorkflowHost workflowHost, IWorkflowController workflowService, IWorkflowRegistry registry, IVberPersistenceProvider workflowStore, ISearchIndex searchService, IDefinitionLoader definitionLoader, IRepository<WorkflowDefinitionInfo, string> workflowDefinitionRepository
  31. )
  32. {
  33. _workflowStepBodyManager = workflowStepBodyManager;
  34. _workflowHost = workflowHost;
  35. _workflowService = workflowService;
  36. _registry = registry;
  37. PersistenceProvider = workflowStore;
  38. _searchService = searchService;
  39. _definitionLoader = definitionLoader;
  40. _workflowDefinitionRepository = workflowDefinitionRepository;
  41. _stepBodies = _workflowStepBodyManager.GetAllStepBodies();
  42. }
  43. /// <summary>
  44. /// 终止流程
  45. /// </summary>
  46. /// <param name="workflowId"></param>
  47. /// <returns></returns>
  48. public virtual async Task<bool> TerminateWorkflow(string workflowId)
  49. {
  50. return await _workflowService.TerminateWorkflow(workflowId);
  51. }
  52. public virtual WorkflowDefinition GetDefinition(string workflowId, int? version = null)
  53. {
  54. return _registry.GetDefinition(workflowId, version);
  55. }
  56. /// <summary>
  57. /// 初始化注册流程
  58. /// </summary>
  59. internal void Initialize()
  60. {
  61. using (UnitOfWorkManager.Begin())
  62. {
  63. using (UnitOfWorkManager.Current.DisableFilter(AbpDataFilters.MayHaveTenant))
  64. {
  65. var definitions = WorkflowDefinitions.ToList();
  66. foreach (var workflow in definitions)
  67. {
  68. LoadDefinition(workflow);
  69. }
  70. }
  71. }
  72. }
  73. /// <summary>
  74. ///
  75. /// </summary>
  76. /// <returns></returns>
  77. public virtual IEnumerable<VberWorkflowStepBody> GetAllStepBodies()
  78. {
  79. return _stepBodies;
  80. }
  81. public virtual async Task PublishEventAsync(string eventName, string eventKey, object eventData)
  82. {
  83. await _workflowHost.PublishEvent(eventName, eventKey, eventData);
  84. }
  85. /// <summary>
  86. /// 创建流程
  87. /// </summary>
  88. /// <param name="entity"></param>
  89. /// <returns></returns>
  90. [UnitOfWork]
  91. public virtual async Task CreateAsync(WorkflowDefinitionInfo entity)
  92. {
  93. LoadDefinition(entity);
  94. await _workflowDefinitionRepository.InsertAsync(entity);
  95. }
  96. /// <summary>
  97. /// 删除指定版本
  98. /// </summary>
  99. /// <param name="id"></param>
  100. /// <param name="version"></param>
  101. /// <returns></returns>
  102. [UnitOfWork]
  103. public virtual async Task DeleteAsync(string id, int version)
  104. {
  105. var entity = await _workflowDefinitionRepository.FirstOrDefaultAsync(a => a.Id == id && a.Version == version);
  106. var all = await PersistenceProvider.GetAllRunnablePersistedWorkflow(entity.Id, entity.Version);
  107. if (all.Any())
  108. {
  109. throw new UserFriendlyException($"编号:{entity.Id},版本:{entity.Version}的流程无法删除!还有没有执行完的流程!");
  110. }
  111. if (_registry.IsRegistered(entity.Id, entity.Version))
  112. {
  113. _registry.DeregisterWorkflow(entity.Id, entity.Version);
  114. }
  115. await _workflowDefinitionRepository.DeleteAsync(entity);
  116. }
  117. /// <summary>
  118. /// 删除全部版本
  119. /// </summary>
  120. /// <param name="id"></param>
  121. /// <returns></returns>
  122. [UnitOfWork]
  123. public virtual async Task DeleteAsync(string id)
  124. {
  125. var entities = await _workflowDefinitionRepository.GetAllListAsync(a => a.Id == id);
  126. foreach (var entity in entities)
  127. {
  128. await DeleteAsync(entity.Id, entity.Version);
  129. }
  130. }
  131. /// <summary>
  132. /// 更新
  133. /// </summary>
  134. /// <param name="entity"></param>
  135. /// <returns></returns>
  136. [UnitOfWork]
  137. public virtual async Task UpdateAsync(WorkflowDefinitionInfo entity)
  138. {
  139. if (_registry.IsRegistered(entity.Id, entity.Version))
  140. {
  141. _registry.DeregisterWorkflow(entity.Id, entity.Version);
  142. }
  143. LoadDefinition(entity);
  144. await _workflowDefinitionRepository.UpdateAsync(entity);
  145. }
  146. /// <summary>
  147. /// 启动工作流
  148. /// </summary>
  149. /// <returns></returns>
  150. public virtual async Task<string> StartWorkflow(string id, int version, Dictionary<string, object> inputs, string reference = null)
  151. {
  152. if (!_registry.IsRegistered(id, version))
  153. {
  154. throw new UserFriendlyException("工作流未定义!");
  155. }
  156. return await _workflowHost.StartWorkflow(id, version, inputs, reference);
  157. }
  158. /// <summary>
  159. /// 注册工作流
  160. /// </summary>
  161. /// <param name="input"></param>
  162. /// <returns></returns>
  163. internal WorkflowDefinition LoadDefinition(WorkflowDefinitionInfo input)
  164. {
  165. if (_registry.IsRegistered(input.Id, input.Version))
  166. {
  167. throw new AbpException($"工作流[{input.Id}]已定义 ");
  168. }
  169. var source = new DefinitionSourceV1
  170. {
  171. Id = input.Id,
  172. Version = input.Version,
  173. Description = input.Title,
  174. DataType = $"{typeof(Dictionary<string, object>).FullName}, {typeof(Dictionary<string, object>).Assembly.FullName}"
  175. };
  176. BuildWorkflow(input.Nodes, source, _stepBodies, input.Nodes.First(u => u.Key.ToLower().StartsWith("start")));
  177. var json = source.ToJsonString();
  178. Logger.DebugFormat("Workflow Json:{0}", json);
  179. var def = _definitionLoader.LoadDefinition(json, Deserializers.Json);
  180. return def;
  181. }
  182. protected virtual void BuildWorkflow(IEnumerable<WorkflowNode> allNodes, DefinitionSourceV1 source, IEnumerable<VberWorkflowStepBody> stepBodies, WorkflowNode node)
  183. {
  184. if (source.Steps.Any(u => u.Id == node.Key))
  185. {
  186. return;
  187. }
  188. var stepSource = new StepSourceV1
  189. {
  190. Id = node.Key,
  191. Name = node.Key
  192. };
  193. VberWorkflowStepBody stepBody = stepBodies.FirstOrDefault(u => node.StepBody != null && u.Name == node.StepBody.Name) ?? new VberWorkflowStepBody() { StepBodyType = typeof(NullStepBody) };
  194. stepSource.StepType = $"{stepBody.StepBodyType.FullName}, {stepBody.StepBodyType.Assembly.FullName}";
  195. foreach (var input in stepBody.Inputs)
  196. {
  197. var value = input.Value.Value;
  198. var key = FirstToLower(input.Key);
  199. if (node.StepBody.Inputs.ContainsKey(key))
  200. {
  201. value = node.StepBody.Inputs[key].Value;
  202. }
  203. if (!(value is IDictionary<string, object> || value is IDictionary<object, object>))
  204. {
  205. value = $"\"{value}\"";
  206. }
  207. stepSource.Inputs.TryAdd(input.Key, value);
  208. }
  209. source.Steps.Add(stepSource);
  210. BuildBranching(allNodes, source, stepSource, stepBodies, node.NextNodes);
  211. }
  212. protected virtual void BuildBranching(IEnumerable<WorkflowNode> allNodes, DefinitionSourceV1 source, StepSourceV1 stepSource, IEnumerable<VberWorkflowStepBody> stepBodies, IEnumerable<WorkflowConditionNode> nodes)
  213. {
  214. foreach (var nextNode in nodes)
  215. {
  216. var node = allNodes.First(u => u.Key == nextNode.NodeId);
  217. stepSource.SelectNextStep[nextNode.NodeId] = "1==1";
  218. if (nextNode.Conditions.Any())
  219. {
  220. List<string> expList = new List<string>();
  221. foreach (var cond in nextNode.Conditions)
  222. {
  223. if (cond.Value is string && (!decimal.TryParse(cond.Value.ToString(), out _)))
  224. {
  225. if (cond.Operator != "==" && cond.Operator != "!=")
  226. {
  227. throw new AbpException($" if {cond.Field} is type of 'String', the Operator must be \"==\" or \"!=\"");
  228. }
  229. expList.Add($"data[\"{cond.Field}\"].ToString() {cond.Operator} \"{cond.Value}\"");
  230. continue;
  231. }
  232. expList.Add($"decimal.Parse(data[\"{cond.Field}\"].ToString()) {cond.Operator} {cond.Value}");
  233. }
  234. stepSource.SelectNextStep[nextNode.NodeId] = string.Join(" && ", expList);
  235. }
  236. BuildWorkflow(allNodes, source, stepBodies, node);
  237. }
  238. }
  239. private string FirstToLower(string str)
  240. {
  241. return str.Substring(0, 1).ToLower() + str.Substring(1);
  242. }
  243. }