WorkflowController.cs 24 KB

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