WorkflowController.cs 24 KB

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