WorkflowController.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. using Hotline.Application.FlowEngine;
  2. using Hotline.FlowEngine.Definitions;
  3. using Hotline.FlowEngine.Workflows;
  4. using Hotline.Identity.Roles;
  5. using Hotline.Permissions;
  6. using Hotline.Repository.SqlSugar.Extensions;
  7. using Hotline.Settings;
  8. using Hotline.Share.Dtos;
  9. using Hotline.Share.Dtos.FlowEngine;
  10. using Hotline.Share.Enums.FlowEngine;
  11. using Hotline.Users;
  12. using MapsterMapper;
  13. using Microsoft.AspNetCore.Mvc;
  14. using SqlSugar;
  15. using Hotline.FlowEngine.WfModules;
  16. using Microsoft.AspNetCore.Authorization;
  17. using XF.Domain.Authentications;
  18. using XF.Domain.Exceptions;
  19. using XF.Utility.EnumExtensions;
  20. using XF.Domain.Repository;
  21. namespace Hotline.Api.Controllers;
  22. /// <summary>
  23. /// 工作流管理
  24. /// </summary>
  25. public class WorkflowController : BaseController
  26. {
  27. private readonly IDefinitionDomainService _definitionDomainService;
  28. private readonly IRepository<Definition> _definitionRepository;
  29. private readonly IWorkflowApplication _workflowApplication;
  30. private readonly IWorkflowDomainService _workflowDomainService;
  31. private readonly IWorkflowRepository _workflowRepository;
  32. private readonly IRepository<User> _userRepository;
  33. private readonly ISystemOrganizeRepository _organizeRepository;
  34. private readonly IRepository<Role> _roleRepository;
  35. private readonly ISystemDomainService _systemDomainService;
  36. private readonly IWfModuleDomainService _wfModuleDomainService;
  37. private readonly IRepository<WorkflowModule> _wfModuleRepository;
  38. private readonly ISessionContext _sessionContext;
  39. private readonly IMapper _mapper;
  40. public WorkflowController(
  41. IDefinitionDomainService definitionDomainService,
  42. IRepository<Definition> definitionRepository,
  43. IWorkflowApplication workflowApplication,
  44. IWorkflowDomainService workflowDomainService,
  45. IWorkflowRepository workflowRepository,
  46. IRepository<User> userRepository,
  47. ISystemOrganizeRepository organizeRepository,
  48. IRepository<Role> roleRepository,
  49. ISystemDomainService systemDomainService,
  50. IWfModuleDomainService wfModuleDomainService,
  51. IRepository<WorkflowModule> wfModuleRepository,
  52. ISessionContext sessionContext,
  53. IMapper mapper)
  54. {
  55. _definitionDomainService = definitionDomainService;
  56. _definitionRepository = definitionRepository;
  57. _workflowApplication = workflowApplication;
  58. _workflowDomainService = workflowDomainService;
  59. _workflowRepository = workflowRepository;
  60. _userRepository = userRepository;
  61. _organizeRepository = organizeRepository;
  62. _roleRepository = roleRepository;
  63. _systemDomainService = systemDomainService;
  64. _wfModuleDomainService = wfModuleDomainService;
  65. _wfModuleRepository = wfModuleRepository;
  66. _sessionContext = sessionContext;
  67. _mapper = mapper;
  68. }
  69. /// <summary>
  70. /// 分页查询最新版本号的模板
  71. /// </summary>
  72. /// <param name="dto"></param>
  73. /// <returns></returns>
  74. [HttpGet("definition/latest")]
  75. public async Task<PagedDto<DefinitionDto>> QueryDefinitionLatest([FromQuery] QueryDefinitionDto dto)
  76. {
  77. var query2 = await _definitionRepository.Queryable()
  78. .WhereIF(dto.Status.HasValue, d => d.Status == dto.Status)
  79. .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Code.Contains(dto.Keyword) || d.Name.Contains(dto.Keyword))
  80. .Select(d => new { i = SqlFunc.RowNumber($"{d.Version} desc", d.Code), d })
  81. .MergeTable()
  82. .Where(d => d.i == 1)
  83. .ToListAsync();
  84. var items = query2.Select(d => d.d).ToList();
  85. return new PagedDto<DefinitionDto>(query2.Count, _mapper.Map<IReadOnlyList<DefinitionDto>>(items));
  86. }
  87. /// <summary>
  88. /// 分页查询流程模板
  89. /// </summary>
  90. /// <param name="dto"></param>
  91. /// <returns></returns>
  92. [Permission(EPermission.FlowDefinitionQuery)]
  93. [HttpGet("definition")]
  94. public async Task<PagedDto<DefinitionDto>> QueryDefinitions([FromQuery] QueryDefinitionDto dto)
  95. {
  96. #region old version:只查询草稿、禁用以及已启用模板的最新版本
  97. ////todo 数据量大需重构
  98. //var query1 = await _definitionRepository.Queryable()
  99. // .Where(d => d.Status == EDefinitionStatus.Temporary)
  100. // .ToListAsync();
  101. //var query2 = await _definitionRepository.Queryable()
  102. // .Where(d => d.Status != EDefinitionStatus.Temporary)
  103. // .Select(d => new { i = SqlFunc.RowNumber($"{d.Version} desc", d.Code), d })
  104. // .MergeTable()
  105. // .Where(d => d.i == 1)
  106. // .ToListAsync();
  107. //var query = query1.Union(query2.Select(d => d.d));
  108. //var total = query.Count();
  109. //var items = query
  110. // .OrderBy(d => d.Status)
  111. // .ThenByDescending(d => d.CreationTime)
  112. // .Skip(dto.Skip())
  113. // .Take(dto.PageSize)
  114. // .ToList();
  115. #endregion
  116. var (total, items) = await _definitionRepository.Queryable()
  117. .WhereIF(dto.Status.HasValue, d => d.Status == dto.Status)
  118. .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Code.Contains(dto.Keyword!) || d.Name.Contains(dto.Keyword!))
  119. .OrderBy(d => d.Status)
  120. .OrderBy(d => d.Code)
  121. .OrderByDescending(d => d.Version)
  122. .ToPagedListAsync(dto, HttpContext.RequestAborted);
  123. return new PagedDto<DefinitionDto>(total, _mapper.Map<IReadOnlyList<DefinitionDto>>(items));
  124. }
  125. /// <summary>
  126. /// 查询流程模板
  127. /// </summary>
  128. /// <param name="id"></param>
  129. /// <returns></returns>
  130. [Permission(EPermission.GetFlow)]
  131. [HttpGet("definition/{id}")]
  132. public async Task<DefinitionDto> GetDefinition(string id)
  133. {
  134. var definition = await _definitionRepository.GetAsync(id, HttpContext.RequestAborted);
  135. if (definition == null) return new();
  136. return _mapper.Map<DefinitionDto>(definition);
  137. }
  138. /// <summary>
  139. /// 新增流程模板草稿
  140. /// </summary>
  141. /// <param name="dto"></param>
  142. /// <returns></returns>
  143. [Permission(EPermission.FlowDefinitionAdd)]
  144. [HttpPost("definition")]
  145. public async Task<string> AddDefinition([FromBody] AddDefinitionDto dto)
  146. {
  147. return await _definitionDomainService.AddAsync(dto, HttpContext.RequestAborted);
  148. }
  149. /// <summary>
  150. /// 更新流程模板草稿
  151. /// </summary>
  152. /// <param name="dto"></param>
  153. /// <returns></returns>
  154. [Permission(EPermission.FlowDefinitionUpdate)]
  155. [HttpPut("definition")]
  156. public async Task UpdateDefinition([FromBody] UpdateDefinitionDto dto)
  157. {
  158. var definition = await _definitionRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
  159. if (definition == null)
  160. throw UserFriendlyException.SameMessage("无效模板编号");
  161. if (definition.Status == EDefinitionStatus.Temporary)
  162. {
  163. _mapper.Map(dto, definition);
  164. await _definitionRepository.UpdateAsync(definition, HttpContext.RequestAborted);
  165. }
  166. else
  167. {
  168. var newDefinition = _mapper.Map<Definition>(dto);
  169. await _definitionRepository.AddAsync(newDefinition, HttpContext.RequestAborted);
  170. }
  171. }
  172. /// <summary>
  173. /// 删除草稿
  174. /// </summary>
  175. /// <param name="id"></param>
  176. /// <returns></returns>
  177. /// <exception cref="UserFriendlyException"></exception>
  178. [Permission(EPermission.FlowDefinitionRemove)]
  179. [HttpDelete("definition/{id}")]
  180. public async Task RemoveDefinition(string id)
  181. {
  182. var definition = await _definitionRepository.GetAsync(id, HttpContext.RequestAborted);
  183. if (definition == null) return;
  184. if (definition.Status != EDefinitionStatus.Temporary)
  185. throw new UserFriendlyException("已发布模板不能删除");
  186. await _definitionRepository.RemoveAsync(id, false, HttpContext.RequestAborted);
  187. }
  188. /// <summary>
  189. /// 发布(列表操作)
  190. /// </summary>
  191. /// <returns></returns>
  192. [Permission(EPermission.FlowDefinitionPublish)]
  193. [HttpPost("definition/{id}/publish")]
  194. public async Task Publish(string id)
  195. {
  196. await _definitionDomainService.PublishAsync(id, HttpContext.RequestAborted);
  197. }
  198. /// <summary>
  199. /// 发布(保存并发布)
  200. /// </summary>
  201. /// <returns></returns>
  202. [Obsolete]
  203. [Permission(EPermission.FlowDefinitionPublish)]
  204. [HttpPost("definition/publish")]
  205. public async Task Publish([FromBody] AddDefinitionDto dto)
  206. {
  207. await _definitionDomainService.PublishAsync(dto, HttpContext.RequestAborted);
  208. }
  209. /// <summary>
  210. /// 分页查询流程
  211. /// </summary>
  212. /// <param name="dto"></param>
  213. /// <returns></returns>
  214. [Permission(EPermission.FlowQuery)]
  215. [HttpGet]
  216. public async Task<PagedDto<WorkflowDto>> QueryPaged([FromQuery] QueryWorkflowPagedDto dto)
  217. {
  218. var (total, items) = await _workflowRepository.Queryable()
  219. .WhereIF(!string.IsNullOrEmpty(dto.ModuleCode), d => d.ModuleCode == dto.ModuleCode)
  220. .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Id.Contains(dto.Keyword!) || d.Title.Contains(dto.Keyword!))
  221. .OrderByDescending(d => d.CreationTime)
  222. .ToPagedListAsync(dto, HttpContext.RequestAborted);
  223. return new PagedDto<WorkflowDto>(total, _mapper.Map<IReadOnlyList<WorkflowDto>>(items));
  224. }
  225. /// <summary>
  226. /// 查询流程办理下一步可选节点
  227. /// </summary>
  228. [HttpGet("{workflowId}/nextsteps")]
  229. public async Task<DefinedStepDto> GetNextStepDefine(string workflowId)
  230. {
  231. var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, true, true,
  232. cancellationToken: HttpContext.RequestAborted);
  233. var current = _workflowDomainService.FindCurrentStep(workflow);
  234. var nextStepDefines = workflow.Definition.FindStepDefines(current.StepBox.NextSteps.Select(d => d.Code));
  235. if (current.StepBox.PathPolicy is not EPathPolicy.None && current.StepBox.NextSteps.Count > 1)
  236. _workflowDomainService.NextStepDefineFilter(current.StepBox.PathPolicy, nextStepDefines);
  237. return new DefinedStepDto
  238. {
  239. Id = workflow.DefinitionId,
  240. Steps = _mapper.Map<IReadOnlyList<StepBasicDto>>(nextStepDefines),//nextStepDefines.Select(d => new KeyValuePair<string, string>(d.Code, d.Name)).ToList(),
  241. ExpiredTime = workflow.ExpiredTime,
  242. Components = current.StepBox.Components,
  243. };
  244. }
  245. /// <summary>
  246. /// 查询流程下一节点待选配置
  247. /// </summary>
  248. [HttpGet("step-options")]
  249. public async Task<NextStepOptionDto> GetNextStepOptions([FromQuery] QueryNextStepOptionDto dto)
  250. {
  251. var definition = await _definitionRepository.GetAsync(dto.DefineId, HttpContext.RequestAborted);
  252. if (definition == null)
  253. throw new UserFriendlyException("无效DefineId");
  254. var defineStep = definition.FindStepDefine(dto.Code);
  255. if (defineStep is null)
  256. throw UserFriendlyException.SameMessage("未查询到对应节点配置");
  257. return await _workflowApplication.GetNextStepOptionsAsync(defineStep, HttpContext.RequestAborted);
  258. }
  259. /// <summary>
  260. /// 办理节点
  261. /// </summary>
  262. [Permission(EPermission.FlowNext)]
  263. [HttpPost("next")]
  264. public async Task Next([FromBody] NextWorkflowDto dto)
  265. {
  266. await _workflowApplication.NextAsync(dto, HttpContext.RequestAborted);
  267. }
  268. /// <summary>
  269. /// 退回(返回前一节点)
  270. /// </summary>
  271. [Permission(EPermission.FlowPrevious)]
  272. [HttpPost("previous")]
  273. public async Task Previous([FromBody] PreviousWorkflowDto dto)
  274. {
  275. var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withSteps: true,
  276. cancellationToken: HttpContext.RequestAborted);
  277. await _workflowDomainService.PreviousAsync(workflow, dto, HttpContext.RequestAborted);
  278. }
  279. /// <summary>
  280. /// 获取撤回可选节点
  281. /// </summary>
  282. /// <param name="workflowId"></param>
  283. /// <returns></returns>
  284. [Permission(EPermission.FlowRecall)]
  285. [HttpGet("{workflowId}/recall")]
  286. public async Task<DefinedStepDto> GetRecallSteps(string workflowId)
  287. {
  288. var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, true, true, cancellationToken: HttpContext.RequestAborted);
  289. var stepCodes = workflow.StepBoxes.Where(d => d.StepType != EStepType.Start && d.StepType != EStepType.End)
  290. .Select(d => d.Code).ToList();
  291. var nextStepDefines = workflow.Definition.FindStepDefines(stepCodes);
  292. return new DefinedStepDto
  293. {
  294. Id = workflow.DefinitionId,
  295. Steps = _mapper.Map<IReadOnlyList<StepBasicDto>>(nextStepDefines)//nextStepDefines.Select(d => new KeyValuePair<string, string>(d.Code, d.Name)).ToList()
  296. };
  297. }
  298. /// <summary>
  299. /// 撤回至任意节点
  300. /// </summary>
  301. /// <param name="dto"></param>
  302. /// <returns></returns>
  303. [Permission(EPermission.FlowRecall)]
  304. [HttpPost("recall")]
  305. public async Task Recall([FromBody] RecallDto dto)
  306. {
  307. await _workflowApplication.RecallAsync(dto, HttpContext.RequestAborted);
  308. }
  309. /// <summary>
  310. /// 获取跳转可选节点
  311. /// </summary>
  312. /// <param name="workflowId"></param>
  313. /// <returns></returns>
  314. [HttpGet("{workflowId}/jump")]
  315. public async Task<DefinedStepDto> GetJumpSteps(string workflowId)
  316. {
  317. var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, true, true, cancellationToken: HttpContext.RequestAborted);
  318. var steps = workflow.Definition.Steps.Where(d => d.StepType != EStepType.Start && d.StepType != EStepType.End).ToList();
  319. var nextStepDefines = workflow.Definition.FindStepDefines(steps.Select(d => d.Code));
  320. return new DefinedStepDto
  321. {
  322. Id = workflow.DefinitionId,
  323. Steps = _mapper.Map<IReadOnlyList<StepBasicDto>>(nextStepDefines)//nextStepDefines.Select(d => new KeyValuePair<string, string>(d.Code, d.Name)).ToList()
  324. };
  325. }
  326. /// <summary>
  327. /// 跳转至任意节点
  328. /// </summary>
  329. /// <param name="dto"></param>
  330. /// <returns></returns>
  331. [Permission(EPermission.FlowJump)]
  332. [HttpPost("jump")]
  333. public async Task Jump([FromBody] RecallDto dto)
  334. {
  335. await _workflowApplication.JumpAsync(dto, HttpContext.RequestAborted);
  336. }
  337. /// <summary>
  338. /// 获取重办可选节点
  339. /// </summary>
  340. /// <param name="workflowId"></param>
  341. /// <returns></returns>
  342. [HttpGet("{workflowId}/redo")]
  343. public async Task<DefinedStepDto> GetRedoSteps(string workflowId)
  344. {
  345. var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, true, true, cancellationToken: HttpContext.RequestAborted);
  346. var steps = workflow.Definition.Steps.Where(d => d.StepType is EStepType.Normal && d.IsOrg()).ToList();
  347. var nextStepDefines = workflow.Definition.FindStepDefines(steps.Select(d => d.Code));
  348. return new DefinedStepDto
  349. {
  350. Id = workflow.DefinitionId,
  351. Steps = _mapper.Map<IReadOnlyList<StepBasicDto>>(nextStepDefines)//nextStepDefines.Select(d => new KeyValuePair<string, string>(d.Code, d.Name)).ToList()
  352. };
  353. }
  354. /// <summary>
  355. /// 终止流程
  356. /// </summary>
  357. [Permission(EPermission.FlowTerminate)]
  358. [HttpPost("terminate")]
  359. public async Task Terminate([FromBody] TerminateDto dto)
  360. {
  361. await _workflowDomainService.TerminateAsync(dto, HttpContext.RequestAborted);
  362. }
  363. /// <summary>
  364. /// 撤销流程
  365. /// </summary>
  366. [HttpPost("cancel")]
  367. public async Task Cancel([FromBody] CancelDto dto)
  368. {
  369. await _workflowDomainService.CancelAsync(dto, HttpContext.RequestAborted);
  370. }
  371. /// <summary>
  372. /// 补充
  373. /// </summary>
  374. /// <param name="dto"></param>
  375. /// <returns></returns>
  376. [Permission(EPermission.FlowSupplement)]
  377. [HttpPost("supplement")]
  378. public async Task Supplement([FromBody] SupplementDto dto)
  379. {
  380. var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId);
  381. await _workflowDomainService.SupplementAsync(workflow, dto, HttpContext.RequestAborted);
  382. }
  383. /// <summary>
  384. /// 查询办理类型参数
  385. /// </summary>
  386. [HttpGet("handlerclassify/{handlerType}")]
  387. public async Task<List<KeyValuePair<string, string>>> GetHandlerClassifies(EHandlerType handlerType)
  388. {
  389. switch (handlerType)
  390. {
  391. case EHandlerType.Role:
  392. var roles = await _roleRepository.QueryAsync();
  393. return roles.Select(d => new KeyValuePair<string, string>(d.Name, d.DisplayName)).ToList();
  394. case EHandlerType.OrgLevel:
  395. var orgs1 = await _systemDomainService.QueryOrgLevelStringOptionsAsync(HttpContext.RequestAborted);
  396. return orgs1.ToList();
  397. case EHandlerType.OrgType:
  398. return EnumExts.GetDescriptions<EOrgType>().Select(d => new KeyValuePair<string, string>(d.Key.ToString(), d.Value)).ToList();
  399. case EHandlerType.AssignOrg:
  400. var orgs = await _organizeRepository.GetOrgJson();
  401. return orgs.Select(d => new KeyValuePair<string, string>(d.OrgCode, d.OrgName)).ToList();
  402. case EHandlerType.AssignUser:
  403. default:
  404. throw new ArgumentOutOfRangeException(nameof(handlerType), handlerType, null);
  405. }
  406. }
  407. /// <summary>
  408. /// 查询流程流转记录
  409. /// </summary>
  410. /// <param name="workflowId"></param>
  411. /// <returns></returns>
  412. [HttpGet("{workflowId}/traces")]
  413. public async Task<WorkflowDto> GetWorkflowTraces(string workflowId)
  414. {
  415. var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withTraces: true,
  416. cancellationToken: HttpContext.RequestAborted);
  417. workflow.Traces = workflow.Traces.Where(d => !string.IsNullOrEmpty(d.AcceptUserId)).ToList();
  418. return _mapper.Map<WorkflowDto>(workflow);
  419. }
  420. /// <summary>
  421. /// 查询被督办/催办部门
  422. /// </summary>
  423. /// <param name="workflowId"></param>
  424. /// <returns></returns>
  425. [HttpGet("{workflowId}/urge")]
  426. public async Task<IReadOnlyList<IdName>> GetUrgeOrgs(string workflowId)
  427. {
  428. var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, true, true, cancellationToken: HttpContext.RequestAborted);
  429. var stepBoxes = workflow.StepBoxes.Where(d => d.StepType != EStepType.Start && d.StepType != EStepType.End).ToList();
  430. var steps = stepBoxes.SelectMany(d => d.Steps);
  431. var orgs = new List<IdName>();
  432. foreach (var step in steps)
  433. {
  434. var orgCode = step.OrgCode ?? step.AcceptOrgCode;
  435. var orgName = step.OrgName ?? step.AcceptOrgName;
  436. if (string.IsNullOrEmpty(orgCode))
  437. {
  438. switch (step.HandlerType)
  439. {
  440. case EHandlerType.Role:
  441. case EHandlerType.AssignUser:
  442. //todo
  443. var users = await _userRepository.Queryable()
  444. .Includes(d => d.Organization)
  445. .Where(d => step.Handlers.Select(x => x.Id).Contains(d.Id))
  446. .ToListAsync(HttpContext.RequestAborted);
  447. orgs.AddRange(users.Select(d => new IdName(d.OrgCode, d.Organization.OrgName)));
  448. break;
  449. case EHandlerType.OrgLevel:
  450. case EHandlerType.OrgType:
  451. case EHandlerType.AssignOrg:
  452. orgs.AddRange(step.Handlers);
  453. break;
  454. default:
  455. throw new ArgumentOutOfRangeException();
  456. }
  457. }
  458. else
  459. {
  460. orgs.Add(new IdName(orgCode, orgName));
  461. }
  462. }
  463. return orgs.DistinctBy(d=>d.Id).ToList();
  464. }
  465. [HttpGet("base-data")]
  466. public async Task<dynamic> BaseData()
  467. {
  468. return new
  469. {
  470. ModuleOptions = WorkflowModuleConsts.AllModules.Select(d => new KeyValuePair<string, string>(d.Code, d.Name)),
  471. HandlerTypeOptions = EnumExts.GetDescriptions<EHandlerType>(),
  472. CountersignMode = EnumExts.GetDescriptions<ECountersignMode>().Where(d => d.Key != 1),
  473. BusinessPropertyOptions = EnumExts.GetDescriptions<EBusinessProperty>(),
  474. StepPropertiesOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.WorkflowStepComponent, HttpContext.RequestAborted),
  475. PathPolicyOptions = EnumExts.GetDescriptions<EPathPolicy>(),
  476. };
  477. }
  478. /// <summary>
  479. /// 持久化新增工作流业务
  480. /// </summary>
  481. /// <returns></returns>
  482. [AllowAnonymous]
  483. [HttpGet("wfmodule/persistence")]
  484. public async Task PersistenceWfModule()
  485. {
  486. await _wfModuleDomainService.PersistenceModulesAsync(HttpContext.RequestAborted);
  487. }
  488. /// <summary>
  489. /// 查询所有工作流模块
  490. /// </summary>
  491. /// <returns></returns>
  492. [HttpGet("wfmodules")]
  493. public async Task<IReadOnlyList<WorkflowModule>> QueryWfModules()
  494. {
  495. return await _wfModuleRepository.Queryable()
  496. .Includes(d => d.Definition)
  497. .ToListAsync();
  498. }
  499. /// <summary>
  500. /// 为工作流业务匹配或取消流程模板
  501. /// </summary>
  502. /// <param name="dto"></param>
  503. /// <returns></returns>
  504. [HttpPut("wfmodule/match")]
  505. public async Task MatchDefinition([FromBody] MatchDefinitionDto dto)
  506. {
  507. if (string.IsNullOrEmpty(dto.DefinitionId))
  508. {
  509. //取消当前已配置模板
  510. await _wfModuleDomainService.MatchDefinitionAsync(dto, HttpContext.RequestAborted);
  511. }
  512. else
  513. {
  514. var definition = await _definitionRepository.GetAsync(dto.DefinitionId);
  515. if (definition == null)
  516. throw UserFriendlyException.SameMessage("无效模板编号");
  517. if (definition.Status != EDefinitionStatus.Enable)
  518. throw UserFriendlyException.SameMessage("该模板未发布");
  519. await _wfModuleDomainService.MatchDefinitionAsync(dto, HttpContext.RequestAborted);
  520. }
  521. }
  522. }