123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323 |
- using Hotline.Application.Contracts.Validators.FlowEngine;
- using Hotline.Caching.Interfaces;
- using Hotline.FlowEngine;
- using Hotline.FlowEngine.Definitions;
- using Hotline.FlowEngine.WorkflowModules;
- using Hotline.FlowEngine.Workflows;
- using Hotline.Identity.Accounts;
- using Hotline.Identity.Roles;
- using Hotline.Orders;
- using Hotline.Settings;
- using Hotline.Settings.TimeLimits;
- using Hotline.Share.Dtos;
- using Hotline.Share.Dtos.FlowEngine;
- using Hotline.Share.Dtos.FlowEngine.Definition;
- using Hotline.Share.Dtos.Settings;
- using Hotline.Share.Enums.FlowEngine;
- using Hotline.Share.Enums.Identity;
- using Hotline.Users;
- using MapsterMapper;
- using Hotline.File;
- using Hotline.Share.Enums.Settings;
- using XF.Domain.Authentications;
- using XF.Domain.Dependency;
- using XF.Domain.Entities;
- using XF.Domain.Exceptions;
- using XF.Domain.Extensions;
- using XF.Domain.Repository;
- using XF.Utility.EnumExtensions;
- using Hotline.Share.Dtos.File;
- using Microsoft.Extensions.Logging;
- using System.Text;
- using System.Diagnostics;
- namespace Hotline.Application.FlowEngine;
- public class WorkflowApplication : IWorkflowApplication, IScopeDependency
- {
- private readonly IDefinitionDomainService _definitionDomainService;
- private readonly IWorkflowDomainService _workflowDomainService;
- private readonly IOrderDomainService _orderDomainService;
- private readonly IWorkflowRepository _workflowRepository;
- private IRepository<WorkflowDefinition> _definitionRepository;
- private IRepository<WorkflowStep> _workflowStepRepository;
- private IRepository<WorkflowTrace> _workflowTraceRepository;
- private readonly IRepository<User> _userRepository;
- private readonly IAccountRepository _accountRepository;
- private readonly ISystemOrganizeRepository _organizeRepository;
- private readonly IRepository<Role> _roleRepository;
- private readonly IWfModuleCacheManager _wfModuleCacheManager;
- private readonly ISystemDomainService _systemDomainService;
- private readonly ITimeLimitDomainService _timeLimitDomainService;
- private readonly IUserDomainService _userDomainService;
- private readonly IAccountDomainService _accountDomainService;
- private readonly ISessionContext _sessionContext;
- private readonly IMapper _mapper;
- private readonly IFileRepository _fileRepository;
- private readonly ILogger<WorkflowApplication> _logger;
- public WorkflowApplication(
- IDefinitionDomainService definitionDomainService,
- IWorkflowDomainService workflowDomainService,
- IOrderDomainService orderDomainService,
- IWorkflowRepository workflowRepository,
- IRepository<WorkflowDefinition> definitionRepository,
- IRepository<WorkflowStep> workflowStepRepository,
- IRepository<WorkflowTrace> workflowTraceRepository,
- IRepository<User> userRepository,
- IAccountRepository accountRepository,
- ISystemOrganizeRepository organizeRepository,
- IRepository<Role> roleRepository,
- IWfModuleCacheManager wfModuleCacheManager,
- ISystemDomainService systemDomainService,
- ITimeLimitDomainService timeLimitDomainService,
- ISessionContext sessionContext,
- IMapper mapper,
- IFileRepository fileRepository,
- ILogger<WorkflowApplication> logger)
- {
- _definitionDomainService = definitionDomainService;
- _workflowDomainService = workflowDomainService;
- _orderDomainService = orderDomainService;
- _workflowRepository = workflowRepository;
- _definitionRepository = definitionRepository;
- _workflowStepRepository = workflowStepRepository;
- _workflowTraceRepository = workflowTraceRepository;
- _userRepository = userRepository;
- _accountRepository = accountRepository;
- _organizeRepository = organizeRepository;
- _roleRepository = roleRepository;
- _wfModuleCacheManager = wfModuleCacheManager;
- _systemDomainService = systemDomainService;
- _timeLimitDomainService = timeLimitDomainService;
- _sessionContext = sessionContext;
- _mapper = mapper;
- _fileRepository = fileRepository;
- _logger = logger;
- }
- public async Task<string> StartWorkflowAsync(StartWorkflowDto dto, ISessionContext current, string externalId,
- DateTime? expiredTime, CancellationToken cancellationToken = default)
- {
- var validator = new StartWorkflowDtoValidator();
- var validResult = await validator.ValidateAsync(dto, cancellationToken);
- if (!validResult.IsValid)
- throw new UserFriendlyException(
- $"非法参数, {string.Join(',', validResult.Errors.Select(d => d.ErrorMessage))}");
- var wfModule = await GetWorkflowModuleAsync(dto.DefinitionModuleCode, cancellationToken);
- var definition = wfModule.Definition;
- if (definition == null)
- throw new UserFriendlyException("无效模板编码");
- if (definition.Status is not EDefinitionStatus.Enable)
- throw new UserFriendlyException("该模板不可用");
- //如果发起会签需检查是否支持发起会签
- var startStepDefine = definition.FindStartStepDefine();
- //下一节点是否为动态节点
- var isNextDynamic = startStepDefine.InstanceMode is EInstanceMode.Dynamic &&
- !_workflowDomainService.DynamicShouldTerminal(startStepDefine, current.OrgLevel);
- var firstStepDefine = isNextDynamic
- ? startStepDefine
- : definition.FindStepDefine(dto.NextStepCode);
- if (firstStepDefine is null)
- throw new UserFriendlyException("未查询到下一步节点配置");
- //1. 如果不是按角色指派,handlers必填 2. 如果按角色指派,handlers可以不选
- if (firstStepDefine.HandlerType is not EHandlerType.Role && !dto.NextHandlers.Any())
- throw UserFriendlyException.SameMessage("未指派办理人");
- if (dto.IsStartCountersign)
- {
- if (!startStepDefine.CanStartCountersign)
- throw new UserFriendlyException("当前节点不支持发起会签");
- //if (startStepDefine.HandlerType is EHandlerType.Role)
- // throw new UserFriendlyException("当前节点不支持发起会签");
- //即使当前节点支持发起会签,但下一节点为信息汇总节点、结束节点时也不可发起会签
- if (firstStepDefine.StepType is EStepType.Summary or EStepType.End)
- throw new UserFriendlyException("下一节点不允许发起会签");
- //下一节点是会签汇总节点也不允许发起会签
- if (dto.BackToCountersignEnd)
- throw new UserFriendlyException("下一节点不允许发起会签");
- }
- var workflow = await _workflowDomainService.CreateWorkflowAsync(wfModule, dto.Title,
- current.RequiredUserId, current.RequiredOrgId,
- externalId, cancellationToken);
- //var startStepHandles = new List<WorkflowStepHandler>{WorkflowStepHandler.Create(workflow.Id, workflow.ExternalId,
- // EFlowAssignType.User, current.RequiredUserId, current.UserName,
- // current.RequiredOrgId, current.OrgName)};
- var startStep = _workflowDomainService.CreateStartStep(workflow, startStepDefine, dto,
- new FlowStepHandler
- {
- Key = current.RequiredUserId,
- Value = current.UserName,
- UserId = current.UserId,
- Username = current.UserName,
- OrgId = current.RequiredOrgId,
- OrgName = current.OrgName
- }, expiredTime);
- var flowAssignInfo =
- await GetNextStepFlowAssignInfoAsync(workflow, startStep, dto, firstStepDefine, isNextDynamic, cancellationToken);
- //var firstStepHandlers = await GetNextStepHandlersAsync(workflow, firstStepDefine, dto, cancellationToken);
- var counterSignType = _workflowDomainService.GetCounterSignType(startStep.BusinessType);
- //办理开始节点
- await _workflowDomainService.HandleStepAsync(current, startStep, workflow, dto, flowAssignInfo.FlowAssignType,
- counterSignType, expiredTime, cancellationToken);
- //startStep.Handle(current.RequiredUserId, current.UserName,
- // current.RequiredOrgId, current.OrgName,
- // current.OrgAreaCode, current.OrgAreaName,
- // current.OrgIsCenter, firstStepDefine.Code);
- if (dto.Files.Any())
- startStep.FileJson =
- await _fileRepository.AddFileAsync(dto.Files, workflow.ExternalId, startStep.Id, cancellationToken);
- await _workflowStepRepository.AddAsync(startStep, cancellationToken);
- //await _workflowStepRepository.AddNav(startStep)
- // .Include(d => d.StepHandlers)
- // .ExecuteCommandAsync();
- workflow.Steps.Add(startStep);
- //starttrace
- var startTrace = _mapper.Map<WorkflowTrace>(startStep);
- startTrace.StepId = startStep.Id;
- startTrace.TraceType = EWorkflowTraceType.Normal;
- _mapper.Map(dto, startTrace);
- await _workflowTraceRepository.AddAsync(startTrace, cancellationToken);
- workflow.Traces.Add(startTrace);
- //更新受理人信息
- workflow.UpdateAcceptor(
- current.RequiredUserId,
- current.UserName,
- current.StaffNo,
- current.RequiredOrgId,
- current.OrgName);
- await _workflowDomainService.StartAsync(workflow, startStep, dto, firstStepDefine, isNextDynamic,
- flowAssignInfo, counterSignType, expiredTime, current, cancellationToken);
- return workflow.Id;
- }
- /// <summary>
- /// 流转至下一节点(节点办理)
- /// </summary>
- public async Task<Workflow> NextAsync(NextWorkflowDto dto, ISessionContext current, DateTime? expiredTime = null,
- CancellationToken cancellationToken = default)
- {
- var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withDefine: true, withSteps: true,
- withTraces: true, withCountersigns: true, cancellationToken: cancellationToken);
- var currentStep = _workflowDomainService.FindCurrentStepWaitForHandle(workflow,
- current.RequiredUserId, current.RequiredOrgId, current.Roles);
- if (currentStep.Status is EWorkflowStepStatus.Handled)
- throw new UserFriendlyException("该状态不支持继续办理");
- var currentStepDefine = _workflowDomainService.GetStepDefine(workflow.WorkflowDefinition, currentStep.Code);
- //下一节点是否为动态节点
- var isNextDynamic = currentStepDefine.InstanceMode is EInstanceMode.Dynamic &&
- !_workflowDomainService.DynamicShouldTerminal(currentStepDefine, current.OrgLevel);
- StepDefine nextStepDefine;
- if (isNextDynamic
- || (currentStep.IsInCountersign() && !currentStep.IsTopCountersignEndStep(workflow.TopCountersignStepId))
- || dto.IsStartCountersign)
- {
- //下一步配置为当前节点配置
- nextStepDefine = currentStepDefine;
- }
- else
- {
- //下一步配置为下一步节点配置
- nextStepDefine = _workflowDomainService.GetStepDefine(workflow.WorkflowDefinition, dto.NextStepCode);
- }
- //需求:按角色选择办理人可以不选,表示该角色下所有人都可以办理,同时依据配置:是否本部门人办理显示待选办理人。角色下只要一人办理即可(即:角色下不发起会签)
- if (nextStepDefine.HandlerType != EHandlerType.Role && !dto.NextHandlers.Any())
- throw new UserFriendlyException("未指定节点处理者");
- if (dto.IsStartCountersign)
- {
- if (!currentStepDefine.CanStartCountersign)
- throw new UserFriendlyException("当前节点不支持发起会签");
- //if (currentStepDefine.HandlerType is EHandlerType.Role)
- // throw new UserFriendlyException("当前节点不支持发起会签");
- //即使当前节点支持发起会签,但下一节点为信息汇总节点、结束节点时也不可发起会签
- if (nextStepDefine.StepType is EStepType.Summary or EStepType.End)
- throw new UserFriendlyException("下一节点不允许发起会签");
- //下一节点是会签汇总节点也不允许发起会签
- if (dto.BackToCountersignEnd)
- throw new UserFriendlyException("下一节点不允许发起会签");
- }
- var flowAssignInfo =
- await GetNextStepFlowAssignInfoAsync(workflow, currentStep, dto, nextStepDefine, isNextDynamic, cancellationToken);
- //var nextStepHandlers = await GetNextStepHandlersAsync(workflow, nextStepDefine, dto, cancellationToken);
- await _workflowDomainService.NextAsync(workflow, currentStep, dto, nextStepDefine, isNextDynamic,
- flowAssignInfo, expiredTime, current, cancellationToken);
- return workflow;
- }
- /// <summary>
- /// 退回(返回前一节点)
- /// </summary>
- public async Task<EFlowDirection> PreviousAsync(PreviousWorkflowDto dto, CancellationToken cancellationToken)
- {
- var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withSteps: true,
- withTraces: true, withCountersigns: true, cancellationToken: cancellationToken);
- //var user = await _userRepository.Queryable()
- // .Includes(x => x.Organization)
- // .FirstAsync(x => x.Id == _sessionContext.RequiredUserId, cancellationToken);
- return await _workflowDomainService.PreviousAsync(workflow, dto,
- _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles,
- _sessionContext, cancellationToken);
- }
- /// <summary>
- /// 工单退回(返回前一节点)
- /// </summary>
- public async Task<EFlowDirection> PreviousAsync(PreviousWorkflowDto dto, string applicantId, string applicantOrgId, string[] applicantRoleIds,
- ISessionContext current, CancellationToken cancellationToken)
- {
- var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withSteps: true,
- withTraces: true, withCountersigns: true, cancellationToken: cancellationToken);
- return await _workflowDomainService.PreviousAsync(workflow, dto,
- applicantId, applicantOrgId, applicantRoleIds, _sessionContext, cancellationToken);
- }
- /// <summary>
- /// 撤回至任意节点
- /// </summary>
- public async Task RecallAsync(RecallDto dto, DateTime? expiredTime, CancellationToken cancellationToken)
- {
- var validator = new RecallDtoValidator();
- var validationResult = await validator.ValidateAsync(dto, cancellationToken);
- if (!validationResult.IsValid)
- throw new UserFriendlyException(string.Join(',', validationResult.Errors));
- var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withDefine: true, withSteps: true,
- withTraces: true, cancellationToken: cancellationToken);
- //await _orderDomainService.ReadyToRecallAsync(workflow.ExternalId, cancellationToken);
- var targetStepDefine = _workflowDomainService.GetStepDefine(workflow.WorkflowDefinition, dto.NextStepCode);
- if (targetStepDefine.StepType is EStepType.End)
- throw UserFriendlyException.SameMessage("结束节点不支持撤回");
- //var isStartCountersign = targetStepDefine.CouldPrevStartCountersign(dto.NextHandlers.Count);
- var flowAssignInfo = await GetNextStepFlowAssignInfoByDefineAsync(targetStepDefine, dto.IsStartCountersign,
- dto.NextHandlers.Select(d => new Kv(d.Key, d.Value)).ToList(), cancellationToken);
- //var stepHandlers = await GetNextStepHandlersAsync(workflow, targetStepDefine, dto, cancellationToken);
- await _workflowDomainService.RecallAsync(workflow, dto, targetStepDefine, flowAssignInfo, expiredTime, _sessionContext, cancellationToken);
- }
- /// <summary>
- /// 无视流程模板配置直接将当前节点办理至结束节点
- /// </summary>
- public async Task HandleToEndAsync(ISessionContext current, string workflowId, string opinion, List<FileDto> files,
- EReviewResult reviewResult = EReviewResult.Unknown, CancellationToken cancellationToken = default)
- {
- var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withDefine: true, withSteps: true,
- cancellationToken: cancellationToken);
- var endStepDefine = workflow.WorkflowDefinition.FindEndStepDefine();
- if (endStepDefine is null)
- throw new UserFriendlyException("未正确配置结束节点");
- var dto = new NextWorkflowDto
- {
- WorkflowId = workflowId,
- NextStepCode = endStepDefine.Code,
- NextStepName = endStepDefine.Name,
- FlowDirection = EFlowDirection.OrgToFile,
- BusinessType = endStepDefine.BusinessType,
- ReviewResult = reviewResult,
- Opinion = opinion,
- Files = files
- };
- await NextAsync(dto, current, cancellationToken: cancellationToken);
- }
- /// <summary>
- /// 跳转至结束节点(无视流程模板配置以及当前办理对象,直接跳至结束节点)
- /// </summary>
- public async Task JumpToEndAsync(ISessionContext current, string workflowId, string opinion, List<FileDto> files,
- EReviewResult reviewResult = EReviewResult.Unknown, CancellationToken cancellationToken = default)
- {
- var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withDefine: true, withSteps: true,
- withTraces: true, cancellationToken: cancellationToken);
- var endStepDefine = workflow.WorkflowDefinition.FindEndStepDefine();
- if (endStepDefine is null)
- throw new UserFriendlyException("未正确配置结束节点");
- //var currentStep = workflow.GetActualStep();
- //if (currentStep is null)
- // throw new UserFriendlyException("未找到实际办理节点");
- var dto = new BasicWorkflowDto
- {
- NextStepCode = endStepDefine.Code,
- NextStepName = endStepDefine.Name,
- FlowDirection = EFlowDirection.OrgToFile,
- BusinessType = endStepDefine.BusinessType,
- ReviewResult = reviewResult,
- Opinion = opinion,
- Files = files
- };
- var unhandleSteps = workflow.Steps
- .Where(d => d.Status != EWorkflowStepStatus.Handled).ToList();
- var unhandleTraces = workflow.Traces
- .Where(d => d.Status != EWorkflowStepStatus.Handled).ToList();
- //todo 结束会签
- foreach (var step in unhandleSteps)
- {
- await _workflowDomainService.HandleStepAsync(current, step, workflow, dto, null,
- null, null, cancellationToken);
- var trace = unhandleTraces.First(d => d.StepId == step.Id);
- _mapper.Map(dto, trace);
- _mapper.Map(step, trace);
- }
- await _workflowStepRepository.UpdateRangeAsync(unhandleSteps, cancellationToken);
- await _workflowTraceRepository.UpdateRangeAsync(unhandleTraces, cancellationToken);
- await _workflowDomainService.EndAsync(workflow, dto,
- endStepDefine, unhandleSteps.First(), current, cancellationToken);
- }
- /// <summary>
- /// 查询开始流程的下一步待选节点
- /// </summary>
- public async Task<NextStepsDto<NextStepOption>> GetStartStepsAsync(string moduleCode, CancellationToken cancellationToken)
- {
- var wfModule = await GetWorkflowModuleAsync(moduleCode, cancellationToken);
- var definition = wfModule.Definition;
- if (definition == null)
- throw new UserFriendlyException("无效模板编码");
- if (definition.Status is not EDefinitionStatus.Enable)
- throw new UserFriendlyException("该模板不可用");
- var startStepDefine = definition.FindStartStepDefine();
- if (startStepDefine.InstanceMode is EInstanceMode.Dynamic &&
- !_workflowDomainService.DynamicShouldTerminal(startStepDefine, _sessionContext.OrgLevel))
- {
- var nextStepOption = await GetDynamicStepAsync(startStepDefine.InstancePolicy.Value,
- startStepDefine.StepType, startStepDefine.BusinessType, cancellationToken);
- return new NextStepsDto<NextStepOption>
- {
- Steps = new List<NextStepOption> { nextStepOption }
- };
- }
- var firstStepDefines = definition.FindStepDefines(startStepDefine.NextSteps.Select(d => d.Code));
- if (!firstStepDefines.Any())
- throw new UserFriendlyException("未正确配置首个办理节点");
- return new NextStepsDto<NextStepOption>
- {
- Steps = await GetConfigStepsAsync(definition.FlowType, startStepDefine.StepType, startStepDefine.BusinessType,
- firstStepDefines, cancellationToken)
- };
- }
- /// <summary>
- /// 查询办理流程的下一步待选节点
- /// </summary>
- public async Task<NextStepsWithOpinionDto<NextStepOption>> GetNextStepsAsync(string workflowId, CancellationToken cancellationToken)
- {
- var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withDefine: true, withSteps: true,
- cancellationToken: cancellationToken);
- var currentStep = _workflowDomainService.FindCurrentStepWaitForHandle(workflow,
- _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles);
- if (currentStep.StepType is EStepType.End)
- throw new UserFriendlyException("结束节点无需办理");
- var dto = new NextStepsWithOpinionDto<NextStepOption>
- {
- CanReject = workflow.IsReviewType() && currentStep.CanReject,
- //ExpiredTime = workflow.ExpiredTime,
- CanStartCountersign = currentStep.CanStartCountersign,
- CurrentStepBusinessType = currentStep.BusinessType,
- TimeTypeOptions = EnumExts.GetDescriptions<ETimeType>().ToList(),
- IsMainHandlerShow = workflow.WorkflowDefinition.IsMainHandlerShow,
- };
- var currentStepDefine = _workflowDomainService.GetStepDefine(workflow.WorkflowDefinition, currentStep.Code);
- if (currentStep.InstanceMode is EInstanceMode.Dynamic &&
- !_workflowDomainService.DynamicShouldTerminal(currentStepDefine, _sessionContext.OrgLevel))
- {
- //动态生成下一步
- var nextStepOption = await GetDynamicStepAsync(currentStep.InstancePolicy.Value, currentStep.StepType,
- currentStep.BusinessType, cancellationToken);
- dto.Steps = new List<NextStepOption> { nextStepOption };
- return dto;
- }
- if (currentStep.IsInCountersign())
- {
- if (currentStep.IsCountersignEndStep)
- {
- // 宜宾需求:会签汇总节点展示会签办理节点办理意见
- var countersignHandleSteps = workflow.Steps.Where(d =>
- d.CountersignId == currentStep.CountersignId &&
- d.CountersignPosition is ECountersignPosition.Multi or ECountersignPosition.Single).ToList();
- var sb = new StringBuilder();
- foreach (var countersignHandleStep in countersignHandleSteps)
- {
- //sb.AppendLine($"{countersignHandleStep.GetActualHandler()?.GetHandler().Value} : {countersignHandleStep.Opinion}");
- sb.AppendLine($"{countersignHandleStep.GetHandler().Value} : {countersignHandleStep.Opinion}");
- }
- dto.Opinion = sb.ToString();
- //当前待办节点为会签汇总节点时:检查是否为顶级会签汇总节点,t:按配置往下走,f:继续往上汇总,不需要重复往下指派
- if (!currentStep.IsTopCountersignEndStep(workflow.TopCountersignStepId))
- {
- var startCountersignStep = GetCsLoopStartStep(workflow, currentStep);
- ////查找当前节点对应会签开始节点的上级作为下一个cs汇总节点的汇总对象
- //var startCountersignStep =
- // workflow.Steps.FirstOrDefault(d => d.Id == currentStep.CountersignStartStepId);
- //if (startCountersignStep is null)
- // throw new UserFriendlyException(
- // $"未查询到会签开始节点,workflowId: {workflow.Id}, startStepId: {currentStep.CountersignStartStepId}",
- // "未查询到会签开始节点,数据异常");
- var countersignEndOption = GetCsEndStepByTargetPrev(workflow.Steps, startCountersignStep);
- //按会签策略
- var nextStepOption = await GetDynamicStepAsync(currentStep.CountersignPolicy.Value,
- EStepType.Normal, currentStep.BusinessType, cancellationToken);
- dto.Steps = new List<NextStepOption> { nextStepOption, countersignEndOption };
- return dto;
- }
- }
- else
- {
- //汇总节点
- var countersignEndOption = GetCsEndStepByTargetPrev(workflow.Steps, currentStep);
- //按会签策略
- var nextStepOption =
- await GetDynamicStepAsync(currentStep.CountersignPolicy.Value,
- EStepType.Normal, currentStep.BusinessType, cancellationToken);
- dto.Steps = new List<NextStepOption> { nextStepOption, countersignEndOption };
- return dto;
- }
- }
- var nextDefines = workflow.WorkflowDefinition.FindStepDefines(currentStep.NextSteps.Select(d => d.Code));
- if (!nextDefines.Any())
- throw new UserFriendlyException("未正确配置下一节点");
- dto.Steps = await GetConfigStepsAsync(workflow, currentStep, nextDefines, cancellationToken);
- // 宜宾需求:汇总节点展示前一级节点办理意见
- if (currentStep.StepType is EStepType.Summary &&
- !currentStep.IsCountersignEndStep &&
- string.IsNullOrEmpty(dto.Opinion))
- {
- var prevStep = workflow.Steps.FirstOrDefault(d => d.Id == currentStep.PrevStepId);
- dto.Opinion = $"{prevStep?.GetHandler().Value} : {prevStep?.Opinion}";
- }
- return dto;
- }
- private WorkflowStep GetCsLoopStartStep(Workflow workflow, WorkflowStep currentStep)
- {
- var startCountersignStep =
- workflow.Steps.FirstOrDefault(d => d.Id == currentStep.CountersignStartStepId);
- if (startCountersignStep is null)
- throw new UserFriendlyException(
- $"未查询到会签开始节点,workflowId: {workflow.Id}, startStepId: {currentStep.CountersignStartStepId}",
- "未查询到会签开始节点,数据异常");
- if (!startCountersignStep.IsCountersignEndStep)
- return startCountersignStep;
- return GetCsLoopStartStep(workflow, startCountersignStep);
- }
- /// <summary>
- /// 查询撤回可选节点及办理对象
- /// </summary>
- public async Task<NextStepsDto<RecallStepOption>> GetRecallStepsAsync(string workflowId, CancellationToken cancellationToken)
- {
- var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withDefine: true, withSteps: true,
- cancellationToken: cancellationToken);
- var isEnd = workflow.Steps.Any(x => x.StepType == EStepType.End);
- var currentStep = workflow.Steps.FirstOrDefault(d => d.Id == workflow.ActualHandleStepId);
- if (currentStep is null)
- throw new UserFriendlyException("无效当前节点编号");
- var quer = workflow.Steps.Where(d =>
- d.StepType != EStepType.End &&
- d.IsOrigin);
- if (!isEnd)
- {
- quer = quer.Where(d => d.Id != currentStep.Id);
- }
- var originSteps = quer.ToList();
- var stepCodes = originSteps.Select(d => d.Code).ToList();
- var stepDefines = workflow.WorkflowDefinition.FindStepDefines(stepCodes);
- var dto = new NextStepsDto<RecallStepOption>
- {
- TimeTypeOptions = EnumExts.GetDescriptions<ETimeType>().ToList()
- };
- var steps = await GetRecallConfigStepsAsync(originSteps, stepDefines, currentStep,
- workflow.FlowType,
- workflow.Status is EWorkflowStatus.Completed,
- cancellationToken);
- dto.Steps = steps;
- return dto;
- }
- private async Task<List<RecallStepOption>> GetRecallConfigStepsAsync(
- List<WorkflowStep> originSteps, List<StepDefine> stepDefines,
- WorkflowStep currentStep, EFlowType flowType, bool isWorkflowFiled, CancellationToken cancellationToken)
- {
- var steps = new List<RecallStepOption>();
- foreach (var originStep in originSteps)
- {
- var stepDefine = stepDefines.First(d => d.Code == originStep.Code);
- var nextStepOption = await GetConfigStepAsync(flowType, stepDefine, cancellationToken);
- var stepOption = _mapper.Map<RecallStepOption>(nextStepOption);
- if (stepDefine.StepType is EStepType.End)
- {
- steps.Add(stepOption);
- continue;
- }
- stepOption.InputRealHandler = false;
- ////已归档工单,撤回至中心看作otc,撤回至部门看作cto
- //stepOption.FlowDirection = isWorkflowFiled
- // ? stepDefine.BusinessType is EBusinessType.Center or EBusinessType.Send
- // ? EFlowDirection.OrgToCenter
- // : stepDefine.BusinessType is EBusinessType.Department
- // ? EFlowDirection.CenterToOrg
- // : null
- // : CheckFlowDirection(currentStep.BusinessType, stepDefine.BusinessType);
- //需求已调整为特提必重算期满时间
- //需求:撤回选择办理对象时,默认选中该节点原办理对象
- if (originStep.Handlers.Any())
- stepOption.Handler =
- originStep.Handlers.FirstOrDefault(d => d.Key == originStep.HandlerId || d.Key == originStep.HandlerOrgId);
- //if (originStep.StepHandlers.Any())
- // stepOption.Handler = originStep.GetActualHandler()?.GetHandler() ?? new();
- steps.Add(stepOption);
- }
- return steps;
- }
- /// <summary>
- /// 否决
- /// </summary>
- public async Task RejectAsync(RejectDto dto, CancellationToken cancellationToken)
- {
- var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withDefine: true,
- cancellationToken: cancellationToken);
- //var basicDto = _mapper.Map<BasicWorkflowDto>(dto);
- //basicDto.NextStepCode = string.Empty;
- //basicDto.IsStartCountersign = false;
- //await _workflowDomainService.RejectAsync(workflow, basicDto, cancellationToken);
- var endStepDefine = workflow.WorkflowDefinition.FindEndStepDefine();
- var nextDto = _mapper.Map<NextWorkflowDto>(dto);
- nextDto.ReviewResult = EReviewResult.Failed;
- nextDto.NextStepCode = endStepDefine.Code;
- nextDto.NextStepName = endStepDefine.Name;
- nextDto.FlowDirection = _sessionContext.OrgIsCenter
- ? EFlowDirection.CenterToFile
- : EFlowDirection.OrgToFile;
- await NextAsync(nextDto, _sessionContext, cancellationToken: cancellationToken);
- }
- //供开启流程调用
- private async Task<List<NextStepOption>> GetConfigStepsAsync(
- EFlowType flowType,
- EStepType currentStepType,
- EBusinessType currentBusinessType,
- List<StepDefine> stepDefines,
- CancellationToken cancellationToken)
- {
- var stepOptions = new List<NextStepOption>();
- foreach (var stepDefine in stepDefines)
- {
- var nextStepOption = await GetConfigStepAsync(flowType, stepDefine, cancellationToken);
- nextStepOption.InputRealHandler = currentStepType == EStepType.Normal &&
- stepDefine.StepType is EStepType.Summary or EStepType.End;
- stepOptions.Add(nextStepOption);
- if (stepDefine.StepType is EStepType.End) continue;
- nextStepOption.FlowDirection = _workflowDomainService.GetFlowDirection(currentBusinessType, stepDefine.BusinessType);
- //stepOptions.Add(nextStepOption);
- }
- return stepOptions;
- }
- /// <summary>
- /// 办理流程调用(根据办理过程过滤汇总节点待选办理对象)
- /// </summary>
- private async Task<List<NextStepOption>> GetConfigStepsAsync(
- Workflow workflow,
- WorkflowStep currentStep,
- //EStepType currentStepType,
- //EBusinessType currentBusinessType,
- List<StepDefine> stepDefines,
- CancellationToken cancellationToken)
- {
- var stepOptions = new List<NextStepOption>();
- foreach (var stepDefine in stepDefines)
- {
- NextStepOption nextStepOption;
- //汇总节点只能选择对应节点办理对象
- if (workflow.FlowType is EFlowType.Handle && stepDefine.StepType is EStepType.Summary)
- {
- //根据汇总对象id找到被汇总节点
- var summaryTargetStep = workflow.Steps.FirstOrDefault(d =>
- d.StepType == EStepType.Normal &&
- d.Code == stepDefine.SummaryTargetCode &&
- d.IsOrigin);
- if (summaryTargetStep is null)
- throw UserFriendlyException.SameMessage("未查询到汇总对象节点");
- //var handlers = summaryTargetStep.Handlers
- // .Where(d => d.Key == summaryTargetStep.HandlerId || d.Key == summaryTargetStep.HandlerOrgId).ToList();
- var handler = new FlowStepHandler
- {
- Key = summaryTargetStep.HandlerId,
- Value = summaryTargetStep.HandlerName,
- UserId = summaryTargetStep.HandlerId,
- Username = summaryTargetStep.HandlerName
- };
- nextStepOption = new NextStepOption
- {
- Key = stepDefine.Code,
- Value = stepDefine.Name,
- StepType = stepDefine.StepType,
- BusinessType = stepDefine.BusinessType,
- //HandlerType = stepDefine.HandlerType,
- HandlerType = EHandlerType.AssignedUser,//指定办理人(业务需求)
- Items = new List<FlowStepHandler> { handler }//handlers
- };
- }
- else
- {
- nextStepOption = await GetConfigStepAsync(workflow.FlowType, stepDefine, cancellationToken);
- }
- nextStepOption.InputRealHandler = currentStep.StepType == EStepType.Normal &&
- stepDefine.StepType is EStepType.Summary or EStepType.End;
- stepOptions.Add(nextStepOption);
- if (stepDefine.StepType is EStepType.End) continue;
- nextStepOption.FlowDirection = _workflowDomainService.GetFlowDirection(currentStep.BusinessType, stepDefine.BusinessType);
- }
- return stepOptions;
- }
- public async Task<NextStepOption> GetConfigStepAsync(EFlowType flowType, StepDefine stepDefine, CancellationToken cancellationToken)
- {
- var handlers = new List<FlowStepHandler>();
- if (stepDefine.StepType is EStepType.End)
- {
- return new NextStepOption
- {
- Key = stepDefine.Code,
- Value = stepDefine.Name,
- StepType = stepDefine.StepType,
- BusinessType = stepDefine.BusinessType,
- HandlerType = stepDefine.HandlerType,
- Items = handlers
- };
- }
- var orgId = _sessionContext.RequiredOrgId;
- var levelOneOrgId = orgId.GetHigherOrgId();
- var isCenter = levelOneOrgId.IsCenter();
- switch (stepDefine.HandlerType)
- {
- case EHandlerType.AssignedUser:
- handlers = await _userRepository.Queryable()
- .Includes(d => d.Organization)
- .Where(d => stepDefine.HandlerTypeItems.Select(x => x.Key).Contains(d.Id))
- .Select(d => new FlowStepHandler
- {
- Key = d.Id,
- Value = d.Name,
- UserId = d.Id,
- Username = d.Name,
- OrgId = d.OrgId,
- OrgName = d.Organization.Name,
- })
- .ToListAsync(cancellationToken);
- break;
- case EHandlerType.AssignedOrg:
- handlers = await _organizeRepository.Queryable() //stepDefine.HandlerTypeItems;
- .Where(d => d.IsEnable && stepDefine.HandlerTypeItems.Select(x => x.Key).Contains(d.Id))
- .Select(d => new FlowStepHandler
- {
- Key = d.Id,
- Value = d.Name,
- OrgId = d.Id,
- OrgName = d.Name
- })
- .ToListAsync(cancellationToken);
- break;
- case EHandlerType.Role:
- //当前操作人所属部门的下级部门并且属于配置包含角色
- var roles = await _roleRepository.Queryable()
- .Includes(
- d => d.Accounts.Where(x =>
- !x.IsDeleted && x.Status == EAccountStatus.Normal && x.AccountType == EAccountType.Personal).ToList(),
- x => x.User, s => s.Organization)
- .Where(d => stepDefine.HandlerTypeItems.Select(x => x.Key).Contains(d.Name))
- .ToListAsync(cancellationToken);
- _logger.LogInformation($"角色: {string.Join(",", roles.Select(d => d.Name))}");
- var users1 = roles.SelectMany(d => d.Accounts).Select(d => d.User);
- //工单办理:除一级部门选择中心汇总(中心会签流程,返回topCountersignStep场景),其余只能选下级部门
- if (flowType is EFlowType.Handle
- && (stepDefine.StepType != EStepType.Summary && stepDefine.BusinessType != EBusinessType.Center))
- users1 = users1.Where(d => d.OrgId.StartsWith(levelOneOrgId));
- handlers = users1.Where(d => d != null && !string.IsNullOrEmpty(d.Id))
- .Select(d => new FlowStepHandler
- {
- Key = d.Id,
- Value = d.Name,
- UserId = d.Id,
- Username = d.Name,
- OrgId = d.OrgId,
- OrgName = d.Organization.Name
- })
- .ToList();
- break;
- case EHandlerType.OrgLevel:
- //当前操作人所属部门的垂直部门并且属于配置orgLevel的部门
- var levels = stepDefine.HandlerTypeItems.Select(d => int.Parse(d.Key)).ToList();
- // var orgs1 = await _organizeRepository.Queryable()
- // .Where(d => d.IsEnable && levels.Contains(d.Level))
- // .WhereIF(!isCenter, d => d.Id.StartsWith(levelOneOrgId))
- // .ToListAsync(cancellationToken);
- _logger.LogInformation($"部门等级: {string.Join(",", levels)}");
- var query = _organizeRepository.Queryable()
- .Where(d => d.IsEnable);
- List<SystemOrganize> orgs1;
- if (isCenter)
- {
- orgs1 = await query
- .Where(d => levels.Contains(d.Level) && !d.IsCenter)
- .ToListAsync(cancellationToken);
- }
- else
- {
- var upLevels = levels.Where(d => d <= _sessionContext.OrgLevel).ToList();
- var lowLevels = levels.Where(d => d > _sessionContext.OrgLevel).ToList();
- orgs1 = await query
- .Where(d => (upLevels.Contains(d.Level) && d.Id.StartsWith(levelOneOrgId)) ||
- (lowLevels.Contains(d.Level) && d.Id.Contains(orgId)))
- .ToListAsync(cancellationToken);
- }
- handlers = orgs1.Select(d => new FlowStepHandler
- {
- Key = d.Id,
- Value = d.Name,
- OrgId = d.Id,
- OrgName = d.Name
- })
- .ToList();
- break;
- case EHandlerType.OrgType:
- var types = stepDefine.HandlerTypeItems.Select(d => d.Key)
- .Select(d => Enum.Parse<EOrgType>(d));
- var orgs2 = await _organizeRepository.Queryable()
- .Where(d => d.IsEnable && types.Contains(d.OrgType))
- .WhereIF(!isCenter, d => d.Id.StartsWith(levelOneOrgId))
- .ToListAsync(cancellationToken);
- handlers = orgs2.Select(d => new FlowStepHandler
- {
- Key = d.Id,
- Value = d.Name,
- OrgId = d.Id,
- OrgName = d.Name
- })
- .ToList();
- break;
- default:
- throw new ArgumentOutOfRangeException();
- }
- return new NextStepOption
- {
- Key = stepDefine.Code,
- Value = stepDefine.Name,
- StepType = stepDefine.StepType,
- BusinessType = stepDefine.BusinessType,
- HandlerType = stepDefine.HandlerType,
- Items = handlers
- };
- }
- private NextStepOption GetCsEndStepByTargetPrev(List<WorkflowStep> steps, WorkflowStep step)
- {
- var prevStep = steps.FirstOrDefault(d => d.Id == step.PrevStepId);
- if (prevStep is null)
- throw new UserFriendlyException("未查找到会签上级节点");
- var text = prevStep.HandlerOrgIsCenter.Value
- ? "热线中心会签汇总"
- : $"{prevStep.HandlerOrgId.CalcOrgLevel().ToChinese()}级部门会签汇总";
- var handlers = prevStep.Handlers
- .Where(d => d.Key == prevStep.HandlerId || d.Key == prevStep.HandlerOrgId).ToList();
- //var handler = prevStep.GetActualHandler()?.GetHandler();
- var handler = new FlowStepHandler
- {
- Key = prevStep.HandlerId,
- Value = prevStep.HandlerName,
- UserId = prevStep.HandlerId,
- Username = prevStep.HandlerName,
- OrgId = prevStep.HandlerOrgId,
- OrgName = prevStep.HandlerOrgName
- };
- return new NextStepOption
- {
- Key = prevStep.Code,
- Value = text,
- BackToCountersignEnd = true,
- StepType = EStepType.Summary,
- BusinessType = prevStep.BusinessType,
- //HandlerType = prevStep.HandlerType,
- HandlerType = EHandlerType.AssignedUser,//指定办理人(业务需求)
- Items = new List<FlowStepHandler> { handler }//handlers //new List<Kv> { new(prevStep.HandlerId, prevStep.HandlerName) },
- };
- }
- /// <summary>
- /// 依据当前操作人及动态策略生成下一步节点
- /// </summary>
- private NextStepOption CreateDynamicStep(EDynamicPolicy policy)
- {
- int orgLevel;
- switch (policy)
- {
- case EDynamicPolicy.OrgUpCenterTop:
- orgLevel = _sessionContext.OrgLevel - 1;
- if (orgLevel < 0) orgLevel = 0;
- break;
- case EDynamicPolicy.OrgUp:
- orgLevel = _sessionContext.OrgLevel - 1;
- if (orgLevel <= 0) orgLevel = 1;
- break;
- case EDynamicPolicy.OrgDownCenterTop:
- orgLevel = _sessionContext.OrgIsCenter
- ? 1
- : _sessionContext.OrgLevel + 1;
- break;
- case EDynamicPolicy.OrgDown:
- orgLevel = _sessionContext.OrgLevel + 1;
- break;
- default:
- throw new ArgumentOutOfRangeException(nameof(policy), policy, null);
- }
- return new NextStepOption
- {
- Key = orgLevel.ToString(),
- Value = orgLevel == 0 ? "热线中心" : $"{orgLevel.ToChinese()}级部门",
- };
- }
- private async Task<NextStepOption> GetDynamicStepAsync(
- EDynamicPolicy policy, EStepType stepType,
- EBusinessType currentBusinessType, CancellationToken cancellationToken)
- {
- int orgLevel;
- List<FlowStepHandler> items;
- string upperOrgId;
- EBusinessType businessType;
- EFlowDirection? flowDirection = null;
- switch (policy)
- {
- case EDynamicPolicy.OrgUpCenterTop:
- orgLevel = _sessionContext.OrgLevel - 1;
- if (orgLevel < 0) orgLevel = 0;
- if (orgLevel == 0)
- {
- businessType = EBusinessType.Send;
- if (currentBusinessType == EBusinessType.Department)
- flowDirection = EFlowDirection.OrgToCenter;
- items = await _organizeRepository.Queryable()
- .Where(d => d.IsCenter)
- .Select(d => new FlowStepHandler
- {
- Key = d.Id,
- Value = d.Name,
- OrgId = d.Id,
- OrgName = d.Name
- })
- .ToListAsync(cancellationToken);
- }
- else
- {
- businessType = EBusinessType.Department;
- //上级部门Id
- upperOrgId = _sessionContext.RequiredOrgId.GetHigherOrgId(orgLevel);
- items = await _organizeRepository.Queryable()
- .Where(d => d.Id == upperOrgId)
- .Select(d => new FlowStepHandler
- {
- Key = d.Id,
- Value = d.Name,
- OrgId = d.Id,
- OrgName = d.Name
- })
- .ToListAsync(cancellationToken);
- }
- break;
- case EDynamicPolicy.OrgUp:
- businessType = _sessionContext.OrgIsCenter
- ? EBusinessType.Send
- : _sessionContext.RequiredOrgId.CalcOrgLevel() == 1
- ? EBusinessType.Send
- : EBusinessType.Department;
- orgLevel = _sessionContext.OrgLevel - 1;
- if (orgLevel <= 0) orgLevel = 1;
- //上级部门Id
- upperOrgId = _sessionContext.RequiredOrgId.GetHigherOrgId(orgLevel);
- items = await _organizeRepository.Queryable()
- .Where(d => d.Id == upperOrgId)
- .Select(d => new FlowStepHandler
- {
- Key = d.Id,
- Value = d.Name,
- OrgId = d.Id,
- OrgName = d.Name
- })
- .ToListAsync(cancellationToken);
- break;
- case EDynamicPolicy.OrgDownCenterTop:
- businessType = EBusinessType.Department;
- if (_sessionContext.OrgIsCenter)
- {
- orgLevel = 1;
- items = await _organizeRepository.Queryable()
- .Where(d => !d.IsCenter && d.Level == orgLevel)
- .Select(d => new FlowStepHandler
- {
- Key = d.Id,
- Value = d.Name,
- OrgId = d.Id,
- OrgName = d.Name
- })
- .ToListAsync(cancellationToken);
- }
- else
- {
- orgLevel = _sessionContext.OrgLevel + 1;
- items = await _organizeRepository.Queryable()
- .Where(d => !d.IsCenter && d.Level == orgLevel &&
- d.Id.StartsWith(_sessionContext.RequiredOrgId))
- .Select(d => new FlowStepHandler
- {
- Key = d.Id,
- Value = d.Name,
- OrgId = d.Id,
- OrgName = d.Name
- })
- .ToListAsync(cancellationToken);
- }
- break;
- case EDynamicPolicy.OrgDown:
- businessType = EBusinessType.Department;
- orgLevel = _sessionContext.OrgLevel + 1;
- items = await _organizeRepository.Queryable()
- .Where(d => d.Level == orgLevel && d.Id.StartsWith(_sessionContext.RequiredOrgId))
- .Select(d => new FlowStepHandler
- {
- Key = d.Id,
- Value = d.Name,
- OrgId = d.Id,
- OrgName = d.Name
- })
- .ToListAsync(cancellationToken);
- break;
- default:
- throw new ArgumentOutOfRangeException(nameof(policy), policy, null);
- }
- return new NextStepOption
- {
- Key = orgLevel.ToString(),
- Value = orgLevel == 0 ? "热线中心" : $"{orgLevel.ToChinese()}级部门",
- FlowDirection = flowDirection,
- StepType = stepType,
- BusinessType = businessType,
- HandlerType = EHandlerType.OrgLevel, //目前所有动态策略均属于部门等级
- Items = items
- };
- }
- /// <summary>
- /// 查询下一节点办理对象类型(user or org)及实际办理对象
- /// </summary>
- public async Task<FlowAssignInfo> GetNextStepFlowAssignInfoAsync(Workflow workflow, WorkflowStep currentStep,
- BasicWorkflowDto dto, StepDefine nextStepDefine, bool isNextDynamic, CancellationToken cancellationToken)
- {
- if (nextStepDefine.StepType is EStepType.End) return new();
- var isStartCountersign = dto.IsStartCountersign;
- var handlers = dto.NextHandlers.Select(d => new Kv(d.Key, d.Value)).ToList();
- if (isStartCountersign)
- {
- var assignType = FlowAssignInfo.GetAssignType(dto.HandlerType);
- //按会签策略判断,目前所有策略为org
- return FlowAssignInfo.Create(assignType, handlers, isStartCountersign);
- }
- //if (currentStep.IsInCountersign() && !currentStep.IsTopCountersignEndStep(workflow.TopCountersignStepId))
- // return FlowAssignInfo.Create(EFlowAssignType.Org, handlers, isStartCountersign);
- if (currentStep.IsInCountersign())
- {
- if (currentStep.IsCountersignEndStep)
- {
- if (!currentStep.IsTopCountersignEndStep(workflow.TopCountersignStepId))
- {
- //汇总节点(非顶级)
- //var csStartStep = workflow.Steps.FirstOrDefault(d => d.Id == currentStep.CountersignStartStepId);
- //if (csStartStep is null)
- // throw new UserFriendlyException("未查询到会签开始节点");
- var csStartStep = GetCsLoopStartStep(workflow, currentStep);
- var prevStep = workflow.Steps.FirstOrDefault(d => d.Id == csStartStep.PrevStepId);
- if (prevStep is null)
- throw new UserFriendlyException("未查询到目标节点的前一节点");
- return FlowAssignInfo.Create(prevStep.FlowAssignType.Value, prevStep.Handlers, isStartCountersign);
- }
- }
- else
- {
- if (dto.BackToCountersignEnd)
- {
- var prevStep = workflow.Steps.FirstOrDefault(d => d.Id == currentStep.PrevStepId);
- if (prevStep is null)
- throw new UserFriendlyException($"未查询到当前节点的上级节点");
- return FlowAssignInfo.Create(prevStep.FlowAssignType.Value, prevStep.Handlers, isStartCountersign);
- }
- else
- {
- var assignType = FlowAssignInfo.GetAssignType(dto.HandlerType);
- //按会签策略判断,目前所有策略为org
- return FlowAssignInfo.Create(assignType, handlers, isStartCountersign);
- }
- }
- }
- if (isNextDynamic)
- return FlowAssignInfo.Create(EFlowAssignType.Org, handlers, isStartCountersign);
- return await GetNextStepFlowAssignInfoByDefineAsync(nextStepDefine, isStartCountersign, handlers,
- cancellationToken);
- }
- //private async ValueTask<List<WorkflowStepHandler>> GetNextStepHandlersAsync(Workflow workflow,
- // StepDefine nextStepDefine, BasicWorkflowDto dto, CancellationToken cancellationToken)
- //{
- // var assignType = FlowAssignInfo.GetAssignType(dto.HandlerType);
- // //var assignType = AssignInfo.GetAssignType(nextStepDefine.HandlerType, dto.NextHandlers.Any());
- // switch (assignType)
- // {
- // case EFlowAssignType.Org:
- // return dto.NextHandlers.Select(d => WorkflowStepHandler.Create(workflow.Id, workflow.ExternalId,
- // assignType, orgId: d.Key, orgName: d.Value)).ToList();
- // case EFlowAssignType.User:
- // if (!dto.NextHandlers.Any() && dto.HandlerType is EHandlerType.Role)
- // {
- // var stepOption = await GetConfigStepAsync(EFlowType.Handle, nextStepDefine, cancellationToken);
- // var uIds = stepOption.Items.Select(d => d.Key).ToList();
- // var users1 = await _userRepository.Queryable()
- // .Includes(d => d.Organization)
- // .Where(d => uIds.Contains(d.Id))
- // .ToListAsync(cancellationToken);
- // return users1.Select(d => WorkflowStepHandler.Create(workflow.Id, workflow.ExternalId,
- // assignType, d.Id, d.Name, d.OrgId, d.Organization.Name))
- // .ToList();
- // }
- // var userIds = dto.NextHandlers.Select(d => d.Key).ToList();
- // var users = await _userRepository.Queryable()
- // .Includes(d => d.Organization)
- // .Where(d => userIds.Contains(d.Id))
- // .ToListAsync(cancellationToken);
- // return users.Select(d => WorkflowStepHandler.Create(workflow.Id, workflow.ExternalId,
- // assignType, d.Id, d.Name, d.OrgId, d.Organization.Name))
- // .ToList();
- // //case EFlowAssignType.Role:
- // // handlers = dto.NextHandlers.Select(d => WorkflowStepHandler.Create(workflow.Id, workflow.ExternalId,
- // // assignType, roleId: d.Key, roleName: d.Value)).ToList();
- // // break;
- // default:
- // throw new ArgumentOutOfRangeException();
- // }
- //}
- /// <summary>
- /// 按流程模板配置创建下一步办理对象
- /// </summary>
- private async Task<FlowAssignInfo> GetNextStepFlowAssignInfoByDefineAsync(StepDefine nextStepDefine,
- bool isStartCountersign,
- List<Kv> handlers, CancellationToken cancellationToken)
- {
- switch (nextStepDefine.HandlerType)
- {
- case EHandlerType.Role:
- if (!handlers.Any())
- {
- //var roles = await _roleRepository.Queryable()
- // .Includes(d => d.Accounts, x => x.User)
- // .Where(d => nextStepDefine.HandlerTypeItems.Select(x => x.Key).Contains(d.Name))
- // .ToListAsync(cancellationToken);
- //handlers = roles.SelectMany(d => d.Accounts).Distinct()
- // .Select(d => new Kv(d.Id, d.User.Name))
- // .ToList();
- handlers = nextStepDefine.HandlerTypeItems;
- return FlowAssignInfo.Create(EFlowAssignType.Role, handlers, isStartCountersign);
- }
- return FlowAssignInfo.Create(EFlowAssignType.User, handlers, isStartCountersign);
- case EHandlerType.OrgLevel:
- case EHandlerType.OrgType:
- case EHandlerType.AssignedOrg:
- return FlowAssignInfo.Create(EFlowAssignType.Org, handlers, isStartCountersign);
- case EHandlerType.AssignedUser:
- return FlowAssignInfo.Create(EFlowAssignType.User, handlers, isStartCountersign);
- default:
- throw new ArgumentOutOfRangeException();
- }
- }
- #region private
- /// <summary>
- /// 查询流程业务模块
- /// </summary>
- /// <param name="code"></param>
- /// <param name="cancellationToken"></param>
- /// <returns></returns>
- /// <exception cref="UserFriendlyException"></exception>
- public async Task<WorkflowModule> GetWorkflowModuleAsync(string code, CancellationToken cancellationToken)
- {
- var wfModule = await _wfModuleCacheManager.GetWorkflowModuleAsync(code, cancellationToken);
- if (wfModule == null)
- throw UserFriendlyException.SameMessage("无效流程模块编码");
- if (wfModule.Definition is null)
- throw new UserFriendlyException($"{code} 未配置流程模板", "未配置流程模板");
- return wfModule;
- }
- /// <summary>
- /// 检查退回节点信息
- /// </summary>
- public async Task<(WorkflowStep currentStep, WorkflowStep prevStep, bool isOrgToCenter, bool isSecondToFirstOrgLevel)>
- GetPreviousInformationAsync(string workflowId, string operatorId, string operatorOrgId, string[] roles,
- CancellationToken cancellationToken)
- {
- var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withSteps: true,
- withCountersigns: true, cancellationToken: cancellationToken);
- var (currentStep, prevStep, _) = _workflowDomainService.GetPreviousStep(workflow, operatorId, operatorOrgId, roles);
- var isOrgToCenter = currentStep.BusinessType is EBusinessType.Department &&
- prevStep.BusinessType is EBusinessType.Center or EBusinessType.Send;
- var isSecondToFirstOrgLevel = currentStep.HandlerType is EHandlerType.OrgLevel &&
- currentStep.Handlers.First().Key.CheckIfOrgLevelIs(2) &&
- prevStep.HandlerType is EHandlerType.OrgLevel &&
- prevStep.Handlers.First().Key.CheckIfOrgLevelIs(1) &&
- !prevStep.Handlers.First().Key.IsCenter();
- return (currentStep, prevStep, isOrgToCenter, isSecondToFirstOrgLevel);
- }
- /// <summary>
- /// 开启流程直接归档
- /// </summary>
- public async Task StartToEndAsync(StartWorkflowDto dto, ISessionContext current, string externalId, DateTime? expiredTime = null,
- CancellationToken cancellationToken = default)
- {
- var wfModule = await GetWorkflowModuleAsync(dto.DefinitionModuleCode, cancellationToken);
- var definition = wfModule.Definition;
- if (definition == null)
- throw new UserFriendlyException("无效模板编码");
- if (definition.Status is not EDefinitionStatus.Enable)
- throw new UserFriendlyException("该模板不可用");
- var endStepDefine = definition.FindEndStepDefine();
- dto.NextStepCode = endStepDefine.Code;
- dto.NextStepName = endStepDefine.Name;
- dto.FlowDirection = EFlowDirection.CenterToFile;
- await StartWorkflowAsync(dto, current, externalId, expiredTime, cancellationToken);
- }
- /// <summary>
- /// 更新省平台办理结果节点附件
- /// </summary>
- public async Task UpdateProvinceHandleResultFilesAsync(string workflowId, List<FileDto> files, CancellationToken cancellationToken)
- {
- var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withSteps: true, withTraces: true,
- cancellationToken: cancellationToken);
- var step = workflow.Steps.FirstOrDefault(d =>
- //d.StepHandlers.Any(d => d.OrgId == "001171" || d.OrgId == "001178"));
- d.HandlerOrgId == "001171" || d.HandlerOrgId == "001178");
- if (step is not null)
- {
- step.FileJson = await _fileRepository.AddFileAsync(files, workflow.ExternalId, step.Id, cancellationToken);
- var trace = workflow.Traces.First(d => d.StepId == step.Id);
- trace.FileJson = step.FileJson;
- await _workflowStepRepository.UpdateAsync(step, cancellationToken);
- await _workflowTraceRepository.UpdateAsync(trace, cancellationToken);
- }
- }
- #endregion
- }
|