xf 2 жил өмнө
parent
commit
d75eaea5c2

+ 1 - 2
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -92,9 +92,8 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         //下一节点为结束节点时,无办理人等参数,只有办理意见即可
         var isOutOfCallCenter = nextStepBoxDefine.StepType is not EStepType.End
                                 && await CheckIfFlowOutOfCallCenterAsync(nextStepBoxDefine, dto.NextMainHandler, cancellationToken);
-        var isStartCountersign = nextStepBoxDefine.StepType is not EStepType.End
-                                 && nextStepBoxDefine.IsStartCountersign(dto.NextHandlers.Count);
 
+        var isStartCountersign = nextStepBoxDefine.IsStartCountersign(dto.NextHandlers.Count);
         if (isStartCountersign && nextStepBoxDefine.StepType is EStepType.CountersignEnd)
             throw UserFriendlyException.SameMessage("汇总节点不允许发起会签");
 

+ 1 - 1
src/Hotline.Application/Mappers/MapperConfigs.cs

@@ -50,7 +50,7 @@ namespace Hotline.Application.Mappers
                 .Ignore(d => d.IsMain)
                 .Ignore(d => d.Status)
                 .Ignore(d => d.ParentId)
-                .Ignore(d => d.HandlerId)
+                .Ignore(d => d.HandlerIds)
                 .Ignore(d => d.Steps)
                 .Ignore(d => d.StartCountersignId)
                 .Ignore(d => d.CountersignId)

+ 4 - 1
src/Hotline/FlowEngine/Definitions/StepDefine.cs

@@ -10,7 +10,7 @@ namespace Hotline.FlowEngine.Definitions;
 public class StepDefine : StepBasic
 {
     public List<NextStepDefine> NextSteps { get; set; }
-    
+
     /// <summary>
     /// 是否发起会签
     /// </summary>
@@ -18,8 +18,11 @@ public class StepDefine : StepBasic
     /// <returns></returns>
     public bool IsStartCountersign(int handlerCount)
     {
+        if (StepType is not EStepType.Normal) return false;
+
         //需求:按角色指派默认不发起会签
         if (HandlerType is EHandlerType.Role) return false;
+
         return handlerCount > 1;
     }
 }

+ 60 - 57
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -99,7 +99,7 @@ namespace Hotline.FlowEngine.Workflows
                 throw UserFriendlyException.SameMessage("未指派办理人");
 
             //开始节点
