WorkflowApplication.cs 88 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889
  1. using Hotline.Application.Contracts.Validators.FlowEngine;
  2. using Hotline.Caching.Interfaces;
  3. using Hotline.FlowEngine;
  4. using Hotline.FlowEngine.Definitions;
  5. using Hotline.FlowEngine.WorkflowModules;
  6. using Hotline.FlowEngine.Workflows;
  7. using Hotline.Identity.Accounts;
  8. using Hotline.Identity.Roles;
  9. using Hotline.Orders;
  10. using Hotline.Settings;
  11. using Hotline.Settings.TimeLimits;
  12. using Hotline.Share.Dtos;
  13. using Hotline.Share.Dtos.FlowEngine;
  14. using Hotline.Share.Dtos.FlowEngine.Definition;
  15. using Hotline.Share.Dtos.Settings;
  16. using Hotline.Share.Enums.FlowEngine;
  17. using Hotline.Share.Enums.Identity;
  18. using Hotline.Users;
  19. using MapsterMapper;
  20. using Hotline.File;
  21. using Hotline.Share.Enums.Settings;
  22. using XF.Domain.Authentications;
  23. using XF.Domain.Dependency;
  24. using XF.Domain.Entities;
  25. using XF.Domain.Exceptions;
  26. using XF.Domain.Extensions;
  27. using XF.Domain.Repository;
  28. using XF.Utility.EnumExtensions;
  29. using Hotline.Share.Dtos.File;
  30. using Microsoft.Extensions.Logging;
  31. using System.Text;
  32. using System.Diagnostics;
  33. using Hotline.Configurations;
  34. using Hotline.Share.Dtos.Order.Handle;
  35. using Microsoft.AspNetCore.Http;
  36. using Microsoft.Extensions.Options;
  37. using Newtonsoft.Json;
  38. using NPOI.SS.Formula.Functions;
  39. using DocumentFormat.OpenXml.Drawing;
  40. using Hotline.Share.Dtos.FlowEngine.Workflow;
  41. using SqlSugar;
  42. using Hotline.SeedData;
  43. namespace Hotline.Application.FlowEngine;
  44. public class WorkflowApplication : IWorkflowApplication, IScopeDependency
  45. {
  46. private readonly IWorkflowDomainService _workflowDomainService;
  47. private IRepository<WorkflowStep> _workflowStepRepository;
  48. private IRepository<WorkflowTrace> _workflowTraceRepository;
  49. private readonly IRepository<WorkflowCountersign> _workflowCountersignRepository;
  50. private readonly IRepository<User> _userRepository;
  51. private readonly ISystemOrganizeRepository _organizeRepository;
  52. private readonly IRepository<Role> _roleRepository;
  53. private readonly IWfModuleCacheManager _wfModuleCacheManager;
  54. private readonly ISessionContextProvider _sessionContextProvider;
  55. private readonly IMapper _mapper;
  56. private readonly IFileRepository _fileRepository;
  57. private readonly ILogger<WorkflowApplication> _logger;
  58. private readonly ISystemSettingCacheManager _systemSettingCacheManager;
  59. public WorkflowApplication(
  60. IWorkflowDomainService workflowDomainService,
  61. IRepository<WorkflowStep> workflowStepRepository,
  62. IRepository<WorkflowTrace> workflowTraceRepository,
  63. IRepository<WorkflowCountersign> workflowCountersignRepository,
  64. IRepository<User> userRepository,
  65. ISystemOrganizeRepository organizeRepository,
  66. IRepository<Role> roleRepository,
  67. IWfModuleCacheManager wfModuleCacheManager,
  68. ISessionContextProvider sessionContextProvider,
  69. IMapper mapper,
  70. IFileRepository fileRepository,
  71. ISystemSettingCacheManager systemSettingCacheManager,
  72. ILogger<WorkflowApplication> logger)
  73. {
  74. _workflowDomainService = workflowDomainService;
  75. _workflowStepRepository = workflowStepRepository;
  76. _workflowTraceRepository = workflowTraceRepository;
  77. _workflowCountersignRepository = workflowCountersignRepository;
  78. _userRepository = userRepository;
  79. _organizeRepository = organizeRepository;
  80. _roleRepository = roleRepository;
  81. _wfModuleCacheManager = wfModuleCacheManager;
  82. _sessionContextProvider = sessionContextProvider;
  83. _mapper = mapper;
  84. _fileRepository = fileRepository;
  85. _logger = logger;
  86. _systemSettingCacheManager = systemSettingCacheManager;
  87. }
  88. public async Task<string> StartWorkflowAsync(StartWorkflowDto dto, string externalId,
  89. DateTime? expiredTime, CancellationToken cancellationToken = default)
  90. {
  91. //var validator = new StartWorkflowDtoValidator();
  92. //var validResult = await validator.ValidateAsync(dto, cancellationToken);
  93. //if (!validResult.IsValid)
  94. // throw new UserFriendlyException(
  95. // $"非法参数, {string.Join(',', validResult.Errors.Select(d => d.ErrorMessage))}");
  96. var wfModule = await GetWorkflowModuleAsync(dto.DefinitionModuleCode, cancellationToken);
  97. var definition = wfModule.Definition;
  98. if (definition == null)
  99. throw new UserFriendlyException("无效模板编码");
  100. if (definition.Status is not EDefinitionStatus.Enable)
  101. throw new UserFriendlyException("该模板不可用");
  102. //如果发起会签需检查是否支持发起会签
  103. var startStepDefine = definition.FindStartStepDefine();
  104. //下一节点是否为动态节点
  105. var isNextDynamic = startStepDefine.InstanceMode is EInstanceMode.Dynamic &&
  106. !_workflowDomainService.DynamicShouldTerminal(startStepDefine, _sessionContextProvider.SessionContext.OrgLevel);
  107. var firstStepDefine = isNextDynamic
  108. ? startStepDefine
  109. : definition.FindStepDefine(dto.NextStepCode);
  110. if (firstStepDefine is null)
  111. throw new UserFriendlyException("未查询到下一步节点配置");
  112. //1. 如果不是按角色指派,handlers必填 2. 如果按角色指派,handlers可以不选
  113. if (firstStepDefine.HandlerType is not EHandlerType.Role && !dto.NextHandlers.Any())
  114. throw UserFriendlyException.SameMessage("未指派办理人");
  115. if (dto.IsStartCountersign)
  116. {
  117. if (!startStepDefine.CanStartCountersign)
  118. throw new UserFriendlyException("当前节点不支持发起会签");
  119. //if (startStepDefine.HandlerType is EHandlerType.Role)
  120. // throw new UserFriendlyException("当前节点不支持发起会签");
  121. //即使当前节点支持发起会签,但下一节点为信息汇总节点、结束节点时也不可发起会签
  122. if (firstStepDefine.StepType is EStepType.Summary or EStepType.End)
  123. throw new UserFriendlyException("下一节点不允许发起会签");
  124. //下一节点是会签汇总节点也不允许发起会签
  125. if (dto.BackToCountersignEnd)
  126. throw new UserFriendlyException("下一节点不允许发起会签");
  127. }
  128. var workflow = await _workflowDomainService.CreateWorkflowAsync(wfModule, dto.Title,
  129. _sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.RequiredOrgId,
  130. externalId, cancellationToken);
  131. //var startStepHandles = new List<WorkflowStepHandler>{WorkflowStepHandler.Create(workflow.Id, workflow.ExternalId,
  132. // EFlowAssignType.User, current.RequiredUserId, current.UserName,
  133. // current.RequiredOrgId, current.OrgName)};
  134. var defineHandler = startStepDefine.HandlerTypeItems.First();
  135. var startStep = _workflowDomainService.CreateStartStep(workflow, startStepDefine, dto,
  136. new FlowStepHandler
  137. {
  138. Key = _sessionContextProvider.SessionContext.RequiredUserId,
  139. Value = _sessionContextProvider.SessionContext.UserName,
  140. UserId = _sessionContextProvider.SessionContext.UserId,
  141. Username = _sessionContextProvider.SessionContext.UserName,
  142. OrgId = _sessionContextProvider.SessionContext.RequiredOrgId,
  143. OrgName = _sessionContextProvider.SessionContext.OrgName,
  144. RoleId = defineHandler.Key,
  145. RoleName = defineHandler.Value,
  146. }, expiredTime);
  147. var flowAssignInfo =
  148. await GetNextStepFlowAssignInfoAsync(workflow, startStep, dto, firstStepDefine, isNextDynamic, cancellationToken);
  149. var counterSignType = _workflowDomainService.GetCounterSignType(dto.IsStartCountersign, startStep.BusinessType);
  150. //办理开始节点
  151. await _workflowDomainService.HandleStepAsync(startStep, workflow, dto, counterSignType, expiredTime, cancellationToken);
  152. if (dto.Files.Any())
  153. startStep.FileJson =
  154. await _fileRepository.AddFileAsync(dto.Files, workflow.ExternalId, startStep.Id, cancellationToken);
  155. await _workflowStepRepository.AddAsync(startStep, cancellationToken);
  156. workflow.Steps.Add(startStep);
  157. //starttrace
  158. var startTrace = _mapper.Map<WorkflowTrace>(startStep);
  159. startTrace.StepId = startStep.Id;
  160. startTrace.TraceType = EWorkflowTraceType.Normal;
  161. //_mapper.Map(dto, startTrace);
  162. await _workflowTraceRepository.AddAsync(startTrace, cancellationToken);
  163. workflow.Traces.Add(startTrace);
  164. startStep.WorkflowTrace = startTrace;
  165. //更新受理人信息
  166. workflow.UpdateAcceptor(
  167. _sessionContextProvider.SessionContext.RequiredUserId,
  168. _sessionContextProvider.SessionContext.UserName,
  169. _sessionContextProvider.SessionContext.StaffNo,
  170. _sessionContextProvider.SessionContext.RequiredOrgId,
  171. _sessionContextProvider.SessionContext.OrgName);
  172. await _workflowDomainService.StartAsync(workflow, startStep, dto, firstStepDefine, isNextDynamic,
  173. flowAssignInfo, counterSignType, expiredTime, cancellationToken);
  174. return workflow.Id;
  175. }
  176. /// <summary>
  177. /// 开始流程并停留在开始节点(开始节点作为待办节点)
  178. /// </summary>
  179. public async Task<string> StartWorkflowToStartStepAsync(StartWorkflowDto dto, string externalId, DateTime? expiredTime = null,
  180. CancellationToken cancellationToken = default)
  181. {
  182. var validator = new StartWorkflowDtoValidator();
  183. var validResult = await validator.ValidateAsync(dto, cancellationToken);
  184. if (!validResult.IsValid)
  185. throw new UserFriendlyException(
  186. $"非法参数, {string.Join(',', validResult.Errors.Select(d => d.ErrorMessage))}");
  187. var wfModule = await GetWorkflowModuleAsync(dto.DefinitionModuleCode, cancellationToken);
  188. var definition = wfModule.Definition;
  189. if (definition == null)
  190. throw new UserFriendlyException("无效模板编码");
  191. if (definition.Status is not EDefinitionStatus.Enable)
  192. throw new UserFriendlyException("该模板不可用");
  193. //如果发起会签需检查是否支持发起会签
  194. var startStepDefine = definition.FindStartStepDefine();
  195. var workflow = await _workflowDomainService.CreateWorkflowAsync(wfModule, dto.Title,
  196. _sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.RequiredOrgId,
  197. externalId, cancellationToken);
  198. var defineHandler = startStepDefine.HandlerTypeItems.First();
  199. //todo 需求:所有坐席都可以办,临时方案,后期重构:依据策略决定指派对象
  200. var startStep = _workflowDomainService.CreateStartStep(workflow, startStepDefine, dto,
  201. new FlowStepHandler
  202. {
  203. Key = _sessionContextProvider.SessionContext.RequiredUserId,
  204. Value = _sessionContextProvider.SessionContext.UserName,
  205. UserId = _sessionContextProvider.SessionContext.UserId,
  206. Username = _sessionContextProvider.SessionContext.UserName,
  207. OrgId = _sessionContextProvider.SessionContext.RequiredOrgId,
  208. OrgName = _sessionContextProvider.SessionContext.OrgName,
  209. RoleId = defineHandler.Key,
  210. RoleName = defineHandler.Value,
  211. }, expiredTime,
  212. EFlowAssignType.Role);
  213. if (dto.Files.Any())
  214. startStep.FileJson = await _fileRepository.AddFileAsync(dto.Files, workflow.ExternalId, startStep.Id, cancellationToken);
  215. await _workflowStepRepository.AddAsync(startStep, cancellationToken);
  216. workflow.Steps.Add(startStep);
  217. //starttrace
  218. var startTrace = _mapper.Map<WorkflowTrace>(startStep);
  219. startTrace.StepId = startStep.Id;
  220. startTrace.TraceType = EWorkflowTraceType.Normal;
  221. //_mapper.Map(dto, startTrace);
  222. await _workflowTraceRepository.AddAsync(startTrace, cancellationToken);
  223. workflow.Traces.Add(startTrace);
  224. startStep.WorkflowTrace = startTrace;
  225. //更新受理人信息
  226. workflow.UpdateAcceptor(
  227. _sessionContextProvider.SessionContext.RequiredUserId,
  228. _sessionContextProvider.SessionContext.UserName,
  229. _sessionContextProvider.SessionContext.StaffNo,
  230. _sessionContextProvider.SessionContext.RequiredOrgId,
  231. _sessionContextProvider.SessionContext.OrgName);
  232. return workflow.Id;
  233. }
  234. /// <summary>
  235. /// 流转至下一节点(节点办理)
  236. /// </summary>
  237. public async Task<Workflow> NextAsync(NextWorkflowDto dto, DateTime? expiredTime = null, CancellationToken cancellationToken = default)
  238. {
  239. var validator = new NextWorkflowDtoValidator();
  240. var validResult = await validator.ValidateAsync(dto, cancellationToken);
  241. if (!validResult.IsValid)
  242. throw new UserFriendlyException(
  243. $"非法参数, {string.Join(',', validResult.Errors.Select(d => d.ErrorMessage))}");
  244. var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withDefine: true, withSteps: true,
  245. withTraces: true, withCountersigns: true, cancellationToken: cancellationToken);
  246. //var currentStep = _workflowDomainService.FindCurrentStepWaitForHandle(workflow,
  247. // current.RequiredUserId, current.RequiredOrgId, current.Roles);
  248. var currentStep = workflow.Steps.FirstOrDefault(d => d.Id == dto.StepId);
  249. if (currentStep == null)
  250. throw new UserFriendlyException(
  251. $"未找到对应节点, workflowId: {dto.WorkflowId}, stepId: {dto.StepId}", "未找到对应节点");
  252. if (currentStep.Status is EWorkflowStepStatus.Handled)
  253. throw new UserFriendlyException("该状态不支持继续办理");
  254. var currentStepDefine = _workflowDomainService.GetStepDefine(workflow.WorkflowDefinition, currentStep.Code);
  255. //下一节点是否为动态节点
  256. var isNextDynamic = currentStepDefine.InstanceMode is EInstanceMode.Dynamic &&
  257. !_workflowDomainService.DynamicShouldTerminal(currentStepDefine, _sessionContextProvider.SessionContext.OrgLevel);
  258. StepDefine nextStepDefine;
  259. if (isNextDynamic
  260. || (currentStep.IsInCountersign() && !currentStep.IsTopCountersignEndStep(workflow.TopCountersignStepId))
  261. || dto.IsStartCountersign)
  262. {
  263. //下一步配置为当前节点配置
  264. nextStepDefine = currentStepDefine;
  265. }
  266. else
  267. {
  268. //下一步配置为下一步节点配置
  269. nextStepDefine = _workflowDomainService.GetStepDefine(workflow.WorkflowDefinition, dto.NextStepCode);
  270. }
  271. //需求:按角色选择办理人可以不选,表示该角色下所有人都可以办理,同时依据配置:是否本部门人办理显示待选办理人。角色下只要一人办理即可(即:角色下不发起会签)
  272. if (nextStepDefine.HandlerType != EHandlerType.Role && !dto.NextHandlers.Any())
  273. throw new UserFriendlyException("未指定节点处理者");
  274. if (dto.IsStartCountersign)
  275. {
  276. if (!currentStepDefine.CanStartCountersign)
  277. throw new UserFriendlyException("当前节点不支持发起会签");
  278. //if (currentStepDefine.HandlerType is EHandlerType.Role)
  279. // throw new UserFriendlyException("当前节点不支持发起会签");
  280. //即使当前节点支持发起会签,但下一节点为信息汇总节点、结束节点时也不可发起会签
  281. if (nextStepDefine.StepType is EStepType.Summary or EStepType.End)
  282. throw new UserFriendlyException("下一节点不允许发起会签");
  283. //下一节点是会签汇总节点也不允许发起会签
  284. if (dto.BackToCountersignEnd)
  285. throw new UserFriendlyException("下一节点不允许发起会签");
  286. }
  287. var flowAssignInfo =
  288. await GetNextStepFlowAssignInfoAsync(workflow, currentStep, dto, nextStepDefine, isNextDynamic, cancellationToken);
  289. //var nextStepHandlers = await GetNextStepHandlersAsync(workflow, nextStepDefine, dto, cancellationToken);
  290. await _workflowDomainService.NextAsync(workflow, currentStep, dto, nextStepDefine, isNextDynamic,
  291. flowAssignInfo, expiredTime, cancellationToken);
  292. return workflow;
  293. }
  294. /// <summary>
  295. /// 退回(返回前一节点)
  296. /// </summary>
  297. public async Task<EFlowDirection> PreviousAsync(PreviousWorkflowDto dto, CancellationToken cancellationToken)
  298. {
  299. var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withSteps: true,
  300. withTraces: true, withCountersigns: true, cancellationToken: cancellationToken);
  301. return await _workflowDomainService.PreviousAsync(workflow, dto,
  302. _sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.UserName,
  303. _sessionContextProvider.SessionContext.RequiredOrgId, _sessionContextProvider.SessionContext.OrgName,
  304. _sessionContextProvider.SessionContext.OrgAreaCode, _sessionContextProvider.SessionContext.OrgAreaName,
  305. _sessionContextProvider.SessionContext.OrgIsCenter, _sessionContextProvider.SessionContext.Roles,
  306. cancellationToken);
  307. }
  308. /// <summary>
  309. /// 工单退回(返回前一节点)
  310. /// </summary>
  311. public async Task<EFlowDirection> PreviousAsync(PreviousWorkflowDto dto, string applicantId, string applicantOrgId, string[] applicantRoleIds,
  312. CancellationToken cancellationToken)
  313. {
  314. var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withSteps: true,
  315. withTraces: true, withCountersigns: true, cancellationToken: cancellationToken);
  316. var user = await _userRepository.Queryable()
  317. .Includes(x => x.Organization)
  318. .FirstAsync(x => x.Id == applicantId, cancellationToken);
  319. return await _workflowDomainService.PreviousAsync(workflow, dto,
  320. applicantId, user.Name,
  321. applicantOrgId, user.Organization.Name,
  322. user.Organization.AreaCode, user.Organization.AreaName,
  323. user.Organization.IsCenter, applicantRoleIds, cancellationToken);
  324. }
  325. /// <summary>
  326. /// 撤回至之前任意节点
  327. /// </summary>
  328. public async Task RecallAsync(RecallDto dto, DateTime? expiredTime, bool isOrderFiled, EWorkflowTraceType traceType,
  329. CancellationToken cancellationToken)
  330. {
  331. var validator = new RecallDtoValidator();
  332. var validationResult = await validator.ValidateAsync(dto, cancellationToken);
  333. if (!validationResult.IsValid)
  334. throw new UserFriendlyException(string.Join(',', validationResult.Errors));
  335. var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withDefine: true, withSteps: true,
  336. withTraces: true, withCountersigns: true, cancellationToken: cancellationToken);
  337. //await _orderDomainService.ReadyToRecallAsync(workflow.ExternalId, cancellationToken);
  338. var targetStepDefine = _workflowDomainService.GetStepDefine(workflow.WorkflowDefinition, dto.NextStepCode);
  339. if (targetStepDefine.StepType is EStepType.End)
  340. throw UserFriendlyException.SameMessage("结束节点不支持撤回");
  341. //var isStartCountersign = targetStepDefine.CouldPrevStartCountersign(dto.NextHandlers.Count);
  342. var targetStep = workflow.Steps.FirstOrDefault(d => d.Code == dto.NextStepCode && d.IsOrigin);
  343. if (targetStep is null)
  344. throw UserFriendlyException.SameMessage("该流程尚未流转至该节点");
  345. ///退回到派单组 没有下一步办理人 获取之前节点办理人
  346. if (!dto.NextHandlers.Any())
  347. {
  348. dto.NextHandlers.Add(new FlowStepHandler()
  349. {
  350. UserId = targetStep.HandlerId,
  351. Username = targetStep.HandlerName,
  352. OrgId = targetStep.HandlerOrgId,
  353. OrgName = targetStep.HandlerOrgName,
  354. Key = targetStep.HandlerId,
  355. Value = targetStep.HandlerName,
  356. RoleId = targetStep.RoleId,
  357. RoleName = targetStep.RoleName
  358. });
  359. }
  360. var flowAssignInfo = await GetNextStepFlowAssignInfoByDefineAsync(targetStepDefine, dto.HandlerType, dto.IsStartCountersign,
  361. dto.NextHandlers.Select(d => new Kv(d.Key, d.Value)).ToList(), cancellationToken);
  362. //var stepHandlers = await GetNextStepHandlersAsync(workflow, targetStepDefine, dto, cancellationToken);
  363. await _workflowDomainService.RecallAsync(workflow, dto, targetStepDefine, flowAssignInfo, traceType, expiredTime, isOrderFiled,
  364. cancellationToken);
  365. }
  366. /// <summary>
  367. /// 无视流程模板配置直接将当前节点办理至结束节点
  368. /// </summary>
  369. public async Task HandleToEndAsync(string workflowId, string opinion, List<FileDto> files,
  370. EReviewResult reviewResult = EReviewResult.Unknown, CancellationToken cancellationToken = default)
  371. {
  372. var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withDefine: true, withSteps: true,
  373. cancellationToken: cancellationToken);
  374. var endStepDefine = workflow.WorkflowDefinition.FindEndStepDefine();
  375. if (endStepDefine is null)
  376. throw new UserFriendlyException("未正确配置结束节点");
  377. var unHandleStep = workflow.Steps.FirstOrDefault(d => d.Status is not EWorkflowStepStatus.Handled);
  378. if (unHandleStep is null)
  379. throw new UserFriendlyException($"无待办节点, workflowId: {workflowId}", "无待办节点");
  380. var dto = new NextWorkflowDto
  381. {
  382. WorkflowId = workflowId,
  383. NextStepCode = endStepDefine.Code,
  384. NextStepName = endStepDefine.Name,
  385. FlowDirection = EFlowDirection.OrgToFile,
  386. BusinessType = endStepDefine.BusinessType,
  387. ReviewResult = reviewResult,
  388. Opinion = opinion,
  389. Files = files,
  390. StepId = unHandleStep.Id
  391. };
  392. await NextAsync(dto, cancellationToken: cancellationToken);
  393. }
  394. /// <summary>
  395. /// 查询开始流程的下一步待选节点
  396. /// </summary>
  397. public async Task<NextStepsDto<NextStepOption>> GetStartStepsAsync(string moduleCode, CancellationToken cancellationToken)
  398. {
  399. var wfModule = await GetWorkflowModuleAsync(moduleCode, cancellationToken);
  400. var definition = wfModule.Definition;
  401. if (definition == null)
  402. throw new UserFriendlyException("无效模板编码");
  403. if (definition.Status is not EDefinitionStatus.Enable)
  404. throw new UserFriendlyException("该模板不可用");
  405. var startStepDefine = definition.FindStartStepDefine();
  406. if (startStepDefine.InstanceMode is EInstanceMode.Dynamic &&
  407. !_workflowDomainService.DynamicShouldTerminal(startStepDefine, _sessionContextProvider.SessionContext.OrgLevel))
  408. {
  409. var settingHandle = _systemSettingCacheManager.GetSetting(SettingConstants.RoleJingBanRen);
  410. var settingLead = _systemSettingCacheManager.GetSetting(SettingConstants.RoleLingDao);
  411. var nextStepOption = await GetDynamicStepAsync(startStepDefine.InstancePolicy.Value,
  412. startStepDefine.StepType, startStepDefine.BusinessType, settingHandle?.SettingValue[0], settingLead?.SettingValue[0],
  413. cancellationToken);
  414. return new NextStepsDto<NextStepOption>
  415. {
  416. Steps = new List<NextStepOption> { nextStepOption }
  417. };
  418. }
  419. var firstStepDefines = definition.FindStepDefines(startStepDefine.NextSteps.Select(d => d.Code));
  420. if (!firstStepDefines.Any())
  421. throw new UserFriendlyException("未正确配置首个办理节点");
  422. return new NextStepsDto<NextStepOption>
  423. {
  424. TimeTypeOptions = EnumExts.GetDescriptions<ETimeType>().ToList(),
  425. Steps = await GetConfigStepsAsync(definition.FlowType, startStepDefine.StepType, startStepDefine.BusinessType,
  426. firstStepDefines, cancellationToken)
  427. };
  428. }
  429. /// <summary>
  430. /// 查询办理流程的下一步待选节点
  431. /// </summary>
  432. public async Task<NextStepsWithOpinionDto<NextStepOption>> GetNextStepsAsync(string workflowId, CancellationToken cancellationToken)
  433. {
  434. var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withDefine: true, withSteps: true,
  435. cancellationToken: cancellationToken);
  436. var currentStep = _workflowDomainService.FindCurrentStepWaitForHandle(workflow,
  437. _sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.RequiredOrgId,
  438. _sessionContextProvider.SessionContext.Roles);
  439. if (currentStep.StepType is EStepType.End)
  440. throw new UserFriendlyException("结束节点无需办理");
  441. return await GetNextStepsAsync(workflow, currentStep, cancellationToken);
  442. }
  443. public async Task<NextStepsWithOpinionDto<NextStepOption>> GetNextStepsAsync(string workflowId, string stepId,
  444. CancellationToken cancellationToken)
  445. {
  446. var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withDefine: true, withSteps: true,
  447. cancellationToken: cancellationToken);
  448. var currentStep = workflow.Steps.FirstOrDefault(d => d.Id == stepId);
  449. if (currentStep == null)
  450. throw new UserFriendlyException($"未查询到选择节点, workflowId: {workflowId}, stepId: {stepId}");
  451. if (currentStep.StepType is EStepType.End)
  452. throw new UserFriendlyException("结束节点无需办理");
  453. return await GetNextStepsAsync(workflow, currentStep, cancellationToken);
  454. }
  455. /// <summary>
  456. /// 跨级指派查询下一步可选节点及办理对象参数
  457. /// </summary>
  458. public async Task<NextStepsDto<NextStepOption>> GetCrossLevelStepsAsync(GetCrossLevelStepsDto dto, CancellationToken cancellationToken)
  459. {
  460. WorkflowDefinition definition;
  461. if (string.IsNullOrEmpty(dto.WorkflowId))
  462. {
  463. var wfModule = await GetWorkflowModuleAsync(WorkflowModuleConsts.OrderHandle, cancellationToken);
  464. definition = wfModule.Definition;
  465. }
  466. else
  467. {
  468. var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withDefine: true, cancellationToken: cancellationToken);
  469. definition = workflow.WorkflowDefinition;
  470. }
  471. if (definition == null)
  472. throw new UserFriendlyException("无效模板编码");
  473. if (definition.Status is not EDefinitionStatus.Enable)
  474. throw new UserFriendlyException("该模板不可用");
  475. var currentStepDefine = definition.FindStepDefine(dto.StepCode);
  476. var nextStepDefines = definition.FindStepDefines(currentStepDefine.NextSteps.Select(d => d.Code))
  477. .Where(d => d.StepType == EStepType.Normal && d.BusinessType == EBusinessType.Department)
  478. .ToList();
  479. var stepOptions = new List<NextStepOption>();
  480. foreach (var stepDefine in nextStepDefines)
  481. {
  482. var success = int.TryParse(stepDefine.HandlerTypeItems.First().Key, out var level);
  483. int? orgLevel = success ? level : null;
  484. var nextStepOption = new NextStepOption
  485. {
  486. Key = stepDefine.Code,
  487. Value = stepDefine.Name,
  488. StepType = stepDefine.StepType,
  489. BusinessType = stepDefine.BusinessType,
  490. HandlerType = stepDefine.HandlerType,
  491. OrgLevel = stepDefine.HandlerType is EHandlerType.OrgLevel ? orgLevel : null,
  492. };
  493. var orgs = await _organizeRepository.Queryable()
  494. .Where(d => d.IsEnable &&
  495. d.Level == orgLevel &&
  496. dto.OrgIds.Contains(d.ParentId))
  497. .ToListAsync(cancellationToken);
  498. nextStepOption.Items = orgs.Select(d => new FlowStepHandler
  499. {
  500. Key = d.Id,
  501. Value = d.Name,
  502. OrgId = d.Id,
  503. OrgName = d.Name
  504. })
  505. .ToList();
  506. nextStepOption.FlowDirection = _workflowDomainService.GetFlowDirection(dto.BusinessType, stepDefine.BusinessType);
  507. stepOptions.Add(nextStepOption);
  508. }
  509. return new NextStepsDto<NextStepOption>
  510. {
  511. CanReject = false,
  512. CanStartCountersign = true,
  513. CurrentStepBusinessType = dto.BusinessType,
  514. Steps = stepOptions
  515. };
  516. }
  517. private async Task<NextStepsWithOpinionDto<NextStepOption>> GetNextStepsAsync(Workflow workflow, WorkflowStep currentStep,
  518. CancellationToken cancellationToken)
  519. {
  520. var dto = new NextStepsWithOpinionDto<NextStepOption>
  521. {
  522. CanReject = workflow.IsReviewType() && currentStep.CanReject,
  523. //ExpiredTime = workflow.ExpiredTime,
  524. CanStartCountersign = currentStep.CanStartCountersign,
  525. CurrentStepBusinessType = currentStep.BusinessType,
  526. CurrentStepType = currentStep.StepType,
  527. CurrentHandlerType = currentStep.HandlerType,
  528. TimeTypeOptions = EnumExts.GetDescriptions<ETimeType>().ToList(),
  529. IsMainHandlerShow = workflow.WorkflowDefinition.IsMainHandlerShow,
  530. StepId = currentStep.Id,
  531. CurrentOrgLevel = string.IsNullOrEmpty(currentStep.HandlerOrgId) ? null : currentStep.HandlerOrgId.CalcOrgLevel(),
  532. Opinion = currentStep.Opinion,
  533. };
  534. var currentStepDefine = _workflowDomainService.GetStepDefine(workflow.WorkflowDefinition, currentStep.Code);
  535. if (currentStep.InstanceMode is EInstanceMode.Dynamic &&
  536. !_workflowDomainService.DynamicShouldTerminal(currentStepDefine, _sessionContextProvider.SessionContext.OrgLevel))
  537. {
  538. var settingHandle = _systemSettingCacheManager.GetSetting(SettingConstants.RoleJingBanRen);
  539. var settingLead = _systemSettingCacheManager.GetSetting(SettingConstants.RoleLingDao);
  540. //动态生成下一步
  541. var nextStepOption = await GetDynamicStepAsync(currentStep.InstancePolicy.Value, currentStep.StepType,
  542. currentStep.BusinessType, settingHandle?.SettingValue[0], settingLead?.SettingValue[0], cancellationToken);
  543. dto.Steps = new List<NextStepOption>
  544. {
  545. nextStepOption
  546. };
  547. return dto;
  548. }
  549. if (workflow.IsInCountersign && currentStep.IsInCountersign())
  550. {
  551. if (currentStep.IsCountersignEndStep)
  552. {
  553. // // 宜宾需求:会签汇总节点展示会签办理节点办理意见
  554. // var countersignHandleSteps = workflow.Steps.Where(d =>
  555. // d.CountersignId == currentStep.CountersignId &&
  556. // d.CountersignPosition is ECountersignPosition.Multi or ECountersignPosition.Single).ToList();
  557. // var sb = new StringBuilder();
  558. // foreach (var countersignHandleStep in countersignHandleSteps)
  559. // {
  560. // //sb.AppendLine($"{countersignHandleStep.GetActualHandler()?.GetHandler().Value} : {countersignHandleStep.Opinion}");
  561. // sb.AppendLine($"{countersignHandleStep.GetHandler().Value} : {countersignHandleStep.Opinion}");
  562. // }
  563. //
  564. // dto.Opinion = sb.ToString();
  565. //当前待办节点为会签汇总节点时:检查是否为顶级会签汇总节点,t:按配置往下走,f:继续往上汇总,不需要重复往下指派
  566. if (!currentStep.IsTopCountersignEndStep(workflow.TopCountersignStepId))
  567. {
  568. var startCountersignStep = GetCsLoopStartStep(workflow, currentStep);
  569. ////查找当前节点对应会签开始节点的上级作为下一个cs汇总节点的汇总对象
  570. //var startCountersignStep =
  571. // workflow.Steps.FirstOrDefault(d => d.Id == currentStep.CountersignStartStepId);
  572. //if (startCountersignStep is null)
  573. // throw new UserFriendlyException(
  574. // $"未查询到会签开始节点,workflowId: {workflow.Id}, startStepId: {currentStep.CountersignStartStepId}",
  575. // "未查询到会签开始节点,数据异常");
  576. var countersignEndOption = GetCsEndStepByTargetPrev(workflow.Steps, startCountersignStep);
  577. //按会签策略
  578. var nextStepOption = await GetDynamicStepAsync(currentStep.CountersignPolicy.Value,
  579. EStepType.Normal, currentStep.BusinessType, cancellationToken);
  580. dto.Steps = new List<NextStepOption> { nextStepOption, countersignEndOption };
  581. return dto;
  582. }
  583. }
  584. else
  585. {
  586. //汇总节点
  587. var countersignEndOption = GetCsEndStepByTargetPrev(workflow.Steps, currentStep);
  588. //按会签策略
  589. var nextStepOption =
  590. await GetDynamicStepAsync(currentStep.CountersignPolicy.Value,
  591. EStepType.Normal, currentStep.BusinessType, cancellationToken);
  592. dto.Steps = new List<NextStepOption> { nextStepOption, countersignEndOption };
  593. return dto;
  594. }
  595. }
  596. var nextDefines = workflow.WorkflowDefinition.FindStepDefines(currentStep.NextSteps.Select(d => d.Code));
  597. if (!nextDefines.Any())
  598. throw new UserFriendlyException("未正确配置下一节点");
  599. dto.Steps = await GetConfigStepsAsync(workflow, currentStep, nextDefines, cancellationToken);
  600. // 宜宾需求:汇总节点展示前一级节点办理意见
  601. if (currentStep.StepType is EStepType.Summary &&
  602. !currentStep.IsCountersignEndStep &&
  603. string.IsNullOrEmpty(dto.Opinion))
  604. {
  605. var prevStep = workflow.Steps.FirstOrDefault(d => d.Id == currentStep.PrevStepId);
  606. dto.Opinion = $"{prevStep?.GetHandler().Value} : {prevStep?.Opinion}";
  607. }
  608. return dto;
  609. }
  610. private WorkflowStep GetCsLoopStartStep(Workflow workflow, WorkflowStep currentStep)
  611. {
  612. var startCountersignStep =
  613. workflow.Steps.FirstOrDefault(d => d.Id == currentStep.CountersignStartStepId);
  614. if (startCountersignStep is null)
  615. throw new UserFriendlyException(
  616. $"未查询到会签开始节点,workflowId: {workflow.Id}, startStepId: {currentStep.CountersignStartStepId}",
  617. "未查询到会签开始节点,数据异常");
  618. if (!startCountersignStep.IsCountersignEndStep)
  619. return startCountersignStep;
  620. return GetCsLoopStartStep(workflow, startCountersignStep);
  621. }
  622. /// <summary>
  623. /// 查询撤回可选节点及办理对象
  624. /// </summary>
  625. public async Task<NextStepsDto<RecallStepOption>> GetRecallStepsAsync(string workflowId, CancellationToken cancellationToken)
  626. {
  627. var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withDefine: true, withSteps: true,
  628. cancellationToken: cancellationToken);
  629. var isEnd = workflow.Steps.Any(x => x.StepType == EStepType.End);
  630. var currentStep = workflow.Steps.FirstOrDefault(d => d.Id == workflow.ActualHandleStepId);
  631. if (currentStep is null)
  632. throw new UserFriendlyException("无效当前节点编号");
  633. var query = workflow.Steps.Where(d =>
  634. d.StepType != EStepType.End &&
  635. d.IsOrigin);
  636. if (!isEnd)
  637. {
  638. query = query.Where(d => d.Id != currentStep.Id);
  639. }
  640. var originSteps = query.ToList();
  641. var stepCodes = originSteps.Select(d => d.Code).ToList();
  642. var stepDefines = workflow.WorkflowDefinition.FindStepDefines(stepCodes);
  643. var dto = new NextStepsDto<RecallStepOption>
  644. {
  645. TimeTypeOptions = EnumExts.GetDescriptions<ETimeType>().ToList()
  646. };
  647. var steps = await GetRecallConfigStepsAsync(originSteps, stepDefines, currentStep,
  648. workflow.FlowType,
  649. workflow.Status is EWorkflowStatus.Completed,
  650. cancellationToken);
  651. dto.Steps = steps;
  652. return dto;
  653. }
  654. private async Task<List<RecallStepOption>> GetRecallConfigStepsAsync(
  655. List<WorkflowStep> originSteps, List<StepDefine> stepDefines,
  656. WorkflowStep currentStep, EFlowType flowType, bool isWorkflowFiled, CancellationToken cancellationToken)
  657. {
  658. var steps = new List<RecallStepOption>();
  659. foreach (var originStep in originSteps)
  660. {
  661. var stepDefine = stepDefines.First(d => d.Code == originStep.Code);
  662. var nextStepOption = await GetConfigStepAsync(flowType, stepDefine, cancellationToken);
  663. var stepOption = _mapper.Map<RecallStepOption>(nextStepOption);
  664. if (stepDefine.StepType is EStepType.End)
  665. {
  666. steps.Add(stepOption);
  667. continue;
  668. }
  669. stepOption.InputRealHandler = false;
  670. //已归档工单,撤回至中心看作otc,撤回至部门看作cto
  671. //todo 依据归档节点的busiType判断
  672. stepOption.FlowDirection = isWorkflowFiled
  673. ? stepDefine.BusinessType is EBusinessType.Seat or EBusinessType.Send
  674. ? EFlowDirection.FiledToCenter
  675. : stepDefine.BusinessType is EBusinessType.Department or EBusinessType.DepartmentLeader
  676. ? EFlowDirection.FiledToOrg
  677. : null
  678. //: CheckFlowDirection(currentStep.BusinessType, stepDefine.BusinessType);
  679. : _workflowDomainService.GetFlowDirection(currentStep.BusinessType, stepDefine.BusinessType);
  680. //需求已调整为特提必重算期满时间
  681. //需求:撤回选择办理对象时,默认选中该节点原办理对象
  682. //if (originStep.Handlers.Any())
  683. // stepOption.Handler = originStep.Handlers.FirstOrDefault(d => d.Key == originStep.HandlerId || d.Key == originStep.HandlerOrgId);
  684. stepOption.Handler = originStep.GetWorkflowStepHandler();
  685. //if (originStep.StepHandlers.Any())
  686. // stepOption.Handler = originStep.GetActualHandler()?.GetHandler() ?? new();
  687. steps.Add(stepOption);
  688. }
  689. return steps;
  690. }
  691. /// <summary>
  692. /// 否决
  693. /// </summary>
  694. public async Task RejectAsync(RejectDto dto, CancellationToken cancellationToken)
  695. {
  696. var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withDefine: true,
  697. cancellationToken: cancellationToken);
  698. //var basicDto = _mapper.Map<BasicWorkflowDto>(dto);
  699. //basicDto.NextStepCode = string.Empty;
  700. //basicDto.IsStartCountersign = false;
  701. //await _workflowDomainService.RejectAsync(workflow, basicDto, cancellationToken);
  702. var endStepDefine = workflow.WorkflowDefinition.FindEndStepDefine();
  703. var nextDto = _mapper.Map<NextWorkflowDto>(dto);
  704. nextDto.ReviewResult = EReviewResult.Failed;
  705. nextDto.NextStepCode = endStepDefine.Code;
  706. nextDto.NextStepName = endStepDefine.Name;
  707. nextDto.FlowDirection = _sessionContextProvider.SessionContext.OrgIsCenter
  708. ? EFlowDirection.CenterToFile
  709. : EFlowDirection.OrgToFile;
  710. await NextAsync(nextDto, cancellationToken: cancellationToken);
  711. }
  712. //供开启流程调用
  713. private async Task<List<NextStepOption>> GetConfigStepsAsync(
  714. EFlowType flowType,
  715. EStepType currentStepType,
  716. EBusinessType currentBusinessType,
  717. List<StepDefine> stepDefines,
  718. CancellationToken cancellationToken)
  719. {
  720. var stepOptions = new List<NextStepOption>();
  721. foreach (var stepDefine in stepDefines)
  722. {
  723. var nextStepOption = await GetConfigStepAsync(flowType, stepDefine, cancellationToken);
  724. nextStepOption.InputRealHandler = currentStepType == EStepType.Normal &&
  725. stepDefine.StepType is EStepType.Summary or EStepType.End;
  726. stepOptions.Add(nextStepOption);
  727. if (stepDefine.StepType is EStepType.End) continue;
  728. nextStepOption.FlowDirection = _workflowDomainService.GetFlowDirection(currentBusinessType, stepDefine.BusinessType);
  729. //stepOptions.Add(nextStepOption);
  730. }
  731. return stepOptions;
  732. }
  733. /// <summary>
  734. /// 办理流程调用(根据办理过程过滤汇总节点待选办理对象)
  735. /// </summary>
  736. private async Task<List<NextStepOption>> GetConfigStepsAsync(
  737. Workflow workflow,
  738. WorkflowStep currentStep,
  739. List<StepDefine> stepDefines,
  740. CancellationToken cancellationToken)
  741. {
  742. var stepOptions = new List<NextStepOption>();
  743. foreach (var stepDefine in stepDefines)
  744. {
  745. NextStepOption nextStepOption;
  746. //汇总节点只能选择对应节点办理对象
  747. if (workflow.FlowType is EFlowType.Handle && stepDefine.StepType is EStepType.Summary)
  748. {
  749. var handler = _workflowDomainService.GetSummaryTargetFlowStepHandler(workflow, stepDefine.SummaryTargetCode);
  750. nextStepOption = new NextStepOption
  751. {
  752. Key = stepDefine.Code,
  753. Value = stepDefine.Name,
  754. StepType = stepDefine.StepType,
  755. BusinessType = stepDefine.BusinessType,
  756. //HandlerType = stepDefine.HandlerType,
  757. HandlerType = EHandlerType.AssignedUser, //指定办理人(业务需求)
  758. Items = new List<FlowStepHandler> { handler } //handlers
  759. };
  760. }
  761. else
  762. {
  763. nextStepOption = await GetConfigStepAsync(workflow.FlowType, stepDefine, cancellationToken);
  764. }
  765. nextStepOption.InputRealHandler = currentStep.StepType == EStepType.Normal &&
  766. stepDefine.StepType is EStepType.Summary or EStepType.End;
  767. stepOptions.Add(nextStepOption);
  768. if (stepDefine.StepType is EStepType.End) continue;
  769. nextStepOption.FlowDirection = _workflowDomainService.GetFlowDirection(currentStep.BusinessType, stepDefine.BusinessType);
  770. }
  771. return stepOptions;
  772. }
  773. public async Task<NextStepOption> GetConfigStepAsync(EFlowType flowType, StepDefine stepDefine, CancellationToken cancellationToken)
  774. {
  775. var handlers = new List<FlowStepHandler>();
  776. if (stepDefine.StepType is EStepType.End)
  777. {
  778. return new NextStepOption
  779. {
  780. Key = stepDefine.Code,
  781. Value = stepDefine.Name,
  782. StepType = stepDefine.StepType,
  783. BusinessType = stepDefine.BusinessType,
  784. HandlerType = stepDefine.HandlerType,
  785. Items = handlers
  786. };
  787. }
  788. var orgId = _sessionContextProvider.SessionContext.RequiredOrgId;
  789. var levelOneOrgId = orgId.GetHigherOrgId();
  790. var isCenter = levelOneOrgId.IsCenter();
  791. switch (stepDefine.HandlerType)
  792. {
  793. case EHandlerType.AssignedUser:
  794. handlers = await _userRepository.Queryable()
  795. .Includes(d => d.Organization)
  796. .Where(d => stepDefine.HandlerTypeItems.Select(x => x.Key).Contains(d.Id))
  797. .Select(d => new FlowStepHandler
  798. {
  799. Key = d.Id,
  800. Value = d.Name,
  801. UserId = d.Id,
  802. Username = d.Name,
  803. OrgId = d.OrgId,
  804. OrgName = d.Organization.Name,
  805. })
  806. .ToListAsync(cancellationToken);
  807. break;
  808. case EHandlerType.AssignedOrg:
  809. handlers = await _organizeRepository.Queryable() //stepDefine.HandlerTypeItems;
  810. .Where(d => d.IsEnable && stepDefine.HandlerTypeItems.Select(x => x.Key).Contains(d.Id))
  811. .Select(d => new FlowStepHandler
  812. {
  813. Key = d.Id,
  814. Value = d.Name,
  815. OrgId = d.Id,
  816. OrgName = d.Name,
  817. })
  818. .ToListAsync(cancellationToken);
  819. break;
  820. case EHandlerType.Role:
  821. //当前操作人所属部门的下级部门并且属于配置包含角色
  822. var roles = await _roleRepository.Queryable()
  823. .Includes(d => d.Accounts.Where(x =>
  824. !x.IsDeleted && x.Status == EAccountStatus.Normal && x.AccountType == EAccountType.Personal).ToList(),
  825. x => x.User, s => s.Organization)
  826. .Where(d => stepDefine.HandlerTypeItems.Select(x => x.Key).Contains(d.Name))
  827. .ToListAsync(cancellationToken);
  828. _logger.LogInformation($"角色: {string.Join(",", roles.Select(d => d.Name))}");
  829. var users1 = roles.SelectMany(d => d.Accounts).Select(d => d.User);
  830. if (flowType is EFlowType.Handle)
  831. {
  832. //工单办理:除一级部门选择中心汇总(中心会签流程,返回topCountersignStep场景),其余只能选下级部门
  833. if (stepDefine.BusinessType is EBusinessType.Department &&
  834. stepDefine.StepType != EStepType.Summary)
  835. {
  836. users1 = users1.Where(d => d.OrgId.StartsWith(levelOneOrgId));
  837. }
  838. else if (stepDefine.BusinessType is EBusinessType.DepartmentLeader)
  839. {
  840. users1 = users1.Where(d => d.OrgId == orgId);
  841. }
  842. }
  843. var defineTypeItem = stepDefine.HandlerTypeItems.First();
  844. handlers = users1.Where(d => d != null && !string.IsNullOrEmpty(d.Id))
  845. .Select(d => new FlowStepHandler
  846. {
  847. Key = d.Id,
  848. Value = d.Name,
  849. UserId = d.Id,
  850. Username = d.Name,
  851. OrgId = d.OrgId,
  852. OrgName = d.Organization?.Name,
  853. RoleId = defineTypeItem.Key,
  854. RoleName = defineTypeItem.Value
  855. })
  856. .ToList();
  857. break;
  858. case EHandlerType.OrgLevel:
  859. //当前操作人所属部门的垂直部门并且属于配置orgLevel的部门
  860. var levels = stepDefine.HandlerTypeItems.Select(d => int.Parse(d.Key)).ToList();
  861. // var orgs1 = await _organizeRepository.Queryable()
  862. // .Where(d => d.IsEnable && levels.Contains(d.Level))
  863. // .WhereIF(!isCenter, d => d.Id.StartsWith(levelOneOrgId))
  864. // .ToListAsync(cancellationToken);
  865. _logger.LogInformation($"部门等级: {string.Join(",", levels)}");
  866. var query = _organizeRepository.Queryable()
  867. .Where(d => d.IsEnable);
  868. List<SystemOrganize> orgs1;
  869. if (isCenter)
  870. {
  871. orgs1 = await query
  872. .Where(d => levels.Contains(d.Level) && !d.IsCenter)
  873. .ToListAsync(cancellationToken);
  874. }
  875. else
  876. {
  877. var upLevels = levels.Where(d => d <= _sessionContextProvider.SessionContext.OrgLevel).ToList();
  878. var lowLevels = levels.Where(d => d > _sessionContextProvider.SessionContext.OrgLevel).ToList();
  879. orgs1 = await query
  880. .Where(d => (upLevels.Contains(d.Level) && d.Id.StartsWith(levelOneOrgId)) ||
  881. (lowLevels.Contains(d.Level) && d.Id.Contains(orgId)))
  882. .ToListAsync(cancellationToken);
  883. }
  884. handlers = orgs1.Select(d => new FlowStepHandler
  885. {
  886. Key = d.Id,
  887. Value = d.Name,
  888. OrgId = d.Id,
  889. OrgName = d.Name
  890. })
  891. .ToList();
  892. break;
  893. case EHandlerType.OrgType:
  894. var types = stepDefine.HandlerTypeItems.Select(d => d.Key)
  895. .Select(d => Enum.Parse<EOrgType>(d));
  896. var orgs2 = await _organizeRepository.Queryable()
  897. .Where(d => d.IsEnable && types.Contains(d.OrgType))
  898. .WhereIF(!isCenter, d => d.Id.StartsWith(levelOneOrgId))
  899. .ToListAsync(cancellationToken);
  900. handlers = orgs2.Select(d => new FlowStepHandler
  901. {
  902. Key = d.Id,
  903. Value = d.Name,
  904. OrgId = d.Id,
  905. OrgName = d.Name
  906. })
  907. .ToList();
  908. break;
  909. default:
  910. throw new ArgumentOutOfRangeException();
  911. }
  912. var success = int.TryParse(stepDefine.HandlerTypeItems.First().Key, out var level);
  913. int? orgLevel = success ? level : null;
  914. return new NextStepOption
  915. {
  916. Key = stepDefine.Code,
  917. Value = stepDefine.Name,
  918. StepType = stepDefine.StepType,
  919. BusinessType = stepDefine.BusinessType,
  920. HandlerType = stepDefine.HandlerType,
  921. OrgLevel = stepDefine.HandlerType is EHandlerType.OrgLevel ? orgLevel : null,
  922. Items = handlers
  923. };
  924. }
  925. private NextStepOption GetCsEndStepByTargetPrev(List<WorkflowStep> steps, WorkflowStep step)
  926. {
  927. var prevStep = steps.FirstOrDefault(d => d.Id == step.PrevStepId);
  928. if (prevStep is null)
  929. throw new UserFriendlyException("未查找到会签上级节点");
  930. var text = prevStep.HandlerOrgIsCenter.Value
  931. ? "热线中心会签汇总"
  932. : $"{prevStep.HandlerOrgId.CalcOrgLevel().ToChinese()}级部门会签汇总";
  933. var handlers = prevStep.Handlers
  934. .Where(d => d.Key == prevStep.HandlerId || d.Key == prevStep.HandlerOrgId).ToList();
  935. //var handler = prevStep.GetActualHandler()?.GetHandler();
  936. var handler = new FlowStepHandler
  937. {
  938. Key = prevStep.HandlerId,
  939. Value = prevStep.HandlerName,
  940. UserId = prevStep.HandlerId,
  941. Username = prevStep.HandlerName,
  942. OrgId = prevStep.HandlerOrgId,
  943. OrgName = prevStep.HandlerOrgName
  944. };
  945. return new NextStepOption
  946. {
  947. Key = prevStep.Code,
  948. Value = text,
  949. BackToCountersignEnd = true,
  950. StepType = EStepType.Summary,
  951. BusinessType = prevStep.BusinessType,
  952. //HandlerType = prevStep.HandlerType,
  953. HandlerType = EHandlerType.AssignedUser, //指定办理人(业务需求)
  954. Items = new List<FlowStepHandler> { handler } //handlers //new List<Kv> { new(prevStep.HandlerId, prevStep.HandlerName) },
  955. };
  956. }
  957. /// <summary>
  958. /// 依据当前操作人及动态策略生成下一步节点
  959. /// </summary>
  960. private NextStepOption CreateDynamicStep(EDynamicPolicy policy)
  961. {
  962. int orgLevel;
  963. switch (policy)
  964. {
  965. case EDynamicPolicy.OrgUpCenterTop:
  966. orgLevel = _sessionContextProvider.SessionContext.OrgLevel - 1;
  967. if (orgLevel < 0) orgLevel = 0;
  968. break;
  969. case EDynamicPolicy.OrgUp:
  970. orgLevel = _sessionContextProvider.SessionContext.OrgLevel - 1;
  971. if (orgLevel <= 0) orgLevel = 1;
  972. break;
  973. case EDynamicPolicy.OrgDownCenterTop:
  974. orgLevel = _sessionContextProvider.SessionContext.OrgIsCenter
  975. ? 1
  976. : _sessionContextProvider.SessionContext.OrgLevel + 1;
  977. break;
  978. case EDynamicPolicy.OrgDown:
  979. orgLevel = _sessionContextProvider.SessionContext.OrgLevel + 1;
  980. break;
  981. default:
  982. throw new ArgumentOutOfRangeException(nameof(policy), policy, null);
  983. }
  984. var centerOrgName = _systemSettingCacheManager.GetSetting(SettingConstants.CenterOrgName)?.SettingValue[0];
  985. return new NextStepOption
  986. {
  987. Key = orgLevel.ToString(),
  988. Value = orgLevel == 0 ? centerOrgName : $"{orgLevel.ToChinese()}级部门",
  989. };
  990. }
  991. /// <summary>
  992. /// 动态策略
  993. /// </summary>
  994. /// <returns></returns>
  995. /// <exception cref="ArgumentOutOfRangeException"></exception>
  996. private async Task<NextStepOption> GetDynamicStepAsync(
  997. EDynamicPolicy policy, EStepType stepType,
  998. EBusinessType currentBusinessType, string handleRoleCode, string leadRoleCode, CancellationToken cancellationToken)
  999. {
  1000. int orgLevel;
  1001. List<FlowStepHandler> items;
  1002. string upperOrgId;
  1003. EBusinessType businessType;
  1004. EFlowDirection? flowDirection = null;
  1005. bool isLead = false;
  1006. bool isSkip = false;
  1007. string roleId = string.Empty;
  1008. string roleName = string.Empty;
  1009. string handleRoleName = "经办人";
  1010. string leadRoleName = "领导";
  1011. EHandlerType handlerType = EHandlerType.OrgLevel;
  1012. switch (policy)
  1013. {
  1014. case EDynamicPolicy.OrgUpCenterTop:
  1015. orgLevel = _sessionContextProvider.SessionContext.OrgLevel - 1;
  1016. if (orgLevel < 0) orgLevel = 0;
  1017. if (orgLevel == 0)
  1018. {
  1019. businessType = EBusinessType.Send;
  1020. if (currentBusinessType == EBusinessType.Department)
  1021. flowDirection = EFlowDirection.OrgToCenter;
  1022. items = await _organizeRepository.Queryable()
  1023. .Where(d => d.IsCenter)
  1024. .Select(d => new FlowStepHandler
  1025. {
  1026. Key = d.Id,
  1027. Value = d.Name,
  1028. OrgId = d.Id,
  1029. OrgName = d.Name
  1030. })
  1031. .ToListAsync(cancellationToken);
  1032. }
  1033. else
  1034. {
  1035. businessType = EBusinessType.Department;
  1036. //上级部门Id
  1037. upperOrgId = _sessionContextProvider.SessionContext.RequiredOrgId.GetHigherOrgId(orgLevel);
  1038. items = await _organizeRepository.Queryable()
  1039. .Where(d => d.Id == upperOrgId)
  1040. .Select(d => new FlowStepHandler
  1041. {
  1042. Key = d.Id,
  1043. Value = d.Name,
  1044. OrgId = d.Id,
  1045. OrgName = d.Name
  1046. })
  1047. .ToListAsync(cancellationToken);
  1048. }
  1049. break;
  1050. case EDynamicPolicy.OrgUp:
  1051. businessType = _sessionContextProvider.SessionContext.OrgIsCenter
  1052. ? EBusinessType.Send
  1053. : _sessionContextProvider.SessionContext.RequiredOrgId.CalcOrgLevel() == 1
  1054. ? EBusinessType.Send
  1055. : EBusinessType.Department;
  1056. orgLevel = _sessionContextProvider.SessionContext.OrgLevel - 1;
  1057. if (orgLevel <= 0) orgLevel = 1;
  1058. //上级部门Id
  1059. upperOrgId = _sessionContextProvider.SessionContext.RequiredOrgId.GetHigherOrgId(orgLevel);
  1060. items = await _organizeRepository.Queryable()
  1061. .Where(d => d.Id == upperOrgId)
  1062. .Select(d => new FlowStepHandler
  1063. {
  1064. Key = d.Id,
  1065. Value = d.Name,
  1066. OrgId = d.Id,
  1067. OrgName = d.Name
  1068. })
  1069. .ToListAsync(cancellationToken);
  1070. break;
  1071. case EDynamicPolicy.OrgUpHandleCenterTop:
  1072. orgLevel = _sessionContextProvider.SessionContext.OrgLevel - 1;
  1073. if (orgLevel < 0) orgLevel = 0;
  1074. if (orgLevel == 0)
  1075. {
  1076. businessType = EBusinessType.Send;
  1077. if (currentBusinessType == EBusinessType.Department)
  1078. flowDirection = EFlowDirection.OrgToCenter;
  1079. items = await _organizeRepository.Queryable()
  1080. .Where(d => d.IsCenter)
  1081. .Select(d => new FlowStepHandler
  1082. {
  1083. Key = d.Id,
  1084. Value = d.Name,
  1085. OrgId = d.Id,
  1086. OrgName = d.Name
  1087. })
  1088. .ToListAsync(cancellationToken);
  1089. }
  1090. else
  1091. {
  1092. businessType = EBusinessType.Department;
  1093. roleName = handleRoleName;
  1094. //上级部门Id
  1095. upperOrgId = _sessionContextProvider.SessionContext.RequiredOrgId.GetHigherOrgId(orgLevel);
  1096. items = await _organizeRepository.Queryable()
  1097. .Where(d => d.Id == upperOrgId)
  1098. .Select(d => new FlowStepHandler
  1099. {
  1100. Key = d.Id,
  1101. Value = d.Name,
  1102. OrgId = d.Id,
  1103. OrgName = d.Name,
  1104. RoleId = handleRoleCode,
  1105. RoleName = handleRoleName,
  1106. })
  1107. .ToListAsync(cancellationToken);
  1108. }
  1109. break;
  1110. case EDynamicPolicy.OrgUpHandle:
  1111. businessType = _sessionContextProvider.SessionContext.OrgIsCenter
  1112. ? EBusinessType.Send
  1113. : _sessionContextProvider.SessionContext.RequiredOrgId.CalcOrgLevel() == 1
  1114. ? EBusinessType.Send
  1115. : EBusinessType.Department;
  1116. orgLevel = _sessionContextProvider.SessionContext.OrgLevel - 1;
  1117. if (orgLevel <= 0) orgLevel = 1;
  1118. roleName = handleRoleName;
  1119. //上级部门Id
  1120. upperOrgId = _sessionContextProvider.SessionContext.RequiredOrgId.GetHigherOrgId(orgLevel);
  1121. items = await _organizeRepository.Queryable()
  1122. .Where(d => d.Id == upperOrgId)
  1123. .Select(d => new FlowStepHandler
  1124. {
  1125. Key = d.Id,
  1126. Value = d.Name,
  1127. OrgId = d.Id,
  1128. OrgName = d.Name,
  1129. RoleId = handleRoleCode,
  1130. RoleName = handleRoleName,
  1131. })
  1132. .ToListAsync(cancellationToken);
  1133. break;
  1134. case EDynamicPolicy.OrgUpLeadCenterTop:
  1135. orgLevel = _sessionContextProvider.SessionContext.OrgLevel - 1;
  1136. if (orgLevel < 0) orgLevel = 0;
  1137. isLead = _sessionContextProvider.SessionContext.Roles.Any(x => x == leadRoleCode);
  1138. isSkip = await _userRepository.Queryable()
  1139. .AnyAsync(x => x.OrgId == _sessionContextProvider.SessionContext.RequiredOrgId && x.Roles.Any(r => r.Name == leadRoleCode),
  1140. cancellationToken);
  1141. if (orgLevel == 0 && (isLead || !isSkip))
  1142. {
  1143. businessType = EBusinessType.Send;
  1144. if (currentBusinessType == EBusinessType.Department)
  1145. flowDirection = EFlowDirection.OrgToCenter;
  1146. items = await _organizeRepository.Queryable()
  1147. .Where(d => d.IsCenter)
  1148. .Select(d => new FlowStepHandler
  1149. {
  1150. Key = d.Id,
  1151. Value = d.Name,
  1152. OrgId = d.Id,
  1153. OrgName = d.Name
  1154. })
  1155. .ToListAsync(cancellationToken);
  1156. }
  1157. else
  1158. {
  1159. businessType = EBusinessType.Department;
  1160. upperOrgId = _sessionContextProvider.SessionContext.RequiredOrgId.GetHigherOrgId(_sessionContextProvider.SessionContext.OrgLevel);
  1161. if (!isLead)
  1162. {
  1163. if (isSkip)
  1164. {
  1165. roleId = leadRoleCode;
  1166. roleName = leadRoleName;
  1167. }
  1168. }
  1169. if (isLead || !isSkip)
  1170. {
  1171. //上级部门Id
  1172. upperOrgId = _sessionContextProvider.SessionContext.RequiredOrgId.GetHigherOrgId(orgLevel);
  1173. roleId = handleRoleCode;
  1174. roleName = handleRoleName;
  1175. }
  1176. else
  1177. {
  1178. orgLevel += 1;
  1179. }
  1180. items = await _organizeRepository.Queryable()
  1181. .Where(d => d.Id == upperOrgId)
  1182. .Select(d => new FlowStepHandler
  1183. {
  1184. Key = d.Id,
  1185. Value = d.Name,
  1186. OrgId = d.Id,
  1187. OrgName = d.Name,
  1188. RoleId = roleId,
  1189. RoleName = roleName
  1190. })
  1191. .ToListAsync(cancellationToken);
  1192. }
  1193. break;
  1194. case EDynamicPolicy.OrgUpLead:
  1195. businessType = _sessionContextProvider.SessionContext.OrgIsCenter
  1196. ? EBusinessType.Send
  1197. : _sessionContextProvider.SessionContext.RequiredOrgId.CalcOrgLevel() == 1
  1198. ? EBusinessType.Send
  1199. : EBusinessType.Department;
  1200. orgLevel = _sessionContextProvider.SessionContext.OrgLevel - 1;
  1201. if (orgLevel <= 0) orgLevel = 1;
  1202. upperOrgId = _sessionContextProvider.SessionContext.RequiredOrgId.GetHigherOrgId(_sessionContextProvider.SessionContext.OrgLevel);
  1203. isLead = _sessionContextProvider.SessionContext.Roles.Any(x => x == leadRoleCode);
  1204. if (!isLead)
  1205. {
  1206. isSkip = await _userRepository.Queryable()
  1207. .AnyAsync(x => x.OrgId == _sessionContextProvider.SessionContext.RequiredOrgId && x.Roles.Any(r => r.Name == leadRoleCode),
  1208. cancellationToken);
  1209. if (isSkip)
  1210. {
  1211. roleId = leadRoleCode;
  1212. roleName = leadRoleName;
  1213. }
  1214. }
  1215. if (isLead || !isSkip)
  1216. {
  1217. //上级部门Id
  1218. upperOrgId = _sessionContextProvider.SessionContext.RequiredOrgId.GetHigherOrgId(orgLevel);
  1219. roleId = handleRoleCode;
  1220. roleName = handleRoleName;
  1221. }
  1222. else
  1223. {
  1224. orgLevel += 1;
  1225. }
  1226. items = await _organizeRepository.Queryable()
  1227. .Where(d => d.Id == upperOrgId)
  1228. .Select(d => new FlowStepHandler
  1229. {
  1230. Key = d.Id,
  1231. Value = d.Name,
  1232. OrgId = d.Id,
  1233. OrgName = d.Name,
  1234. RoleId = roleId,
  1235. RoleName = roleName
  1236. })
  1237. .ToListAsync(cancellationToken);
  1238. break;
  1239. case EDynamicPolicy.ArriveCenter:
  1240. businessType = _sessionContextProvider.SessionContext.OrgIsCenter
  1241. ? EBusinessType.Send
  1242. : _sessionContextProvider.SessionContext.RequiredOrgId.CalcOrgLevel() == 1
  1243. ? EBusinessType.Send
  1244. : EBusinessType.Department;
  1245. orgLevel = _sessionContextProvider.SessionContext.OrgLevel - 1;
  1246. if (orgLevel <= 0) orgLevel = 1;
  1247. items = await _organizeRepository.Queryable()
  1248. .Where(d => d.IsCenter)
  1249. .Select(d => new FlowStepHandler
  1250. {
  1251. Key = d.Id,
  1252. Value = d.Name,
  1253. OrgId = d.Id,
  1254. OrgName = d.Name
  1255. })
  1256. .ToListAsync(cancellationToken);
  1257. break;
  1258. case EDynamicPolicy.ArriveOneOrg:
  1259. businessType = _sessionContextProvider.SessionContext.OrgIsCenter ? EBusinessType.Send : EBusinessType.Department;
  1260. orgLevel = _sessionContextProvider.SessionContext.OrgIsCenter ? 0 : 1;
  1261. //上级部门Id
  1262. upperOrgId = _sessionContextProvider.SessionContext.OrgIsCenter
  1263. ? _sessionContextProvider.SessionContext.RequiredOrgId.Substring(0, 3)
  1264. : _sessionContextProvider.SessionContext.RequiredOrgId.Substring(0, 6);
  1265. items = await _organizeRepository.Queryable()
  1266. .Where(d => d.Id == upperOrgId)
  1267. .Select(d => new FlowStepHandler
  1268. {
  1269. Key = d.Id,
  1270. Value = d.Name,
  1271. OrgId = d.Id,
  1272. OrgName = d.Name
  1273. })
  1274. .ToListAsync(cancellationToken);
  1275. break;
  1276. case EDynamicPolicy.OrgDownCenterTop:
  1277. businessType = EBusinessType.Department;
  1278. if (_sessionContextProvider.SessionContext.OrgIsCenter)
  1279. {
  1280. orgLevel = 1;
  1281. items = await _organizeRepository.Queryable()
  1282. .Where(d => !d.IsCenter && d.Level == orgLevel)
  1283. .Select(d => new FlowStepHandler
  1284. {
  1285. Key = d.Id,
  1286. Value = d.Name,
  1287. OrgId = d.Id,
  1288. OrgName = d.Name
  1289. })
  1290. .ToListAsync(cancellationToken);
  1291. }
  1292. else
  1293. {
  1294. orgLevel = _sessionContextProvider.SessionContext.OrgLevel + 1;
  1295. items = await _organizeRepository.Queryable()
  1296. .Where(d => !d.IsCenter && d.Level == orgLevel &&
  1297. d.Id.StartsWith(_sessionContextProvider.SessionContext.RequiredOrgId))
  1298. .Select(d => new FlowStepHandler
  1299. {
  1300. Key = d.Id,
  1301. Value = d.Name,
  1302. OrgId = d.Id,
  1303. OrgName = d.Name
  1304. })
  1305. .ToListAsync(cancellationToken);
  1306. }
  1307. break;
  1308. case EDynamicPolicy.OrgDown:
  1309. businessType = EBusinessType.Department;
  1310. orgLevel = _sessionContextProvider.SessionContext.OrgLevel + 1;
  1311. items = await _organizeRepository.Queryable()
  1312. .Where(d => d.Level == orgLevel && d.Id.StartsWith(_sessionContextProvider.SessionContext.RequiredOrgId))
  1313. .Select(d => new FlowStepHandler
  1314. {
  1315. Key = d.Id,
  1316. Value = d.Name,
  1317. OrgId = d.Id,
  1318. OrgName = d.Name
  1319. })
  1320. .ToListAsync(cancellationToken);
  1321. break;
  1322. default:
  1323. throw new ArgumentOutOfRangeException(nameof(policy), policy, null);
  1324. }
  1325. var centerOrgName = _systemSettingCacheManager.GetSetting(SettingConstants.CenterOrgName)?.SettingValue[0];
  1326. return new NextStepOption
  1327. {
  1328. Key = orgLevel.ToString(),
  1329. Value = orgLevel == 0 ? centerOrgName : $"{orgLevel.ToChinese()}级部门 {roleName}",
  1330. FlowDirection = flowDirection,
  1331. StepType = stepType,
  1332. BusinessType = businessType,
  1333. HandlerType = handlerType, //目前所有动态策略均属于部门等级
  1334. Items = items
  1335. };
  1336. }
  1337. /// <summary>
  1338. /// 会签 动态策略
  1339. /// </summary>
  1340. /// <returns></returns>
  1341. private async Task<NextStepOption> GetDynamicStepAsync(
  1342. ECountersignPolicy policy, EStepType stepType,
  1343. EBusinessType currentBusinessType, CancellationToken cancellationToken)
  1344. {
  1345. int orgLevel;
  1346. List<FlowStepHandler> items;
  1347. string upperOrgId;
  1348. EBusinessType businessType;
  1349. EFlowDirection? flowDirection = null;
  1350. switch (policy)
  1351. {
  1352. case ECountersignPolicy.OrgUpCenterTop:
  1353. orgLevel = _sessionContextProvider.SessionContext.OrgLevel - 1;
  1354. if (orgLevel < 0) orgLevel = 0;
  1355. if (orgLevel == 0)
  1356. {
  1357. businessType = EBusinessType.Send;
  1358. if (currentBusinessType == EBusinessType.Department)
  1359. flowDirection = EFlowDirection.OrgToCenter;
  1360. items = await _organizeRepository.Queryable()
  1361. .Where(d => d.IsCenter)
  1362. .Select(d => new FlowStepHandler
  1363. {
  1364. Key = d.Id,
  1365. Value = d.Name,
  1366. OrgId = d.Id,
  1367. OrgName = d.Name
  1368. })
  1369. .ToListAsync(cancellationToken);
  1370. }
  1371. else
  1372. {
  1373. businessType = EBusinessType.Department;
  1374. //上级部门Id
  1375. upperOrgId = _sessionContextProvider.SessionContext.RequiredOrgId.GetHigherOrgId(orgLevel);
  1376. items = await _organizeRepository.Queryable()
  1377. .Where(d => d.Id == upperOrgId)
  1378. .Select(d => new FlowStepHandler
  1379. {
  1380. Key = d.Id,
  1381. Value = d.Name,
  1382. OrgId = d.Id,
  1383. OrgName = d.Name
  1384. })
  1385. .ToListAsync(cancellationToken);
  1386. }
  1387. break;
  1388. case ECountersignPolicy.OrgUp:
  1389. businessType = _sessionContextProvider.SessionContext.OrgIsCenter
  1390. ? EBusinessType.Send
  1391. : _sessionContextProvider.SessionContext.RequiredOrgId.CalcOrgLevel() == 1
  1392. ? EBusinessType.Send
  1393. : EBusinessType.Department;
  1394. orgLevel = _sessionContextProvider.SessionContext.OrgLevel - 1;
  1395. if (orgLevel <= 0) orgLevel = 1;
  1396. //上级部门Id
  1397. upperOrgId = _sessionContextProvider.SessionContext.RequiredOrgId.GetHigherOrgId(orgLevel);
  1398. items = await _organizeRepository.Queryable()
  1399. .Where(d => d.Id == upperOrgId)
  1400. .Select(d => new FlowStepHandler
  1401. {
  1402. Key = d.Id,
  1403. Value = d.Name,
  1404. OrgId = d.Id,
  1405. OrgName = d.Name
  1406. })
  1407. .ToListAsync(cancellationToken);
  1408. break;
  1409. case ECountersignPolicy.OrgDownCenterTop:
  1410. businessType = EBusinessType.Department;
  1411. if (_sessionContextProvider.SessionContext.OrgIsCenter)
  1412. {
  1413. orgLevel = 1;
  1414. items = await _organizeRepository.Queryable()
  1415. .Where(d => !d.IsCenter && d.Level == orgLevel)
  1416. .Select(d => new FlowStepHandler
  1417. {
  1418. Key = d.Id,
  1419. Value = d.Name,
  1420. OrgId = d.Id,
  1421. OrgName = d.Name
  1422. })
  1423. .ToListAsync(cancellationToken);
  1424. }
  1425. else
  1426. {
  1427. orgLevel = _sessionContextProvider.SessionContext.OrgLevel + 1;
  1428. items = await _organizeRepository.Queryable()
  1429. .Where(d => !d.IsCenter && d.Level == orgLevel &&
  1430. d.Id.StartsWith(_sessionContextProvider.SessionContext.RequiredOrgId))
  1431. .Select(d => new FlowStepHandler
  1432. {
  1433. Key = d.Id,
  1434. Value = d.Name,
  1435. OrgId = d.Id,
  1436. OrgName = d.Name
  1437. })
  1438. .ToListAsync(cancellationToken);
  1439. }
  1440. break;
  1441. case ECountersignPolicy.OrgDown:
  1442. businessType = EBusinessType.Department;
  1443. orgLevel = _sessionContextProvider.SessionContext.OrgLevel + 1;
  1444. items = await _organizeRepository.Queryable()
  1445. .Where(d => d.Level == orgLevel && d.Id.StartsWith(_sessionContextProvider.SessionContext.RequiredOrgId))
  1446. .Select(d => new FlowStepHandler
  1447. {
  1448. Key = d.Id,
  1449. Value = d.Name,
  1450. OrgId = d.Id,
  1451. OrgName = d.Name
  1452. })
  1453. .ToListAsync(cancellationToken);
  1454. break;
  1455. default:
  1456. throw new ArgumentOutOfRangeException(nameof(policy), policy, null);
  1457. }
  1458. var centerOrgName = _systemSettingCacheManager.GetSetting(SettingConstants.CenterOrgName)?.SettingValue[0];
  1459. return new NextStepOption
  1460. {
  1461. Key = orgLevel.ToString(),
  1462. Value = orgLevel == 0 ? centerOrgName : $"{orgLevel.ToChinese()}级部门",
  1463. FlowDirection = flowDirection,
  1464. StepType = stepType,
  1465. BusinessType = businessType,
  1466. HandlerType = EHandlerType.OrgLevel, //目前所有动态策略均属于部门等级
  1467. Items = items
  1468. };
  1469. }
  1470. /// <summary>
  1471. /// 查询下一节点办理对象类型(user or org)及实际办理对象
  1472. /// </summary>
  1473. public async Task<FlowAssignInfo> GetNextStepFlowAssignInfoAsync(Workflow workflow, WorkflowStep currentStep,
  1474. BasicWorkflowDto dto, StepDefine nextStepDefine, bool isNextDynamic, CancellationToken cancellationToken)
  1475. {
  1476. if (nextStepDefine.StepType is EStepType.End) return new();
  1477. var isStartCountersign = dto.IsStartCountersign;
  1478. var handlers = dto.NextHandlers.Select(d => new Kv(d.Key, d.Value)).ToList();
  1479. if (isStartCountersign)
  1480. {
  1481. var assignType = FlowAssignInfo.GetAssignType(dto.HandlerType, dto.NextHandlers.Any());
  1482. //按会签策略判断,目前所有策略为org
  1483. return FlowAssignInfo.Create(assignType, handlers, isStartCountersign);
  1484. }
  1485. //if (currentStep.IsInCountersign() && !currentStep.IsTopCountersignEndStep(workflow.TopCountersignStepId))
  1486. // return FlowAssignInfo.Create(EFlowAssignType.Org, handlers, isStartCountersign);
  1487. if (currentStep.IsInCountersign())
  1488. {
  1489. if (currentStep.IsCountersignEndStep)
  1490. {
  1491. //汇总节点(非顶级)
  1492. if (!currentStep.IsTopCountersignEndStep(workflow.TopCountersignStepId))
  1493. {
  1494. if (dto.BackToCountersignEnd)
  1495. {
  1496. var csStartStep = GetCsLoopStartStep(workflow, currentStep);
  1497. var prevStep = workflow.Steps.FirstOrDefault(d => d.Id == csStartStep.PrevStepId);
  1498. if (prevStep is null)
  1499. throw new UserFriendlyException("未查询到目标节点的前一节点");
  1500. return FlowAssignInfo.Create(prevStep.FlowAssignType.Value, prevStep.Handlers, isStartCountersign);
  1501. }
  1502. }
  1503. }
  1504. else
  1505. {
  1506. if (dto.BackToCountersignEnd)
  1507. {
  1508. var prevStep = workflow.Steps.FirstOrDefault(d => d.Id == currentStep.PrevStepId);
  1509. if (prevStep is null)
  1510. throw new UserFriendlyException($"未查询到当前节点的上级节点");
  1511. return FlowAssignInfo.Create(prevStep.FlowAssignType.Value, prevStep.Handlers, isStartCountersign);
  1512. }
  1513. else
  1514. {
  1515. var assignType = FlowAssignInfo.GetAssignType(dto.HandlerType, dto.NextHandlers.Any());
  1516. //按会签策略判断,目前所有策略为org
  1517. return FlowAssignInfo.Create(assignType, handlers, isStartCountersign);
  1518. }
  1519. }
  1520. }
  1521. if (isNextDynamic)
  1522. {
  1523. switch (currentStep.InstancePolicy)
  1524. {
  1525. case EDynamicPolicy.OrgUpCenterTop:
  1526. case EDynamicPolicy.OrgUp:
  1527. case EDynamicPolicy.OrgDownCenterTop:
  1528. case EDynamicPolicy.OrgDown:
  1529. case EDynamicPolicy.ArriveCenter:
  1530. case EDynamicPolicy.ArriveOneOrg:
  1531. return FlowAssignInfo.Create(EFlowAssignType.Org, handlers, isStartCountersign);
  1532. case EDynamicPolicy.OrgUpHandleCenterTop:
  1533. case EDynamicPolicy.OrgUpHandle:
  1534. case EDynamicPolicy.OrgUpLeadCenterTop:
  1535. case EDynamicPolicy.OrgUpLead:
  1536. return FlowAssignInfo.Create(EFlowAssignType.OrgAndRole, handlers, isStartCountersign);
  1537. default:
  1538. throw new ArgumentOutOfRangeException();
  1539. }
  1540. }
  1541. return await GetNextStepFlowAssignInfoByDefineAsync(nextStepDefine, dto.HandlerType, isStartCountersign, handlers,
  1542. cancellationToken);
  1543. }
  1544. /// <summary>
  1545. /// 按流程模板配置创建下一步办理对象
  1546. /// </summary>
  1547. private async Task<FlowAssignInfo> GetNextStepFlowAssignInfoByDefineAsync(StepDefine nextStepDefine,
  1548. EHandlerType handlerType, bool isStartCountersign, List<Kv> handlers, CancellationToken cancellationToken)
  1549. {
  1550. switch (handlerType)
  1551. {
  1552. case EHandlerType.Role:
  1553. if (!handlers.Any())
  1554. {
  1555. //var roles = await _roleRepository.Queryable()
  1556. // .Includes(d => d.Accounts, x => x.User)
  1557. // .Where(d => nextStepDefine.HandlerTypeItems.Select(x => x.Key).Contains(d.Name))
  1558. // .ToListAsync(cancellationToken);
  1559. //handlers = roles.SelectMany(d => d.Accounts).Distinct()
  1560. // .Select(d => new Kv(d.Id, d.User.Name))
  1561. // .ToList();
  1562. handlers = nextStepDefine.HandlerTypeItems;
  1563. return FlowAssignInfo.Create(EFlowAssignType.Role, handlers, isStartCountersign);
  1564. }
  1565. return FlowAssignInfo.Create(EFlowAssignType.User, handlers, isStartCountersign);
  1566. case EHandlerType.OrgLevel:
  1567. case EHandlerType.OrgType:
  1568. case EHandlerType.AssignedOrg:
  1569. return FlowAssignInfo.Create(EFlowAssignType.Org, handlers, isStartCountersign);
  1570. case EHandlerType.AssignedUser:
  1571. return FlowAssignInfo.Create(EFlowAssignType.User, handlers, isStartCountersign);
  1572. //case EHandlerType.AssignedOrgOrRole:
  1573. // return FlowAssignInfo.Create(EFlowAssignType.OrgAndRole, handlers, isStartCountersign);
  1574. default:
  1575. throw new ArgumentOutOfRangeException();
  1576. }
  1577. }
  1578. public ISugarQueryable<WorkflowCountersign,Workflow,Order> QueryOrderCountersigns(QueryOrderCountersignDto dto, ISessionContext _sessionContext)
  1579. {
  1580. var Role = _sessionContext.Roles;
  1581. var query = _workflowCountersignRepository.Queryable()
  1582. .Includes(x => x.Members)
  1583. .LeftJoin<Workflow>((c, w) => c.WorkflowId == w.Id)
  1584. .InnerJoin<Order>((c, w, o) => w.ExternalId == o.Id)
  1585. .WhereIF(!string.IsNullOrEmpty(dto.Title), (c, w, o) => o.Title.Contains(dto.Title))
  1586. .WhereIF(!string.IsNullOrEmpty(dto.OrderNo), (c, w, o) => o.No == dto.OrderNo)
  1587. .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), (c, w, o) => o.AcceptTypeCode == dto.AcceptType)//受理类型
  1588. .WhereIF(!string.IsNullOrEmpty(dto.Channel), (c, w, o) => o.SourceChannelCode == dto.Channel)//受理类型
  1589. .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), (c, w, o) => o.HotspotSpliceName != null && o.HotspotSpliceName.Contains(dto.Hotspot))//热点类型
  1590. .WhereIF(!string.IsNullOrEmpty(dto.OrgId), (c, w, o) => c.FinisherOrgId == dto.OrgId) //接办部门
  1591. .WhereIF(dto.CounterSignType != null, (c, w, o) => c.CounterSignType == dto.CounterSignType) //会签类型
  1592. ;
  1593. var rolePaiDan = _systemSettingCacheManager.GetSetting(SettingConstants.RolePaiDan)?.SettingValue[0];//派单员角色
  1594. var seatsMonitor = _systemSettingCacheManager.GetSetting(SettingConstants.SeatsMonitor)?.SettingValue[0];//班长角色
  1595. var isAdmin = false;
  1596. var systemAdministrator = _systemSettingCacheManager.GetSetting(SettingConstants.SystemAdministrator)?.SettingValue[0];//管理员角色
  1597. if (!string.IsNullOrEmpty(systemAdministrator) && (_sessionContext.Roles.Contains(systemAdministrator) || _sessionContext.Roles.Contains(RoleSeedData.AdminRole)))
  1598. isAdmin = true;
  1599. //发起会签:班长角色能看所有会签信件;新增管理员能看到所有会签
  1600. //派单员角色只能看到自己发起的会签信件;
  1601. //承办部门用户能看到自己发起的和同级部门用户发起的会签件
  1602. if (dto.InitiatedCountersignature.HasValue && dto.InitiatedCountersignature == true)
  1603. {
  1604. if (_sessionContext.Roles.Any(p => p == seatsMonitor) || isAdmin)
  1605. {
  1606. }
  1607. else
  1608. if (_sessionContext.Roles.Any(p => p == rolePaiDan))
  1609. {
  1610. query = query.Where((c, w, o) => c.StarterId == _sessionContext.UserId);
  1611. }
  1612. else
  1613. {
  1614. query = query.Where((c, w, o) => c.StarterOrgId == _sessionContext.RequiredOrgId);
  1615. }
  1616. }
  1617. //会签已办(会签状态为已结束):
  1618. //班长角色能看所有已结束的会签信件;新增管理员能看到所有会签
  1619. //派单员不会办理会签件只会发起会签件所以这一点派单员角色可以忽略;
  1620. //承办部门用户能看到和同级部门用户已办理过的会签件
  1621. if (dto.HandleCountersignature.HasValue && dto.HandleCountersignature == true)
  1622. {
  1623. if (_sessionContext.Roles.Any(p => p == seatsMonitor) || isAdmin)
  1624. {
  1625. query = query.Where((c, w, o) => c.EndTime.HasValue);
  1626. }
  1627. else
  1628. if (_sessionContext.Roles.Any(p => p == rolePaiDan))
  1629. {
  1630. query = query.Where((c, w, o) => c.Members.Any(m => m.Key == _sessionContext.RequiredOrgId) && c.EndTime.HasValue);
  1631. }
  1632. else
  1633. {
  1634. query = query.Where((c, w, o) => c.Members.Any(m => m.Key == _sessionContext.OrgId || m.Key == _sessionContext.RequiredOrgId) && c.EndTime.HasValue);
  1635. }
  1636. }
  1637. var items = query
  1638. .OrderByDescending((c, w, o) => o.ExpiredTime);
  1639. return items;
  1640. }
  1641. #region private
  1642. /// <summary>
  1643. /// 查询流程业务模块
  1644. /// </summary>
  1645. /// <param name="code"></param>
  1646. /// <param name="cancellationToken"></param>
  1647. /// <returns></returns>
  1648. /// <exception cref="UserFriendlyException"></exception>
  1649. public async Task<WorkflowModule> GetWorkflowModuleAsync(string code, CancellationToken cancellationToken)
  1650. {
  1651. var wfModule = await _wfModuleCacheManager.GetWorkflowModuleAsync(code, cancellationToken);
  1652. if (wfModule == null)
  1653. throw UserFriendlyException.SameMessage("无效流程模块编码");
  1654. if (wfModule.Definition is null)
  1655. throw new UserFriendlyException($"{code} 未配置流程模板", "未配置流程模板");
  1656. return wfModule;
  1657. }
  1658. /// <summary>
  1659. /// 检查退回节点信息
  1660. /// </summary>
  1661. public async Task<(WorkflowStep currentStep, WorkflowStep prevStep, bool isOrgToCenter, bool isSecondToFirstOrgLevel)>
  1662. GetPreviousInformationAsync(string workflowId, string operatorId, string operatorOrgId, string[] roles,
  1663. CancellationToken cancellationToken)
  1664. {
  1665. var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withSteps: true,
  1666. withCountersigns: true, cancellationToken: cancellationToken);
  1667. var (currentStep, prevStep, _) = _workflowDomainService.GetPreviousStep(workflow, operatorId, operatorOrgId, roles);
  1668. var isOrgToCenter = currentStep.BusinessType is EBusinessType.Department &&
  1669. prevStep.BusinessType is EBusinessType.Seat or EBusinessType.Send;
  1670. var isSecondToFirstOrgLevel = currentStep.HandlerType is EHandlerType.OrgLevel &&
  1671. currentStep.Handlers.First().Key.CheckIfOrgLevelIs(2) &&
  1672. prevStep.HandlerType is EHandlerType.OrgLevel &&
  1673. prevStep.Handlers.First().Key.CheckIfOrgLevelIs(1) &&
  1674. !prevStep.Handlers.First().Key.IsCenter();
  1675. return (currentStep, prevStep, isOrgToCenter, isSecondToFirstOrgLevel);
  1676. }
  1677. /// <summary>
  1678. /// 开启流程直接归档
  1679. /// </summary>
  1680. public async Task StartToEndAsync(StartWorkflowDto dto, string externalId, DateTime? expiredTime = null,
  1681. CancellationToken cancellationToken = default)
  1682. {
  1683. var wfModule = await GetWorkflowModuleAsync(dto.DefinitionModuleCode, cancellationToken);
  1684. var definition = wfModule.Definition;
  1685. if (definition == null)
  1686. throw new UserFriendlyException("无效模板编码");
  1687. if (definition.Status is not EDefinitionStatus.Enable)
  1688. throw new UserFriendlyException("该模板不可用");
  1689. var endStepDefine = definition.FindEndStepDefine();
  1690. dto.NextStepCode = endStepDefine.Code;
  1691. dto.NextStepName = endStepDefine.Name;
  1692. dto.FlowDirection = EFlowDirection.CenterToFile;
  1693. await StartWorkflowAsync(dto, externalId, expiredTime, cancellationToken);
  1694. }
  1695. /// <summary>
  1696. /// 更新省平台办理结果节点附件
  1697. /// </summary>
  1698. public async Task UpdateProvinceHandleResultFilesAsync(string workflowId, List<FileDto> files, CancellationToken cancellationToken)
  1699. {
  1700. var setting = _systemSettingCacheManager.GetSetting(SettingConstants.CityBaseConfiguration)?.SettingValue[0];
  1701. CityBaseConfiguration cityBase = JsonConvert.DeserializeObject<CityBaseConfiguration>(setting);
  1702. var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withSteps: true, withTraces: true,
  1703. cancellationToken: cancellationToken);
  1704. var step = workflow.Steps.FirstOrDefault(d =>
  1705. //d.StepHandlers.Any(d => d.OrgId == _cityBaseConfiguration.Value.CityProvince.OrgId || d.OrgId == _cityBaseConfiguration.Value.CityProvinceAssign.OrgId));
  1706. d.HandlerOrgId == cityBase.CityProvince.OrgId || d.HandlerOrgId == cityBase.CityProvinceAssign.OrgId);
  1707. if (step is not null)
  1708. {
  1709. step.FileJson = await _fileRepository.AddFileAsync(files, workflow.ExternalId, step.Id, cancellationToken);
  1710. var trace = workflow.Traces.First(d => d.StepId == step.Id);
  1711. trace.FileJson = step.FileJson;
  1712. await _workflowStepRepository.UpdateAsync(step, cancellationToken);
  1713. await _workflowTraceRepository.UpdateAsync(trace, cancellationToken);
  1714. }
  1715. }
  1716. #endregion
  1717. }