|
@@ -36,6 +36,7 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
private readonly IFileRepository _fileRepository;
|
|
|
private readonly IRepository<User> _userRepository;
|
|
|
private readonly ISystemSettingCacheManager _systemSettingCacheManager;
|
|
|
+ private readonly IWfModuleCacheManager _wfModuleCacheManager;
|
|
|
|
|
|
public WorkflowDomainService(
|
|
|
IWorkflowRepository workflowRepository,
|
|
@@ -44,6 +45,7 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
IRepository<WorkflowSupplement> workflowSupplementRepository,
|
|
|
IRepository<WorkflowCountersign> workflowCountersignRepository,
|
|
|
ISystemSettingCacheManager systemSettingCacheManager,
|
|
|
+ IWfModuleCacheManager wfModuleCacheManager,
|
|
|
ISessionContextProvider sessionContextProvider,
|
|
|
IMapper mapper,
|
|
|
Publisher publisher,
|
|
@@ -61,6 +63,7 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
_logger = logger;
|
|
|
_fileRepository = fileRepository;
|
|
|
_systemSettingCacheManager = systemSettingCacheManager;
|
|
|
+ _wfModuleCacheManager = wfModuleCacheManager;
|
|
|
}
|
|
|
|
|
|
public async Task<Workflow> CreateWorkflowAsync(WorkflowModule wfModule, string title, string userId,
|
|
@@ -116,7 +119,7 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
|
|
|
//firststeps
|
|
|
var firstSteps = await CreateNextStepsAsync(workflow, startStep, dto, firstStepDefine,
|
|
|
- isNextDynamic, flowAssignInfo, expiredTime, dto.IsStartCountersign, cancellationToken);
|
|
|
+ isNextDynamic, flowAssignInfo.FlowAssignType, expiredTime, dto.IsStartCountersign, cancellationToken);
|
|
|
|
|
|
await _workflowStepRepository.UpdateAsync(startStep, cancellationToken);
|
|
|
|
|
@@ -140,6 +143,354 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
PublishStrategy.ParallelWhenAll, cancellationToken);
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// new(开启流程并停留在开始节点,开始节点为待办节点,指派给当前操作人)
|
|
|
+ /// </summary>
|
|
|
+ public async Task<WorkflowStep> StartAsync(StartWorkflowDto dto,
|
|
|
+ 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 &&
|
|
|
+ !DynamicShouldTerminal(startStepDefine, _sessionContext.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 CreateWorkflowAsync(wfModule, dto.Title,
|
|
|
+ _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId,
|
|
|
+ externalId, cancellationToken);
|
|
|
+
|
|
|
+ var startStep = CreateStartStep(workflow, startStepDefine, dto,
|
|
|
+ new FlowStepHandler
|
|
|
+ {
|
|
|
+ Key = _sessionContext.RequiredUserId,
|
|
|
+ Value = _sessionContext.UserName,
|
|
|
+ UserId = _sessionContext.UserId,
|
|
|
+ Username = _sessionContext.UserName,
|
|
|
+ OrgId = _sessionContext.RequiredOrgId,
|
|
|
+ OrgName = _sessionContext.OrgName,
|
|
|
+ // RoleId = defineHandler.Key,
|
|
|
+ // RoleName = defineHandler.Value,
|
|
|
+ }, expiredTime);
|
|
|
+
|
|
|
+ if (dto.Files.Any())
|
|
|
+ startStep.FileJson =
|
|
|
+ await _fileRepository.AddFileAsync(dto.Files, workflow.ExternalId, startStep.Id, cancellationToken);
|
|
|
+
|
|
|
+ await _workflowStepRepository.AddAsync(startStep, cancellationToken);
|
|
|
+ workflow.Steps.Add(startStep);
|
|
|
+
|
|
|
+ //starttrace
|
|
|
+ var startTrace = _mapper.Map<WorkflowTrace>(startStep);
|
|
|
+ startTrace.StepId = startStep.Id;
|
|
|
+ startTrace.TraceType = EWorkflowTraceType.Normal;
|
|
|
+ await _workflowTraceRepository.AddAsync(startTrace, cancellationToken);
|
|
|
+ workflow.Traces.Add(startTrace);
|
|
|
+ startStep.WorkflowTrace = startTrace;
|
|
|
+
|
|
|
+ //更新受理人信息
|
|
|
+ workflow.UpdateAcceptor(
|
|
|
+ _sessionContext.RequiredUserId,
|
|
|
+ _sessionContext.UserName,
|
|
|
+ _sessionContext.StaffNo,
|
|
|
+ _sessionContext.RequiredOrgId,
|
|
|
+ _sessionContext.OrgName);
|
|
|
+
|
|
|
+ return startStep;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// new
|
|
|
+ /// </summary>
|
|
|
+ public async Task<List<WorkflowStep>> NextAsync(NextWorkflowDto dto,
|
|
|
+ DateTime? expiredTime = null, CancellationToken cancellationToken = default)
|
|
|
+ {
|
|
|
+ var workflow = await GetWorkflowAsync(dto.WorkflowId, withDefine: true, withSteps: true,
|
|
|
+ withTraces: true, withCountersigns: true, cancellationToken: cancellationToken);
|
|
|
+ CheckWhetherRunnable(workflow.Status);
|
|
|
+
|
|
|
+ //var currentStep = _workflowDomainService.FindCurrentStepWaitForHandle(workflow,
|
|
|
+ // current.RequiredUserId, current.RequiredOrgId, current.Roles);
|
|
|
+ var currentStep = workflow.Steps.FirstOrDefault(d => d.Id == dto.StepId);
|
|
|
+ if (currentStep == null)
|
|
|
+ throw new UserFriendlyException(
|
|
|
+ $"未找到对应节点, workflowId: {dto.WorkflowId}, stepId: {dto.StepId}", "未找到对应节点");
|
|
|
+ if (currentStep.Status is EWorkflowStepStatus.Handled)
|
|
|
+ throw new UserFriendlyException("该状态不支持继续办理");
|
|
|
+
|
|
|
+ var currentStepDefine = GetStepDefine(workflow.WorkflowDefinition, currentStep.Code);
|
|
|
+
|
|
|
+ //下一节点是否为动态节点
|
|
|
+ var isNextDynamic = currentStepDefine.InstanceMode is EInstanceMode.Dynamic &&
|
|
|
+ !DynamicShouldTerminal(currentStepDefine, _sessionContext.OrgLevel);
|
|
|
+
|
|
|
+ StepDefine nextStepDefine;
|
|
|
+ if (isNextDynamic
|
|
|
+ || (currentStep.IsInCountersign() && !currentStep.IsTopCountersignEndStep(workflow.TopCountersignStepId))
|
|
|
+ || dto.IsStartCountersign)
|
|
|
+ {
|
|
|
+ //下一步配置为当前节点配置
|
|
|
+ nextStepDefine = currentStepDefine;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //下一步配置为下一步节点配置
|
|
|
+ nextStepDefine = 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);
|
|
|
+
|
|
|
+
|
|
|
+ #region 办理当前节点
|
|
|
+
|
|
|
+ if (dto.Files != null && dto.Files.Any())
|
|
|
+ currentStep.FileJson = await _fileRepository.AddFileAsync(dto.Files, workflow.ExternalId,
|
|
|
+ currentStep.Id, cancellationToken);
|
|
|
+
|
|
|
+ //(currentStep.IsInCountersign() && !dto.BackToCountersignEnd) || dto.IsStartCountersign;
|
|
|
+ var isStartCountersign = currentStep.CountersignPosition switch
|
|
|
+ {
|
|
|
+ ECountersignPosition.None => dto.IsStartCountersign,
|
|
|
+ ECountersignPosition.Multi => !dto.BackToCountersignEnd,
|
|
|
+ ECountersignPosition.Single => !dto.BackToCountersignEnd,
|
|
|
+ ECountersignPosition.End => dto.IsStartCountersign,
|
|
|
+ _ => throw new ArgumentOutOfRangeException()
|
|
|
+ };
|
|
|
+
|
|
|
+ var counterSignType = GetCounterSignType(dto.IsStartCountersign);
|
|
|
+
|
|
|
+ var updateSteps = new List<WorkflowStep> { currentStep };
|
|
|
+
|
|
|
+ //结束当前会签流程
|
|
|
+ if (currentStep.IsCountersignEndStep)
|
|
|
+ {
|
|
|
+ var countersignStartStep =
|
|
|
+ workflow.Steps.FirstOrDefault(d => d.Id == currentStep.CountersignStartStepId);
|
|
|
+ if (countersignStartStep is null)
|
|
|
+ throw new UserFriendlyException(
|
|
|
+ $"未查询到会签开始step, workflowId: {workflow.Id}, currentStepId: {currentStep.Id}",
|
|
|
+ "未查询到会签开始节点");
|
|
|
+
|
|
|
+ if (countersignStartStep.IsStartCountersign)
|
|
|
+ {
|
|
|
+ var currentCountersign =
|
|
|
+ workflow.Countersigns.FirstOrDefault(d => d.Id == countersignStartStep.StartCountersignId);
|
|
|
+ if (currentCountersign is null)
|
|
|
+ throw new UserFriendlyException(
|
|
|
+ $"未查询到对应会签信息,workflowId:{workflow.Id}, countersignId:{currentStep.CountersignId}",
|
|
|
+ "无效会签编号");
|
|
|
+
|
|
|
+ //结束step会签信息
|
|
|
+ countersignStartStep.CountersignEnd();
|
|
|
+ updateSteps.Add(countersignStartStep);
|
|
|
+
|
|
|
+ //结束会签
|
|
|
+ currentCountersign.End(currentStep.Id, currentStep.Code, currentStep.BusinessType,
|
|
|
+ _sessionContext.RequiredUserId, _sessionContext.UserName,
|
|
|
+ _sessionContext.RequiredOrgId, _sessionContext.OrgName,
|
|
|
+ _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName);
|
|
|
+ await _workflowCountersignRepository.UpdateAsync(currentCountersign, cancellationToken);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ await HandleStepAsync(currentStep, workflow, dto, counterSignType, expiredTime, cancellationToken);
|
|
|
+
|
|
|
+ //创建会签数据
|
|
|
+ if (isStartCountersign)
|
|
|
+ {
|
|
|
+ var exists = workflow.Countersigns.Any(d =>
|
|
|
+ !d.IsCompleted() && d.StarterId == _sessionContext.RequiredUserId);
|
|
|
+ if (exists)
|
|
|
+ throw new UserFriendlyException("该用户在当前流程存在未结束会签");
|
|
|
+ await StartCountersignAsync(_sessionContext, workflow, currentStep, dto, flowAssignInfo.FlowAssignType,
|
|
|
+ counterSignType, expiredTime, cancellationToken);
|
|
|
+ }
|
|
|
+
|
|
|
+ currentStep.IsActualHandled = CheckIsActualHandle(workflow, currentStep, nextStepDefine, dto);
|
|
|
+
|
|
|
+ _mapper.Map(dto, workflow);
|
|
|
+
|
|
|
+ //会签办理节点办理时更新会签members字段
|
|
|
+ if (currentStep.CountersignPosition is ECountersignPosition.Multi or ECountersignPosition.Single)
|
|
|
+ {
|
|
|
+ if (!string.IsNullOrEmpty(currentStep.CountersignId))
|
|
|
+ {
|
|
|
+ //会签中正常办理节点,更新会签members办理状态
|
|
|
+ var countersign =
|
|
|
+ workflow.Countersigns.FirstOrDefault(d =>
|
|
|
+ !d.IsCompleted() && d.Id == currentStep.CountersignId);
|
|
|
+ if (countersign is not null)
|
|
|
+ {
|
|
|
+ //throw new UserFriendlyException(
|
|
|
+ // $"会签数据异常, workflowId: {currentStep.WorkflowId}, countersignId: {currentStep.CountersignId}",
|
|
|
+ // "会签数据异常");
|
|
|
+ countersign.MemberHandled(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId);
|
|
|
+ //update cs
|
|
|
+ await _workflowCountersignRepository.UpdateNav(countersign)
|
|
|
+ .Include(d => d.Members)
|
|
|
+ .ExecuteCommandAsync();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ await _workflowStepRepository.UpdateRangeAsync(updateSteps, cancellationToken);
|
|
|
+
|
|
|
+ //更新traces
|
|
|
+ var updateTraces = new List<WorkflowTrace>();
|
|
|
+ foreach (var updateStep in updateSteps)
|
|
|
+ {
|
|
|
+ var updateTrace = workflow.Traces.First(d => d.Id == updateStep.Id);
|
|
|
+ _mapper.Map(updateStep, updateTrace);
|
|
|
+ updateTraces.Add(updateTrace);
|
|
|
+ }
|
|
|
+
|
|
|
+ await _workflowTraceRepository.UpdateRangeAsync(updateTraces, cancellationToken);
|
|
|
+
|
|
|
+ //var trace = await NextTraceAsync(workflow, dto, currentStep, cancellationToken);
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 处理流程
|
|
|
+
|
|
|
+ //检查会签是否结束,并更新当前会签节点字段
|
|
|
+ var isCountersignOver = false;
|
|
|
+ if (workflow.IsInCountersign && currentStep.IsCountersignEndStep)
|
|
|
+ {
|
|
|
+ isCountersignOver = workflow.CheckIfCountersignOver();
|
|
|
+ if (isCountersignOver)
|
|
|
+ workflow.EndCountersign();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (workflow.ActualHandleStepId == currentStep.Id)
|
|
|
+ {
|
|
|
+ //更新实际办理节点信息
|
|
|
+ workflow.UpdateActualStepWhenHandle(currentStep, _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName, _sessionContext.OrgLevel);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (workflow.CurrentStepId == currentStep.Id)
|
|
|
+ {
|
|
|
+ workflow.UpdateCurrentStepWhenHandle(currentStep, _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName, _sessionContext.OrgLevel);
|
|
|
+ }
|
|
|
+
|
|
|
+ //检查是否流转到流程终点
|
|
|
+ if (nextStepDefine.StepType is EStepType.End)
|
|
|
+ {
|
|
|
+ var endTrace = await EndAsync(workflow, dto, nextStepDefine, currentStep, expiredTime, cancellationToken);
|
|
|
+ return new List<WorkflowStep>();
|
|
|
+ }
|
|
|
+
|
|
|
+ //创建下一/N个节点(会签汇总节点:会签未全部办理时不创建,最后一个会签办理节点创建会签汇总节点)
|
|
|
+ var nextSteps = await CreateNextStepsAsync(workflow, currentStep, dto,
|
|
|
+ nextStepDefine, isNextDynamic, flowAssignInfo.FlowAssignType, expiredTime, isStartCountersign,
|
|
|
+ cancellationToken);
|
|
|
+
|
|
|
+ ////赋值当前节点的下级办理节点
|
|
|
+ //if (dto.IsStartCountersign
|
|
|
+ // //|| (currentStep.IsInCountersign() &&
|
|
|
+ // // !currentStep.IsTopCountersignEndStep(workflow.TopCountersignStepId))
|
|
|
+ // )
|
|
|
+ //{
|
|
|
+ // currentStep.CreateCountersignSteps(nextSteps);
|
|
|
+ // await _workflowStepRepository.UpdateAsync(currentStep, cancellationToken);
|
|
|
+ //}
|
|
|
+
|
|
|
+ // //更新办理对象(nextSteps无元素表示当前节点为会签办理节点且当前会签没有全部办理完成)
|
|
|
+ // workflow.UpdateHandlers(current.RequiredUserId, current.RequiredOrgId,
|
|
|
+ // flowAssignInfo.FlowAssignType, flowAssignInfo.HandlerObjects, nextSteps.Any());
|
|
|
+
|
|
|
+ //todo 计算办理工作时长
|
|
|
+
|
|
|
+ //指派实际办理节点
|
|
|
+ UpdateActualStep(workflow, dto, nextStepDefine, nextSteps);
|
|
|
+
|
|
|
+ //更新实际办理节点
|
|
|
+ UpdateCurrentStep(workflow, dto, nextStepDefine, nextSteps);
|
|
|
+
|
|
|
+ //发起会签时记录顶层会签节点
|
|
|
+ if (dto.IsStartCountersign && !workflow.IsInCountersign)
|
|
|
+ workflow.StartCountersign(currentStep.Id, counterSignType);
|
|
|
+
|
|
|
+ //更新指派信息
|
|
|
+ //workflow.Assign(flowAssignInfo.FlowAssignType, flowAssignInfo.GetHandlerIds());
|
|
|
+
|
|
|
+ //更新会签实际办理对象信息
|
|
|
+ if (currentStep.IsActualHandled)
|
|
|
+ workflow.AddCsActualHandler(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId);
|
|
|
+
|
|
|
+ await _workflowRepository.UpdateAsync(workflow, cancellationToken);
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 流转记录
|
|
|
+
|
|
|
+ //var trace = await NextTraceAsync(workflow, dto, currentStep, cancellationToken);
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ var currentTrace = workflow.Traces.First(d => d.Id == currentStep.Id);
|
|
|
+ await _publisher.PublishAsync(
|
|
|
+ new NextStepNotify(workflow, dto, flowAssignInfo, currentTrace, nextStepDefine,
|
|
|
+ _sessionContext.RequiredOrgId, expiredTime.HasValue), PublishStrategy.ParallelWhenAll,
|
|
|
+ cancellationToken);
|
|
|
+
|
|
|
+ return nextSteps;
|
|
|
+ }
|
|
|
+
|
|
|
public async Task<Workflow> GetWorkflowAsync(string workflowId,
|
|
|
bool withDefine = false, bool withSteps = false,
|
|
|
bool withTraces = false, bool withTracesTree = false,
|
|
@@ -197,8 +548,7 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
/// <summary>
|
|
|
/// 查询工作流包含当前用户结束会签权限(是否可结束)
|
|
|
/// </summary>
|
|
|
- public async Task<(Workflow Workflow, string? CountersignId, bool CanHandle, bool CanPrevious, WorkflowTrace?
|
|
|
- Trace)>
|
|
|
+ public async Task<(Workflow Workflow, string? CountersignId, bool CanHandle, bool CanPrevious, WorkflowTrace? Trace)>
|
|
|
GetWorkflowHandlePermissionAsync(
|
|
|
string workflowId, string userId, string orgId, string[] roleIds,
|
|
|
CancellationToken cancellationToken = default)
|
|
@@ -341,8 +691,7 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- await HandleStepAsync(currentStep, workflow, dto, flowAssignInfo.FlowAssignType,
|
|
|
- counterSignType, expiredTime, cancellationToken);
|
|
|
+ await HandleStepAsync(currentStep, workflow, dto, counterSignType, expiredTime, cancellationToken);
|
|
|
|
|
|
//创建会签数据
|
|
|
if (isStartCountersign)
|
|
@@ -454,7 +803,7 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
|
|
|
//创建下一/N个节点(会签汇总节点:会签未全部办理时不创建,最后一个会签办理节点创建会签汇总节点)
|
|
|
var nextSteps = await CreateNextStepsAsync(workflow, currentStep, dto,
|
|
|
- nextStepDefine, isNextDynamic, flowAssignInfo, expiredTime, isStartCountersign,
|
|
|
+ nextStepDefine, isNextDynamic, flowAssignInfo.FlowAssignType, expiredTime, isStartCountersign,
|
|
|
cancellationToken);
|
|
|
|
|
|
////赋值当前节点的下级办理节点
|
|
@@ -1519,7 +1868,7 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
/// 办理节点
|
|
|
/// </summary>
|
|
|
public async Task HandleStepAsync(WorkflowStep step, Workflow workflow,
|
|
|
- BasicWorkflowDto dto, EFlowAssignType? flowAssignType, ECounterSignType? counterSignType,
|
|
|
+ BasicWorkflowDto dto, ECounterSignType? counterSignType,
|
|
|
DateTime? expiredTime, CancellationToken cancellationToken)
|
|
|
{
|
|
|
if (step.Status is EWorkflowStepStatus.Handled)
|
|
@@ -1643,7 +1992,7 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
/// 创建下1/N个节点
|
|
|
/// </summary>
|
|
|
private async Task<List<WorkflowStep>> CreateNextStepsAsync(Workflow workflow, WorkflowStep currentStep,
|
|
|
- BasicWorkflowDto dto, StepDefine nextStepDefine, bool isNextDynamic, FlowAssignInfo flowAssignInfo,
|
|
|
+ BasicWorkflowDto dto, StepDefine nextStepDefine, bool isNextDynamic, EFlowAssignType flowAssignType,
|
|
|
DateTime? expiredTime, bool isStartCountersign,
|
|
|
CancellationToken cancellationToken)
|
|
|
{
|
|
@@ -1660,13 +2009,13 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
{
|
|
|
//依据会签策略创建会签下一级节点
|
|
|
nextSteps = await CreateCountersignStepsAsync(workflow, nextStepDefine, currentStep, dto,
|
|
|
- flowAssignInfo.FlowAssignType, expiredTime, isStartCountersign, cancellationToken);
|
|
|
+ flowAssignType, expiredTime, cancellationToken);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
//创建普通节点(根据配置)
|
|
|
nextSteps = await CreateConfigStepsAsync(workflow, nextStepDefine, currentStep, dto,
|
|
|
- flowAssignInfo, EWorkflowTraceType.Normal, expiredTime, cancellationToken);
|
|
|
+ flowAssignType, EWorkflowTraceType.Normal, expiredTime, cancellationToken);
|
|
|
}
|
|
|
}
|
|
|
else
|
|
@@ -1685,7 +2034,7 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
{
|
|
|
//依据会签策略创建会签下一级节点
|
|
|
nextSteps = await CreateCountersignStepsAsync(workflow, nextStepDefine, currentStep, dto,
|
|
|
- flowAssignInfo.FlowAssignType, expiredTime, isStartCountersign, cancellationToken);
|
|
|
+ flowAssignType, expiredTime, cancellationToken);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -1701,7 +2050,7 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
{
|
|
|
//依据会签策略创建会签下一级节点
|
|
|
nextSteps = await CreateCountersignStepsAsync(workflow, nextStepDefine, currentStep, dto,
|
|
|
- flowAssignInfo.FlowAssignType, expiredTime, isStartCountersign, cancellationToken);
|
|
|
+ flowAssignType, expiredTime, cancellationToken);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -1709,18 +2058,18 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
{
|
|
|
//依据会签策略创建会签下一级节点
|
|
|
nextSteps = await CreateCountersignStepsAsync(workflow, nextStepDefine, currentStep, dto,
|
|
|
- flowAssignInfo.FlowAssignType, expiredTime, isStartCountersign, cancellationToken);
|
|
|
+ flowAssignType, expiredTime, cancellationToken);
|
|
|
}
|
|
|
else if (isNextDynamic)
|
|
|
{
|
|
|
//创建动态下一级节点
|
|
|
- nextSteps = await CreateDynamicStepsAsync(workflow, nextStepDefine, currentStep, dto, flowAssignInfo,
|
|
|
+ nextSteps = await CreateDynamicStepsAsync(workflow, nextStepDefine, currentStep, dto, flowAssignType,
|
|
|
expiredTime, cancellationToken);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
//创建普通节点(根据配置)
|
|
|
- nextSteps = await CreateConfigStepsAsync(workflow, nextStepDefine, currentStep, dto, flowAssignInfo,
|
|
|
+ nextSteps = await CreateConfigStepsAsync(workflow, nextStepDefine, currentStep, dto, flowAssignType,
|
|
|
EWorkflowTraceType.Normal, expiredTime, cancellationToken);
|
|
|
}
|
|
|
|
|
@@ -1745,7 +2094,7 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
StepDefine nextStepDefine,
|
|
|
WorkflowStep prevStep,
|
|
|
BasicWorkflowDto dto,
|
|
|
- FlowAssignInfo flowAssignInfo,
|
|
|
+ EFlowAssignType flowAssignType,
|
|
|
DateTime? expiredTime,
|
|
|
CancellationToken cancellationToken)
|
|
|
{
|
|
@@ -1766,7 +2115,7 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
};
|
|
|
|
|
|
return await CreateStepsAsync(workflow, nextStepDefine, prevStep, dto,
|
|
|
- flowAssignInfo.FlowAssignType, dto.NextHandlers, null, EWorkflowStepStatus.WaitForAccept,
|
|
|
+ flowAssignType, dto.NextHandlers, null, EWorkflowStepStatus.WaitForAccept,
|
|
|
ECountersignPosition.None, false, EWorkflowTraceType.Normal, handlerType, expiredTime,
|
|
|
cancellationToken: cancellationToken);
|
|
|
}
|
|
@@ -1778,28 +2127,14 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
BasicWorkflowDto dto,
|
|
|
EFlowAssignType flowAssignType,
|
|
|
DateTime? expiredTime,
|
|
|
- bool isStartCountersign,
|
|
|
CancellationToken cancellationToken = default
|
|
|
)
|
|
|
{
|
|
|
//var countersignId = dto.IsStartCountersign ? prevStep.StartCountersignId : prevStep.CountersignId;
|
|
|
var countersignId = prevStep.StartCountersignId;
|
|
|
|
|
|
- var handlerType = stepDefine.CountersignPolicy switch
|
|
|
- {
|
|
|
- EDynamicPolicyCountersign.OrgUpCenterTop => EHandlerType.OrgLevel,
|
|
|
- EDynamicPolicyCountersign.OrgUp => EHandlerType.OrgLevel,
|
|
|
- EDynamicPolicyCountersign.OrgUpHandleCenterTop => EHandlerType.OrgLevel,
|
|
|
- EDynamicPolicyCountersign.OrgUpHandle => EHandlerType.OrgLevel,
|
|
|
- EDynamicPolicyCountersign.OrgUpLeadCenterTop => EHandlerType.OrgLevel,
|
|
|
- EDynamicPolicyCountersign.OrgUpLead => EHandlerType.OrgLevel,
|
|
|
- EDynamicPolicyCountersign.ArriveCenter => EHandlerType.OrgLevel,
|
|
|
- EDynamicPolicyCountersign.ArriveOneOrg => EHandlerType.OrgLevel,
|
|
|
- EDynamicPolicyCountersign.OrgDownCenterTop => EHandlerType.OrgLevel,
|
|
|
- EDynamicPolicyCountersign.OrgDown => EHandlerType.OrgLevel,
|
|
|
- null => throw new ArgumentOutOfRangeException(),
|
|
|
- _ => throw new ArgumentOutOfRangeException()
|
|
|
- };
|
|
|
+ //当前策略均为orglevel
|
|
|
+ var handlerType = EHandlerType.OrgLevel;
|
|
|
|
|
|
var nextStepCountersignPosition = dto.NextHandlers.Count > 1
|
|
|
? ECountersignPosition.Multi
|
|
@@ -2416,7 +2751,7 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
StepDefine stepDefine,
|
|
|
WorkflowStep prevStep,
|
|
|
BasicWorkflowDto dto,
|
|
|
- FlowAssignInfo flowAssignInfo,
|
|
|
+ EFlowAssignType flowAssignType,
|
|
|
EWorkflowTraceType traceType,
|
|
|
DateTime? expiredTime,
|
|
|
CancellationToken cancellationToken)
|
|
@@ -2437,8 +2772,8 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
handlers = dto.NextHandlers;
|
|
|
}
|
|
|
|
|
|
- return await CreateStepsAsync(workflow, stepDefine, prevStep, dto, /*dto.IsStartCountersign,*/
|
|
|
- flowAssignInfo.FlowAssignType, handlers, null,
|
|
|
+ return await CreateStepsAsync(workflow, stepDefine, prevStep, dto,
|
|
|
+ flowAssignType, handlers, null,
|
|
|
EWorkflowStepStatus.WaitForAccept, ECountersignPosition.None,
|
|
|
true, traceType, null, expiredTime, cancellationToken);
|
|
|
}
|
|
@@ -2468,18 +2803,11 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
var step = CreateStep(workflow, stepDefine, prevStep, flowAssignType,
|
|
|
handler, dto.NextStepCode, countersignId, stepStatus, csPosition, expiredTime,
|
|
|
dto.NextStepName, isOrigin, isMain, handlerType, dto.BusinessType);
|
|
|
-
|
|
|
- //var stepHandler = stepHandlers.First(d => d.GetHandler().Key == handler.Key);
|
|
|
- //step.StepHandlers = new List<WorkflowStepHandler> { stepHandler };
|
|
|
-
|
|
|
steps.Add(step);
|
|
|
}
|
|
|
|
|
|
await _workflowStepRepository.AddRangeAsync(steps, cancellationToken);
|
|
|
workflow.Steps.AddRange(steps);
|
|
|
- //await _workflowStepRepository.AddNav(steps)
|
|
|
- // .Include(d => d.StepHandlers)
|
|
|
- // .ExecuteCommandAsync();
|
|
|
|
|
|
//create traces todo add range traces
|
|
|
foreach (var step in steps)
|
|
@@ -2848,6 +3176,175 @@ namespace Hotline.FlowEngine.Workflows
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ //new
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 查询流程业务模块
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="code"></param>
|
|
|
+ /// <param name="cancellationToken"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ /// <exception cref="UserFriendlyException"></exception>
|
|
|
+ private 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;
|
|
|
+ }
|
|
|
+ //
|
|
|
+ // private StepAssignInfo GetStepAssignInfo(TargetStepAssignPolicyInfo targetStepAssignPolicyInfo, bool anyHandlers,
|
|
|
+ // StepDefine? stepDefine = null, WorkflowStep? targetStep = null, FlowStepHandler? handler = null)
|
|
|
+ // {
|
|
|
+ // switch (targetStepAssignPolicyInfo.TargetStepAssignPolicy)
|
|
|
+ // {
|
|
|
+ // case ETargetStepAssignPolicy.Config:
|
|
|
+ // if (stepDefine is null) throw new UserFriendlyException($"{nameof(stepDefine)} is null");
|
|
|
+ // return new StepAssignInfo
|
|
|
+ // {
|
|
|
+ // FlowAssignType = GetNextStepFlowAssignTypeByDefine(stepDefine, anyHandlers),
|
|
|
+ // //todo
|
|
|
+ // // Handler =
|
|
|
+ // };
|
|
|
+ // case ETargetStepAssignPolicy.TargetStep:
|
|
|
+ // if (targetStep is null) throw new UserFriendlyException($"{nameof(targetStep)} is null");
|
|
|
+ // if (targetStep.FlowAssignType is null) throw new UserFriendlyException($"targetStep.FlowAssignType is null");
|
|
|
+ // return new StepAssignInfo
|
|
|
+ // {
|
|
|
+ // FlowAssignType = targetStep.FlowAssignType.Value,
|
|
|
+ // Handler = targetStep.GetWorkflowStepHandler()
|
|
|
+ // };
|
|
|
+ // case ETargetStepAssignPolicy.AssignHandler:
|
|
|
+ // if(handler is null) throw new UserFriendlyException($"{nameof(handler)} is null");
|
|
|
+ // return new()
|
|
|
+ // {
|
|
|
+ // FlowAssignType = EFlowAssignType.User,
|
|
|
+ // Handler = handler
|
|
|
+ // };
|
|
|
+ // default:
|
|
|
+ // throw new ArgumentOutOfRangeException();
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ //
|
|
|
+ // /// <summary>
|
|
|
+ // /// 按流程模板配置获取下一节点指派类型
|
|
|
+ // /// </summary>
|
|
|
+ // private EFlowAssignType GetNextStepFlowAssignTypeByDefine(StepDefine nextStepDefine, bool anyHandlers)
|
|
|
+ // {
|
|
|
+ // switch (nextStepDefine.HandlerType)
|
|
|
+ // {
|
|
|
+ // case EHandlerType.Role:
|
|
|
+ // return !anyHandlers ? EFlowAssignType.Role : EFlowAssignType.User;
|
|
|
+ //
|
|
|
+ // case EHandlerType.OrgLevel:
|
|
|
+ // case EHandlerType.OrgType:
|
|
|
+ // case EHandlerType.AssignedOrg:
|
|
|
+ // return EFlowAssignType.Org;
|
|
|
+ //
|
|
|
+ // case EHandlerType.AssignedUser:
|
|
|
+ // return EFlowAssignType.User;
|
|
|
+ //
|
|
|
+ // default:
|
|
|
+ // throw new ArgumentOutOfRangeException();
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 查询下一节点办理对象类型(user or org)及实际办理对象
|
|
|
+ /// </summary>
|
|
|
+ private 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, dto.NextHandlers.Any());
|
|
|
+ //按会签策略判断,目前所有策略为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))
|
|
|
+ {
|
|
|
+ if (dto.BackToCountersignEnd)
|
|
|
+ {
|
|
|
+ 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, dto.NextHandlers.Any());
|
|
|
+ //按会签策略判断,目前所有策略为org
|
|
|
+ return FlowAssignInfo.Create(assignType, handlers, isStartCountersign);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (isNextDynamic)
|
|
|
+ {
|
|
|
+ switch (currentStep.InstancePolicy)
|
|
|
+ {
|
|
|
+ case EDynamicPolicy.OrgUpCenterTop:
|
|
|
+ case EDynamicPolicy.OrgUp:
|
|
|
+ case EDynamicPolicy.OrgDownCenterTop:
|
|
|
+ case EDynamicPolicy.OrgDown:
|
|
|
+ case EDynamicPolicy.ArriveCenter:
|
|
|
+ case EDynamicPolicy.ArriveOneOrg:
|
|
|
+ return FlowAssignInfo.Create(EFlowAssignType.Org, handlers, isStartCountersign);
|
|
|
+ case EDynamicPolicy.OrgUpHandleCenterTop:
|
|
|
+ case EDynamicPolicy.OrgUpHandle:
|
|
|
+ case EDynamicPolicy.OrgUpLeadCenterTop:
|
|
|
+ case EDynamicPolicy.OrgUpLead:
|
|
|
+ return FlowAssignInfo.Create(EFlowAssignType.OrgAndRole, handlers, isStartCountersign);
|
|
|
+ default:
|
|
|
+ throw new ArgumentOutOfRangeException();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return await GetNextStepFlowAssignInfoByDefineAsync(nextStepDefine, dto.HandlerType, isStartCountersign, handlers,
|
|
|
+ cancellationToken);
|
|
|
+ }
|
|
|
+
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+
|
|
|
#endregion
|
|
|
}
|
|
|
}
|