-            var (startStepBox, startStep) = await CreateStartStepAsync(workflow, dto, cancellationToken);
+            var (startStepBox, startStep) = await CreateStartStepAsync(workflow, dto, isStartCountersign, cancellationToken);
 
             if (isStartCountersign)
             {
@@ -114,7 +114,7 @@ namespace Hotline.FlowEngine.Workflows
             await NextTraceAsync(workflow, dto, startStep, cancellationToken);
 
             //第二节点(创建即为 已指派/待接办 状态)
-            var nextStepBox = await CreateStepAsync(workflow, nextStepBoxDefine, dto, EWorkflowStepStatus.Assigned,
+            var nextStepBox = await CreateStepAsync(isStartCountersign, workflow, nextStepBoxDefine, dto, EWorkflowStepStatus.Assigned,
                 startStepBox, startStep, cancellationToken);
 
             //更新当前节点名称、时间、会签节点code 等字段
@@ -186,12 +186,12 @@ namespace Hotline.FlowEngine.Workflows
             if (currentStep.HandlerType is EHandlerType.AssignUser or EHandlerType.Role)
             {
                 //userId
-                if (currentStep.HandlerId != userId) return;
+                if (!currentStep.HandlerIds.Contains(userId)) return;
             }
             else
             {
                 //orgId
-                if (currentStep.HandlerId != orgCode) return;
+                if (!currentStep.HandlerIds.Contains(orgCode)) return;
             }
             if (currentStep.StepType is EStepType.End)
                 throw new UserFriendlyException("当前流程已流转到最终步骤");
@@ -347,7 +347,7 @@ namespace Hotline.FlowEngine.Workflows
             }
 
             //创建下一节点(会签汇总节点不重复创建)
-            var nextStepBox = await CreateStepAsync(workflow, nextStepBoxDefine, dto, EWorkflowStepStatus.Created,
+            var nextStepBox = await CreateStepAsync(isStartCountersign, workflow, nextStepBoxDefine, dto, EWorkflowStepStatus.Created,
                 currentStepBox, currentStep, cancellationToken);
 
             //下一节点为汇总节点时,检查下一节点是否可办理
@@ -455,7 +455,8 @@ namespace Hotline.FlowEngine.Workflows
             {
                 //向后跳转
                 var nextStepBoxDefine = GetStepBoxDefine(workflow.Definition, dto.NextStepCode);
-                var nextStepBox = await CreateStepAsync(workflow, nextStepBoxDefine, dto, EWorkflowStepStatus.Assigned, currentStepBox, currentStep, cancellationToken);
+                var isStartCountersign = nextStepBoxDefine.IsStartCountersign(dto.NextHandlers.Count);
+                var nextStepBox = await CreateStepAsync(isStartCountersign, workflow, nextStepBoxDefine, dto, EWorkflowStepStatus.Assigned, currentStepBox, currentStep, cancellationToken);
 
                 await ResetWorkflowCurrentStepInfo(workflow, dto, nextStepBox, cancellationToken);
 
@@ -571,23 +572,19 @@ namespace Hotline.FlowEngine.Workflows
         /// <returns></returns>
         private async Task SetNextCountersignEndAssignedAsync(WorkflowStep nextStepBox, WorkflowStep currentStep, CancellationToken cancellationToken)
         {
-            WorkflowStep? nextStep;
-            if (currentStep.StepCountersignStatus is EStepCountersignStatus.InCountersign)
-            {
-                nextStep = nextStepBox.Steps.FirstOrDefault(d => d.CountersignId == currentStep.CountersignId);
-            }
-            else
-            {
-                nextStep = nextStepBox.Steps.FirstOrDefault(d => d.ParentId == currentStep.Id);
-            }
+            var nextSteps = currentStep.StepCountersignStatus is EStepCountersignStatus.InCountersign
+                ? nextStepBox.Steps.Where(d => d.CountersignId == currentStep.CountersignId).ToList()
+                : nextStepBox.Steps.Where(d => d.PreviousId == currentStep.Id).ToList();
 
-            if (nextStep == null)
-                throw new UserFriendlyException(
-                    $"未查询到下一节点, workflowId:{currentStep.WorkflowId}, currentStepId: {currentStep.Id}");
+            if (!nextSteps.Any())
+                throw new UserFriendlyException($"未查询到下一节点, currentStepId: {currentStep.Id}");
 
-            nextStep.SetAssigned();
+            foreach (var nextStep in nextSteps)
+            {
+                nextStep.SetAssigned();
+            }
 
-            await _workflowStepRepository.UpdateAsync(nextStep, cancellationToken);
+            await _workflowStepRepository.UpdateRangeAsync(nextSteps, cancellationToken);
         }
 
         /// <summary>
@@ -704,7 +701,8 @@ namespace Hotline.FlowEngine.Workflows
 
             //recreate targetStep
             var nextStepBoxDefine = GetStepBoxDefine(workflow.Definition, dto.NextStepCode);
-            await CreateStepAsync(workflow, nextStepBoxDefine, dto, EWorkflowStepStatus.Assigned, targetStepBox, targetStepBox.Steps.First(), cancellationToken);
+            var isStartCountersign = nextStepBoxDefine.IsStartCountersign(dto.NextHandlers.Count);
+            await CreateStepAsync(isStartCountersign, workflow, nextStepBoxDefine, dto, EWorkflowStepStatus.Assigned, targetStepBox, targetStepBox.Steps.First(), cancellationToken);
 
             //flow manage
             if (workflow.IsInCountersign())
@@ -745,7 +743,7 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 创建开始节点(保存开始流程的办理意见,对应definition的start节点)
         /// </summary>
-        private async Task<(WorkflowStep stepBox, WorkflowStep step)> CreateStartStepAsync(Workflow workflow, BasicWorkflowDto dto, CancellationToken cancellationToken)
+        private async Task<(WorkflowStep stepBox, WorkflowStep step)> CreateStartStepAsync(Workflow workflow, BasicWorkflowDto dto, bool isStartCountersign, CancellationToken cancellationToken)
         {
             if (workflow.StepBoxes.Any())
                 throw UserFriendlyException.SameMessage("无法反复开始流程");
@@ -759,14 +757,14 @@ namespace Hotline.FlowEngine.Workflows
 
             //start节点的办理人分类默认为用户,即为当前发起流程的操作员
             var handler = new IdName { Id = _sessionContext.RequiredUserId, Name = _sessionContext.UserName };
-            await CreateStartSubStepAsync(handler, dto, stepBox, null, cancellationToken);
+            await CreateStartSubStepAsync(handler, dto, stepBox, cancellationToken);
             return (stepBox, stepBox.Steps.First());
         }
 
         /// <summary>
         /// 创建节点(不含开始、结束节点)
         /// </summary>
-        private async Task<WorkflowStep> CreateStepAsync(Workflow workflow, StepDefine stepBoxDefine, BasicWorkflowDto dto, EWorkflowStepStatus status,
+        private async Task<WorkflowStep> CreateStepAsync(bool isPrevStartCountersign, Workflow workflow, StepDefine stepBoxDefine, BasicWorkflowDto dto, EWorkflowStepStatus status,
             WorkflowStep? prevStepBox = null, WorkflowStep? prevStep = null, CancellationToken cancellationToken = default)
         {
             if (stepBoxDefine.StepType is EStepType.Start or EStepType.End)
@@ -792,7 +790,7 @@ namespace Hotline.FlowEngine.Workflows
                     return stepBox;
             }
 
-            await CreateSubStepsAsync(stepBoxDefine, dto, stepBox, status, prevStep, cancellationToken);
+            await CreateSubStepsAsync(isPrevStartCountersign, stepBoxDefine, dto, stepBox, status, prevStep, cancellationToken);
 
             return stepBox;
         }
@@ -801,15 +799,13 @@ namespace Hotline.FlowEngine.Workflows
             IdName handler,
             BasicWorkflowDto dto,
             WorkflowStep stepBox,
-            string? startCountersignId = null,
-            CancellationToken cancellationToken = default)
+            CancellationToken cancellationToken)
         {
-            var nextCountersignStatus = string.IsNullOrEmpty(startCountersignId)
-                ? EStepCountersignStatus.None
-                : EStepCountersignStatus.InCountersign;
-            var subStep = CreateSubStep(stepBox, handler, dto.NextStepCode, dto.NextMainHandler, null, startCountersignId, null,
-                EWorkflowStepStatus.Completed, nextCountersignStatus);
-            subStep.Accept(_sessionContext.RequiredUserId, _sessionContext.UserName, _sessionContext.RequiredOrgCode, _sessionContext.OrgName);
+            //开始节点既不发起会签,也不处于会签中
+            var subStep = CreateSubStep(stepBox, new List<IdName> { handler }, dto.NextStepCode, dto.NextMainHandler,
+                null, null, EWorkflowStepStatus.Completed, EStepCountersignStatus.None);
+            subStep.Accept(_sessionContext.RequiredUserId, _sessionContext.UserName,
+                _sessionContext.RequiredOrgCode, _sessionContext.OrgName);
             //step办理状态
             subStep.StepComplete(
                 _sessionContext.RequiredUserId, _sessionContext.UserName,
@@ -822,26 +818,26 @@ namespace Hotline.FlowEngine.Workflows
         }
 
         private async Task CreateSubStepsAsync(
+            bool isPrevStartCountersign,
             StepDefine stepBoxDefine,
             BasicWorkflowDto dto,
             WorkflowStep stepBox,
             EWorkflowStepStatus stepStatus,
-            WorkflowStep? prevStep = null,
+            WorkflowStep prevStep,
             CancellationToken cancellationToken = default)
         {
-            //开始节点无会签
-            var countersignStatus = prevStep?.GetNextStepCountersignStatus() ?? EStepCountersignStatus.None;
+            var countersignStatus = prevStep.GetNextStepCountersignStatus();
             List<WorkflowStep> subSteps;
             if (stepBoxDefine.HandlerType is EHandlerType.AssignUser or EHandlerType.AssignOrg)
             {
-                subSteps = CreateSubSteps(stepBox, stepBox.HandlerClassifies, dto.NextStepCode, dto.NextMainHandler,
+                subSteps = CreateSubSteps(isPrevStartCountersign, stepBox, stepBox.HandlerClassifies, dto.NextStepCode, dto.NextMainHandler,
                     prevStep?.Id, prevStep?.StartCountersignId, stepStatus, countersignStatus);
             }
             else
             {
                 if (stepBoxDefine.HandlerType != EHandlerType.Role && !dto.NextHandlers.Any())
                     throw new UserFriendlyException("未指定节点处理者");
-                subSteps = CreateSubSteps(stepBox, dto.NextHandlers, dto.NextStepCode, dto.NextMainHandler,
+                subSteps = CreateSubSteps(isPrevStartCountersign, stepBox, dto.NextHandlers, dto.NextStepCode, dto.NextMainHandler,
                     prevStep?.Id, prevStep?.StartCountersignId, stepStatus, countersignStatus);
             }
             stepBox.Steps.AddRange(subSteps);
@@ -887,7 +883,7 @@ namespace Hotline.FlowEngine.Workflows
             {
                 foreach (var step in stepBox.Steps)
                 {
-                    if (predicate(step.Status) && (step.HandlerId == orgCode || step.HandlerId == userId))
+                    if (predicate(step.Status) && (step.HandlerIds.Contains(orgCode) || step.HandlerIds.Contains(userId)))
                         return (stepBox, step);
                 }
             }
@@ -906,6 +902,7 @@ namespace Hotline.FlowEngine.Workflows
         }
 
         private List<WorkflowStep> CreateSubSteps(
+            bool isPrevStartContersign,
             WorkflowStep stepBox,
             List<IdName> handlers,
             string nextStepCode,
@@ -920,20 +917,23 @@ namespace Hotline.FlowEngine.Workflows
             if (countersignStatus is not EStepCountersignStatus.None && string.IsNullOrEmpty(countersignId))
                 throw UserFriendlyException.SameMessage("非法参数");
 
+            //依据是否发起会签创建step,发起会签表示一个handler创建一个step,未发起会签表示多人处理同一个节点,只创建一个step
             var steps = new List<WorkflowStep>();
-            foreach (var handler in handlers)
-            {
-                //var step = _mapper.Map<WorkflowStep>(stepBox);
-                //step.ParentId = stepBox.Id;
-                //step.HandlerId = handler.Id;
-                //step.IsMain = handler.Id == nextMainHandler;
-                //step.PreviousId = prevStepId;
-                //step.StartCountersignId = startCountersignId;
-                //step.CountersignId = countersignId;
-                //step.Status = stepStatus;
-
-                var step = CreateSubStep(stepBox, handler, nextMainHandler, nextStepCode,
-                    prevStepId, null, countersignId, stepStatus, countersignStatus);
+            if (isPrevStartContersign)
+            {
+                foreach (var handler in handlers)
+                {
+                    var step = CreateSubStep(stepBox, new List<IdName> { handler }, nextMainHandler, nextStepCode,
+                        prevStepId, countersignId, stepStatus, countersignStatus);
+
+                    steps.Add(step);
+                }
+            }
+            else
+            {
+                var step = CreateSubStep(stepBox, handlers, nextMainHandler, nextStepCode,
+                    prevStepId, countersignId, stepStatus, countersignStatus);
+
                 steps.Add(step);
             }
 
@@ -942,22 +942,25 @@ namespace Hotline.FlowEngine.Workflows
 
         private WorkflowStep CreateSubStep(
             WorkflowStep stepBox,
-            IdName handler,
+            List<IdName> handlers,
             string nextStepCode,
             string? nextMainHandler,
             string? prevStepId,
-            string? startCountersignId,
             string? countersignId,
             EWorkflowStepStatus stepStatus,
             EStepCountersignStatus countersignStatus)
         {
+            if (!handlers.Any())
+                throw new UserFriendlyException("非法参数");
             var step = _mapper.Map<WorkflowStep>(stepBox);
+            var handlerIds = handlers.Select(d => d.Id).ToList();
+            var isMain = handlers.Count > 1 || handlerIds.First() == nextMainHandler;
+
             step.ParentId = stepBox.Id;
-            step.HandlerId = handler.Id;
+            step.HandlerIds = handlerIds;
             step.NextStepCode = nextStepCode;
-            step.IsMain = handler.Id == nextMainHandler;
+            step.IsMain = isMain;
             step.PreviousId = prevStepId;
-            step.StartCountersignId = startCountersignId;
             step.CountersignId = countersignId;
             step.Status = stepStatus;
             step.StepCountersignStatus = countersignStatus;

+ 4 - 3
src/Hotline/FlowEngine/Workflows/WorkflowStep.cs

@@ -10,9 +10,10 @@ public class WorkflowStep : StepBasicEntity
 
     /// <summary>
     /// 被指派办理对象(依据不同指派方式可能为:depCode或userId),该字段subStep才会存在,stepBox不存在
+    /// 改为list,兼容多个办理对象可以办理同一个节点的场景
     /// </summary>
-    [SugarColumn(IsNullable = true)]
-    public string? HandlerId { get; set; }
+    [SugarColumn(ColumnDataType = "varchar(1000)", IsJson = true)]
+    public List<string> HandlerIds { get; set; } = new();
 
     /// <summary>
     /// 前一级节点Id(stepBox此字段为上级stepBoxId,step为上级stepId),汇总节点无此字段(可能有多个上级来源)
@@ -37,7 +38,7 @@ public class WorkflowStep : StepBasicEntity
     public List<WorkflowStep> Steps { get; set; } = new();
 
     #region 会签
-    
+
     /// <summary>
     /// 发起会签生成会签Id(不发起会签节点无此字段)
     /// </summary>