Browse Source

Merge branch 'master' of http://110.188.24.182:10023/Fengwo/hotline

田爽 1 year ago
parent
commit
6b6ea3caf0

+ 5 - 5
src/Hotline.Api/Controllers/EnforcementOrderController.cs

@@ -256,7 +256,7 @@ namespace Hotline.Api.Controllers
                 .Where(d => d.Order.Id != null)
                 .Where(d => d.Order.Id != null)
                 .Where(d => d.Order.CreationTime >= StartDate && d.Order.CreationTime <= EndDate)
                 .Where(d => d.Order.CreationTime >= StartDate && d.Order.CreationTime <= EndDate)
                 .GroupBy(d => d.Id)
                 .GroupBy(d => d.Id)
-                 .Select(d => new
+                 .Select(d => new EventClassificationOrderCountDto
                  {
                  {
                      TheClueIsTrue = SqlFunc.AggregateSum(SqlFunc.IIF(d.IsTheClueTrue.HasValue && d.IsTheClueTrue.Value == true, 1, 0)),
                      TheClueIsTrue = SqlFunc.AggregateSum(SqlFunc.IIF(d.IsTheClueTrue.HasValue && d.IsTheClueTrue.Value == true, 1, 0)),
                      TheClueIsNotTrue = SqlFunc.AggregateSum(SqlFunc.IIF(d.IsTheClueTrue.HasValue && d.IsTheClueTrue.Value == false, 1, 0)),
                      TheClueIsNotTrue = SqlFunc.AggregateSum(SqlFunc.IIF(d.IsTheClueTrue.HasValue && d.IsTheClueTrue.Value == false, 1, 0)),
@@ -267,10 +267,10 @@ namespace Hotline.Api.Controllers
 
 
             var orderCount = new
             var orderCount = new
             {
             {
-                TheClueIsTrue = data?[0].TheClueIsTrue,
-                TheClueIsNotTrue = data?[0].TheClueIsNotTrue,
-                EnforcementOrder = data?[0].EnforcementOrder,
-                PassTheBuckOrder = data?[0].PassTheBuckOrder
+                TheClueIsTrue = data.Sum(x => x.TheClueIsTrue),
+                TheClueIsNotTrue = data.Sum(x => x.TheClueIsNotTrue),
+                EnforcementOrder = data.Sum(x => x.EnforcementOrder),
+                PassTheBuckOrder = data.Sum(x => x.PassTheBuckOrder),
             };
             };
 
 
             return new { List = items, Total = total, OrderCount = orderCount };
             return new { List = items, Total = total, OrderCount = orderCount };

+ 50 - 85
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -98,7 +98,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         DateTime? expiredTime, CancellationToken cancellationToken = default)
         DateTime? expiredTime, CancellationToken cancellationToken = default)
     {
     {
         var validator = new StartWorkflowDtoValidator();
         var validator = new StartWorkflowDtoValidator();
-        var validResult = validator.Validate(dto);
+        var validResult = await validator.ValidateAsync(dto, cancellationToken);
         if (!validResult.IsValid)
         if (!validResult.IsValid)
             throw new UserFriendlyException(
             throw new UserFriendlyException(
                 $"非法参数, {string.Join(',', validResult.Errors.Select(d => d.ErrorMessage))}");
                 $"非法参数, {string.Join(',', validResult.Errors.Select(d => d.ErrorMessage))}");
@@ -144,12 +144,19 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId,
             _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId,
             externalId, cancellationToken);
             externalId, cancellationToken);
 
 
+        var startStepHandles = new List<WorkflowStepHandler>{WorkflowStepHandler.Create(workflow.Id, workflow.ExternalId,
+            EFlowAssignType.User, _sessionContext.RequiredUserId, _sessionContext.UserName,
+            _sessionContext.RequiredOrgId, _sessionContext.OrgName)};
+
         var startStep = _workflowDomainService.CreateStartStep(workflow, startStepDefine, dto,
         var startStep = _workflowDomainService.CreateStartStep(workflow, startStepDefine, dto,
-            new List<Kv> { new(_sessionContext.RequiredUserId, _sessionContext.UserName) }, expiredTime);
+            new List<Kv> { new(_sessionContext.RequiredUserId, _sessionContext.UserName) },
+            startStepHandles, expiredTime);
 
 
         var flowAssignInfo =
         var flowAssignInfo =
             await GetNextStepFlowAssignInfoAsync(workflow, startStep, dto, firstStepDefine, isNextDynamic, cancellationToken);
             await GetNextStepFlowAssignInfoAsync(workflow, startStep, dto, firstStepDefine, isNextDynamic, cancellationToken);
 
 
+        var firstStepHandlers = await GetNextStepHandlersAsync(workflow, firstStepDefine, dto, cancellationToken);
+
         var counterSignType = _workflowDomainService.GetCounterSignType(startStep.BusinessType);
         var counterSignType = _workflowDomainService.GetCounterSignType(startStep.BusinessType);
 
 
         //办理开始节点
         //办理开始节点
@@ -184,7 +191,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             _sessionContext.OrgName);
             _sessionContext.OrgName);
 
 
         await _workflowDomainService.StartAsync(workflow, startStep, dto, firstStepDefine, isNextDynamic,
         await _workflowDomainService.StartAsync(workflow, startStep, dto, firstStepDefine, isNextDynamic,
-            flowAssignInfo, counterSignType, expiredTime, cancellationToken);
+            flowAssignInfo, counterSignType, expiredTime, firstStepHandlers, cancellationToken);
 
 
         return workflow.Id;
         return workflow.Id;
     }
     }
@@ -252,8 +259,10 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         var flowAssignInfo =
         var flowAssignInfo =
             await GetNextStepFlowAssignInfoAsync(workflow, currentStep, dto, nextStepDefine, isNextDynamic, cancellationToken);
             await GetNextStepFlowAssignInfoAsync(workflow, currentStep, dto, nextStepDefine, isNextDynamic, cancellationToken);
 
 
+        var nextStepHandlers = await GetNextStepHandlersAsync(workflow, nextStepDefine, dto, cancellationToken);
+
         await _workflowDomainService.NextAsync(workflow, currentStep, dto, nextStepDefine, isNextDynamic,
         await _workflowDomainService.NextAsync(workflow, currentStep, dto, nextStepDefine, isNextDynamic,
-            flowAssignInfo, expiredTime, cancellationToken);
+            flowAssignInfo, expiredTime, nextStepHandlers, cancellationToken);
 
 
         return workflow;
         return workflow;
     }
     }
@@ -302,7 +311,9 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             dto.NextHandlers,
             dto.NextHandlers,
             cancellationToken);
             cancellationToken);
 
 
-        await _workflowDomainService.RecallAsync(workflow, dto, targetStepDefine, flowAssignInfo, expiredTime, cancellationToken);
+        var stepHandlers = await GetNextStepHandlersAsync(workflow, targetStepDefine, dto, cancellationToken);
+
+        await _workflowDomainService.RecallAsync(workflow, dto, targetStepDefine, flowAssignInfo, stepHandlers, expiredTime, cancellationToken);
     }
     }
 
 
     ///// <summary>
     ///// <summary>
@@ -339,10 +350,10 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             throw new UserFriendlyException("未找到实际办理节点");
             throw new UserFriendlyException("未找到实际办理节点");
 
 
         await _workflowDomainService.EndAsync(workflow, new BasicWorkflowDto
         await _workflowDomainService.EndAsync(workflow, new BasicWorkflowDto
-            {
-                Opinion = opinion,
-                Files = files
-            }, endStepDefine, currentStep,
+        {
+            Opinion = opinion,
+            Files = files
+        }, endStepDefine, currentStep,
             reviewResult, cancellationToken);
             reviewResult, cancellationToken);
     }
     }
 
 
@@ -623,13 +634,13 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             throw new UserFriendlyException("无效当前节点编号");
             throw new UserFriendlyException("无效当前节点编号");
         var quer = workflow.Steps.Where(d =>
         var quer = workflow.Steps.Where(d =>
             d.StepType != EStepType.End &&
             d.StepType != EStepType.End &&
-            d.IsOrigin );
+            d.IsOrigin);
         if (!isEnd)
         if (!isEnd)
         {
         {
             quer = quer.Where(d => d.Id != currentStep.Id);
             quer = quer.Where(d => d.Id != currentStep.Id);
         }
         }
         var originSteps = quer.ToList();
         var originSteps = quer.ToList();
-		var stepCodes = originSteps.Select(d => d.Code).ToList();
+        var stepCodes = originSteps.Select(d => d.Code).ToList();
         var stepDefines = workflow.WorkflowDefinition.FindStepDefines(stepCodes);
         var stepDefines = workflow.WorkflowDefinition.FindStepDefines(stepCodes);
 
 
         var dto = new NextStepsDto<RecallStepOption>
         var dto = new NextStepsDto<RecallStepOption>
@@ -1065,80 +1076,6 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         };
         };
     }
     }
 
 
-    //private async Task<IReadOnlyList<NextStepOption>> GetConfigStepsAsync(List<StepDefine> stepDefines,
-    //    CancellationToken cancellationToken)
-    //{
-    //    foreach (var stepDefine in stepDefines)
-    //    {
-    //        if (stepDefine.StepType == EStepType.End)
-    //            throw new UserFriendlyException("结束节点无待选项");
-
-    //        var handlers = new List<Kv>();
-    //        switch (stepDefine.HandlerType)
-    //        {
-    //            case EHandlerType.AssignedUser:
-    //            case EHandlerType.AssignedOrg:
-    //                handlers = stepDefine.HandlerTypeItems;
-    //                break;
-    //            case EHandlerType.Role:
-    //                //当前操作人所属部门的下级部门并且属于配置包含角色
-    //                var roles = await _roleRepository.Queryable()
-    //                    .Includes(d => d.Accounts.Where(x => !x.IsDeleted && x.Status == EAccountStatus.Normal).ToList(),
-    //                        x => x.User)
-    //                    .Where(d => stepDefine.HandlerTypeItems.Select(x => x.Key).Contains(d.Name))
-    //                    .ToListAsync(cancellationToken);
-    //                var users1 = roles.SelectMany(d => d.Accounts).Select(d => d.User);
-    //                handlers = users1.Select(d => new Kv(d.Id, d.Name)).ToList();
-    //                break;
-    //            case EHandlerType.OrgLevel:
-    //                //当前操作人所属部门的下级部门并且属于配置orgLevel的部门
-    //                var levels = stepDefine.HandlerTypeItems.Select(d => d.Key).Select(d => int.Parse(d));
-    //                var levelOneOrg = _sessionContext.RequiredOrgId.GetHigherOrgCode();
-    //                //var orgs1 = await _organizeRepository.QueryAsync(d =>
-    //                //    d.IsEnable && d.OrgCode.StartsWith(levelOneOrg) &&
-    //                //    levels.Contains(d.OrgLevel));
-
-    //                var orgs1 = await _organizeRepository.Queryable()
-    //                    .Where(d => d.IsEnable && levels.Contains(d.Level))
-    //                    .WhereIF(!levelOneOrg.IsCenter(), d => d.Id.StartsWith(levelOneOrg))
-    //                    .ToListAsync(cancellationToken);
-
-    //                handlers = orgs1.Select(d => new Kv(d.Id, d.Name)).ToList();
-    //                break;
-    //            case EHandlerType.OrgType:
-    //                var types = stepDefine.HandlerTypeItems.Select(d => d.Key)
-    //                    .Select(d => Enum.Parse<EOrgType>(d));
-    //                var levelOneOrg1 = _sessionContext.RequiredOrgId.GetHigherOrgCode();
-    //                //var org2 = await _organizeRepository.QueryAsync(d =>
-    //                //    d.IsEnable && d.OrgCode.StartsWith(levelOneOrg1) &&
-    //                //    types.Contains(d.OrgType));
-
-    //                var orgs2 = await _organizeRepository.Queryable()
-    //                    .Where(d => d.IsEnable && types.Contains(d.OrgType))
-    //                    .WhereIF(!levelOneOrg1.IsCenter(), d => d.Id.StartsWith(levelOneOrg1))
-    //                    .ToListAsync(cancellationToken);
-
-    //                handlers = orgs2.Select(d => new Kv(d.Id, d.Name)).ToList();
-    //                break;
-    //            default:
-    //                throw new ArgumentOutOfRangeException();
-    //        }
-
-    //        var dto = new NextStepOptionDto { Handlers = handlers };
-
-    //        if (stepDefine.Components.Contains(SysDicTypeConsts.OrderRedoReason))
-    //        {
-    //            var orderRedoReasons =
-    //                await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.OrderRedoReason,
-    //                    cancellationToken);
-    //            dto.OrderRedoReasonOptions = orderRedoReasons.Select(d => new Kv(d.DicDataValue, d.DicDataName)).ToList();
-    //        }
-
-    //        return dto;
-    //    }
-    //    throw new NotImplementedException();
-    //}
-
     /// <summary>
     /// <summary>
     /// 查询下一节点办理对象类型(user or org)及实际办理对象
     /// 查询下一节点办理对象类型(user or org)及实际办理对象
     /// </summary>
     /// </summary>
@@ -1203,6 +1140,34 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             cancellationToken);
             cancellationToken);
     }
     }
 
 
+    private async ValueTask<List<WorkflowStepHandler>> GetNextStepHandlersAsync(Workflow workflow,
+        StepDefine nextStepDefine, BasicWorkflowDto dto, CancellationToken cancellationToken)
+    {
+        var assignType = FlowAssignInfo.GetAssignType(nextStepDefine.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:
+                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>
     /// 按流程模板配置创建下一步办理对象
     /// 按流程模板配置创建下一步办理对象
     /// </summary>
     /// </summary>

+ 2 - 0
src/Hotline.Application/Mappers/WorkflowMapperConfigs.cs

@@ -84,5 +84,7 @@ public class WorkflowMapperConfigs : IRegister
             .IgnoreNonMapped(true)
             .IgnoreNonMapped(true)
             ;
             ;
 
 
+        config.ForType<BasicWorkflowDto, WorkflowStep>()
+            .Ignore(d => d.BusinessType);
     }
     }
 }
 }

+ 27 - 0
src/Hotline.Share/Dtos/JudicialManagement/EventClassificationOrderCountDto.cs

@@ -0,0 +1,27 @@
+namespace Hotline.Share.Dtos.JudicialManagement
+{
+    public class EventClassificationOrderCountDto
+    {
+        /// <summary>
+        /// 线索属实
+        /// </summary>
+        public int TheClueIsTrue { get; set; }
+        /// <summary>
+        /// 线索不属实
+        /// </summary>
+        public int TheClueIsNotTrue { get; set; }
+
+        /// <summary>
+        /// 行政执法类工单
+        /// </summary>
+        public int EnforcementOrder { get; set; }
+
+        /// <summary>
+        /// 推诿工单
+        /// </summary>
+        public int PassTheBuckOrder { get; set; }
+
+
+
+    }
+}

+ 8 - 4
src/Hotline/FlowEngine/Workflows/IWorkflowDomainService.cs

@@ -23,7 +23,7 @@ namespace Hotline.FlowEngine.Workflows
         /// </summary>
         /// </summary>
         Task StartAsync(Workflow workflow, WorkflowStep startStep, BasicWorkflowDto dto, StepDefine firstStepDefine,
         Task StartAsync(Workflow workflow, WorkflowStep startStep, BasicWorkflowDto dto, StepDefine firstStepDefine,
             bool isNextDynamic, FlowAssignInfo flowAssignInfo, ECounterSignType? counterSignType, DateTime? expiredTime,
             bool isNextDynamic, FlowAssignInfo flowAssignInfo, ECounterSignType? counterSignType, DateTime? expiredTime,
-            CancellationToken cancellationToken);
+            List<WorkflowStepHandler> stepHandlers, CancellationToken cancellationToken);
 
 
         /// <summary>
         /// <summary>
         /// 查询工作流
         /// 查询工作流
@@ -48,7 +48,7 @@ namespace Hotline.FlowEngine.Workflows
         /// 办理(流转至下一节点)
         /// 办理(流转至下一节点)
         /// </summary>
         /// </summary>
         Task NextAsync(Workflow workflow, WorkflowStep currentStep, NextWorkflowDto dto, StepDefine nextStepDefine,
         Task NextAsync(Workflow workflow, WorkflowStep currentStep, NextWorkflowDto dto, StepDefine nextStepDefine,
-            bool isNextDynamic, FlowAssignInfo flowAssignInfo, DateTime? expiredTime,
+            bool isNextDynamic, FlowAssignInfo flowAssignInfo, DateTime? expiredTime, List<WorkflowStepHandler> stepHandlers,
             CancellationToken cancellationToken);
             CancellationToken cancellationToken);
 
 
         /// <summary>
         /// <summary>
@@ -62,7 +62,7 @@ namespace Hotline.FlowEngine.Workflows
         /// 撤回(返回到之前任意节点)
         /// 撤回(返回到之前任意节点)
         /// </summary>
         /// </summary>
         Task RecallAsync(Workflow workflow, RecallDto dto, StepDefine targetStepDefine, FlowAssignInfo flowAssignInfo,
         Task RecallAsync(Workflow workflow, RecallDto dto, StepDefine targetStepDefine, FlowAssignInfo flowAssignInfo,
-            DateTime? expiredTime, CancellationToken cancellationToken);
+            List<WorkflowStepHandler> stepHandlers, DateTime? expiredTime, CancellationToken cancellationToken);
 
 
         /// <summary>
         /// <summary>
         /// 撤回至开始节点
         /// 撤回至开始节点
@@ -147,7 +147,7 @@ namespace Hotline.FlowEngine.Workflows
         /// 创建开始节点
         /// 创建开始节点
         /// </summary>
         /// </summary>
         WorkflowStep CreateStartStep(Workflow workflow, StepDefine startStepDefine, BasicWorkflowDto dto,
         WorkflowStep CreateStartStep(Workflow workflow, StepDefine startStepDefine, BasicWorkflowDto dto,
-            List<Kv> handlers, DateTime? expiredTime);
+            List<Kv> handlers, List<WorkflowStepHandler> stepHandlers, DateTime? expiredTime);
 
 
         /// <summary>
         /// <summary>
         /// 查询未完成节点
         /// 查询未完成节点
@@ -220,5 +220,9 @@ namespace Hotline.FlowEngine.Workflows
             IReadOnlyList<(string userId, string username, IReadOnlyList<string> stepIds)> handlers,
             IReadOnlyList<(string userId, string username, IReadOnlyList<string> stepIds)> handlers,
             CancellationToken cancellationToken);
             CancellationToken cancellationToken);
 
 
+        /// <summary>
+        /// 查询工单办理中的一级部门
+        /// </summary>
+        Task<ICollection<Kv>> GetLevelOneOrgsAsync(string workflowId, CancellationToken cancellation);
     }
     }
 }
 }

+ 80 - 35
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -98,7 +98,8 @@ namespace Hotline.FlowEngine.Workflows
         /// </summary>
         /// </summary>
         public async Task StartAsync(Workflow workflow, WorkflowStep startStep, BasicWorkflowDto dto,
         public async Task StartAsync(Workflow workflow, WorkflowStep startStep, BasicWorkflowDto dto,
             StepDefine firstStepDefine, bool isNextDynamic, FlowAssignInfo flowAssignInfo,
             StepDefine firstStepDefine, bool isNextDynamic, FlowAssignInfo flowAssignInfo,
-            ECounterSignType? counterSignType, DateTime? expiredTime, CancellationToken cancellationToken)
+            ECounterSignType? counterSignType, DateTime? expiredTime, List<WorkflowStepHandler> stepHandlers,
+            CancellationToken cancellationToken)
         {
         {
             //1. 创建first节点 (和trace)2.办理开始节点 
             //1. 创建first节点 (和trace)2.办理开始节点 
 
 
@@ -121,7 +122,7 @@ namespace Hotline.FlowEngine.Workflows
 
 
             //firststeps
             //firststeps
             var firstSteps = await CreateNextStepsAsync(workflow, startStep, dto, firstStepDefine,
             var firstSteps = await CreateNextStepsAsync(workflow, startStep, dto, firstStepDefine,
-                isNextDynamic, flowAssignInfo, expiredTime, cancellationToken);
+                isNextDynamic, flowAssignInfo, expiredTime, stepHandlers, cancellationToken);
             if (firstSteps.Any())
             if (firstSteps.Any())
                 workflow.Steps.AddRange(firstSteps);
                 workflow.Steps.AddRange(firstSteps);
 
 
@@ -193,7 +194,7 @@ namespace Hotline.FlowEngine.Workflows
             if (withCountersigns)
             if (withCountersigns)
                 query = query.Includes(d => d.Countersigns, x => x.Members);
                 query = query.Includes(d => d.Countersigns, x => x.Members);
             if (withSteps)
             if (withSteps)
-                query = query.Includes(d => d.Steps);
+                query = query.Includes(d => d.Steps, x => x.StepHandlers);
             //if (withTraces)
             //if (withTraces)
             //    query = query.Includes(d => d.Traces);
             //    query = query.Includes(d => d.Traces);
 
 
@@ -313,7 +314,7 @@ namespace Hotline.FlowEngine.Workflows
         /// </summary>
         /// </summary>
         public async Task NextAsync(Workflow workflow, WorkflowStep currentStep, NextWorkflowDto dto,
         public async Task NextAsync(Workflow workflow, WorkflowStep currentStep, NextWorkflowDto dto,
             StepDefine nextStepDefine, bool isNextDynamic, FlowAssignInfo flowAssignInfo,
             StepDefine nextStepDefine, bool isNextDynamic, FlowAssignInfo flowAssignInfo,
-            DateTime? expiredTime, CancellationToken cancellationToken)
+            DateTime? expiredTime, List<WorkflowStepHandler> stepHandlers, CancellationToken cancellationToken)
         {
         {
             ValidatePermission(workflow, _sessionContext.RequiredOrgId, _sessionContext.RequiredUserId);
             ValidatePermission(workflow, _sessionContext.RequiredOrgId, _sessionContext.RequiredUserId);
             //CheckWhetherRunnable(workflow.Status);
             //CheckWhetherRunnable(workflow.Status);
@@ -405,7 +406,10 @@ namespace Hotline.FlowEngine.Workflows
                     .ExecuteCommandAsync();
                     .ExecuteCommandAsync();
             }
             }
 
 
-            await _workflowStepRepository.UpdateRangeAsync(updateSteps, cancellationToken);
+            //await _workflowStepRepository.UpdateRangeAsync(updateSteps, cancellationToken);
+            await _workflowStepRepository.UpdateNav(updateSteps)
+                .Include(d => d.StepHandlers)
+                .ExecuteCommandAsync();
 
 
             await NextTraceAsync(workflow, dto, currentStep, cancellationToken);
             await NextTraceAsync(workflow, dto, currentStep, cancellationToken);
 
 
@@ -454,7 +458,7 @@ namespace Hotline.FlowEngine.Workflows
 
 
             //创建下一/N个节点(会签汇总节点:会签未全部办理时不创建,最后一个会签办理节点创建会签汇总节点)
             //创建下一/N个节点(会签汇总节点:会签未全部办理时不创建,最后一个会签办理节点创建会签汇总节点)
             var nextSteps = await CreateNextStepsAsync(workflow, currentStep, dto, nextStepDefine, isNextDynamic,
             var nextSteps = await CreateNextStepsAsync(workflow, currentStep, dto, nextStepDefine, isNextDynamic,
-                flowAssignInfo, expiredTime, cancellationToken);
+                flowAssignInfo, expiredTime, stepHandlers, cancellationToken);
 
 
             //赋值当前节点的下级办理节点
             //赋值当前节点的下级办理节点
             if (dto.IsStartCountersign
             if (dto.IsStartCountersign
@@ -693,6 +697,20 @@ namespace Hotline.FlowEngine.Workflows
             return steps.Select(d => d.WorkflowId).ToList();
             return steps.Select(d => d.WorkflowId).ToList();
         }
         }
 
 
+        /// <summary>
+        /// 查询工单办理中的一级部门
+        /// </summary>
+        public async Task<ICollection<Kv>> GetLevelOneOrgsAsync(string workflowId, CancellationToken cancellation)
+        {
+            var workflow = await GetWorkflowAsync(workflowId, withSteps: true, cancellationToken: cancellation);
+            return workflow.Steps.Where(d => d.BusinessType == EBusinessType.Department &&
+                                      d.HandlerType == EHandlerType.OrgLevel &&
+                                      d.StepHandlers.Any(d =>
+                                          !string.IsNullOrEmpty(d.OrgId) && d.OrgId.CheckIfOrgLevelIs(1)))
+                .Select(d => new Kv(d.StepHandlers.First().OrgId, d.StepHandlers.First().OrgName))
+                .ToList();
+        }
+
         /// <summary>
         /// <summary>
         /// 查找当前会签内所有节点(含start,end)
         /// 查找当前会签内所有节点(含start,end)
         /// </summary>
         /// </summary>
@@ -717,7 +735,8 @@ namespace Hotline.FlowEngine.Workflows
         /// 撤回(返回到之前任意节点)
         /// 撤回(返回到之前任意节点)
         /// </summary>
         /// </summary>
         public async Task RecallAsync(Workflow workflow, RecallDto dto, StepDefine targetStepDefine,
         public async Task RecallAsync(Workflow workflow, RecallDto dto, StepDefine targetStepDefine,
-            FlowAssignInfo flowAssignInfo, DateTime? expiredTime, CancellationToken cancellationToken)
+            FlowAssignInfo flowAssignInfo, List<WorkflowStepHandler> stepHandlers, DateTime? expiredTime,
+            CancellationToken cancellationToken)
         {
         {
             var targetStep = workflow.Steps.FirstOrDefault(d => d.Code == dto.NextStepCode && d.IsOrigin);
             var targetStep = workflow.Steps.FirstOrDefault(d => d.Code == dto.NextStepCode && d.IsOrigin);
             if (targetStep is null)
             if (targetStep is null)
@@ -727,7 +746,7 @@ namespace Hotline.FlowEngine.Workflows
             await RecallTraceAsync(workflow.Id, dto.Opinion, cancellationToken);
             await RecallTraceAsync(workflow.Id, dto.Opinion, cancellationToken);
 
 
             var isOrgToCenter = await RecallAsync(workflow, dto, flowAssignInfo, targetStepDefine, targetStep,
             var isOrgToCenter = await RecallAsync(workflow, dto, flowAssignInfo, targetStepDefine, targetStep,
-                EWorkflowTraceStatus.Recall, expiredTime, cancellationToken);
+                EWorkflowTraceStatus.Recall, stepHandlers, expiredTime, cancellationToken);
 
 
             workflow.ResetHandlers(flowAssignInfo.FlowAssignType, flowAssignInfo.HandlerObjects);
             workflow.ResetHandlers(flowAssignInfo.FlowAssignType, flowAssignInfo.HandlerObjects);
 
 
@@ -1075,7 +1094,7 @@ namespace Hotline.FlowEngine.Workflows
         /// 创建开始节点
         /// 创建开始节点
         /// </summary>
         /// </summary>
         public WorkflowStep CreateStartStep(Workflow workflow, StepDefine startStepDefine,
         public WorkflowStep CreateStartStep(Workflow workflow, StepDefine startStepDefine,
-            BasicWorkflowDto dto, List<Kv> handles, DateTime? expiredTime)
+            BasicWorkflowDto dto, List<Kv> handles, List<WorkflowStepHandler> stepHandlers, DateTime? expiredTime)
         {
         {
             //startstep
             //startstep
             var nextSteps = _mapper.Map<List<StepSimple>>(startStepDefine.NextSteps);
             var nextSteps = _mapper.Map<List<StepSimple>>(startStepDefine.NextSteps);
@@ -1090,6 +1109,7 @@ namespace Hotline.FlowEngine.Workflows
             _mapper.Map(dto, startStep);
             _mapper.Map(dto, startStep);
             _mapper.Map(workflow, startStep);
             _mapper.Map(workflow, startStep);
             startStep.Handlers = handles;
             startStep.Handlers = handles;
+            startStep.StepHandlers = stepHandlers;
             startStep.NextSteps = nextSteps;
             startStep.NextSteps = nextSteps;
             startStep.IsMain = true;
             startStep.IsMain = true;
             startStep.IsOrigin = true;
             startStep.IsOrigin = true;
@@ -1115,8 +1135,12 @@ namespace Hotline.FlowEngine.Workflows
             WorkflowStep currentStep, EReviewResult? reviewResult = EReviewResult.Unknown,
             WorkflowStep currentStep, EReviewResult? reviewResult = EReviewResult.Unknown,
             CancellationToken cancellationToken = default)
             CancellationToken cancellationToken = default)
         {
         {
+            var endStepHandles = new List<WorkflowStepHandler>{WorkflowStepHandler.Create(workflow.Id, workflow.ExternalId,
+                EFlowAssignType.User, _sessionContext.RequiredUserId, _sessionContext.UserName,
+                _sessionContext.RequiredOrgId, _sessionContext.OrgName)};
+
             //create endStep
             //create endStep
-            var endStep = await CreateEndStepAsync(workflow, endStepDefine, currentStep, cancellationToken);
+            var endStep = await CreateEndStepAsync(workflow, endStepDefine, currentStep, endStepHandles, cancellationToken);
             workflow.Steps.Add(endStep);
             workflow.Steps.Add(endStep);
 
 
             //update endTrace
             //update endTrace
@@ -1222,11 +1246,14 @@ namespace Hotline.FlowEngine.Workflows
         }
         }
 
 
         private async Task<WorkflowStep> CreateStartStepAsync(Workflow workflow, StepDefine startStepDefine,
         private async Task<WorkflowStep> CreateStartStepAsync(Workflow workflow, StepDefine startStepDefine,
-            BasicWorkflowDto dto, List<Kv> handles, EWorkflowTraceStatus traceStatus, DateTime? expiredTime,
-            CancellationToken cancellationToken)
+            BasicWorkflowDto dto, List<Kv> handles, List<WorkflowStepHandler> stepHandlers, EWorkflowTraceStatus traceStatus,
+            DateTime? expiredTime, CancellationToken cancellationToken)
         {
         {
-            var startStep = CreateStartStep(workflow, startStepDefine, dto, handles, expiredTime);
-            await _workflowStepRepository.AddAsync(startStep, cancellationToken);
+            var startStep = CreateStartStep(workflow, startStepDefine, dto, handles, stepHandlers, expiredTime);
+            //await _workflowStepRepository.AddAsync(startStep, cancellationToken);
+            await _workflowStepRepository.AddNav(startStep)
+                .Include(d => d.StepHandlers)
+                .ExecuteCommandAsync();
             await CreateTraceAsync(workflow, startStep, traceStatus, cancellationToken);
             await CreateTraceAsync(workflow, startStep, traceStatus, cancellationToken);
             return startStep;
             return startStep;
         }
         }
@@ -1250,7 +1277,7 @@ namespace Hotline.FlowEngine.Workflows
         /// </summary>
         /// </summary>
         private async Task<List<WorkflowStep>> CreateNextStepsAsync(Workflow workflow, WorkflowStep currentStep,
         private async Task<List<WorkflowStep>> CreateNextStepsAsync(Workflow workflow, WorkflowStep currentStep,
             BasicWorkflowDto dto, StepDefine nextStepDefine, bool isNextDynamic, FlowAssignInfo flowAssignInfo,
             BasicWorkflowDto dto, StepDefine nextStepDefine, bool isNextDynamic, FlowAssignInfo flowAssignInfo,
-            DateTime? expiredTime, CancellationToken cancellationToken)
+            DateTime? expiredTime, List<WorkflowStepHandler> stepHandlers, CancellationToken cancellationToken)
         {
         {
             List<WorkflowStep> nextSteps = new();
             List<WorkflowStep> nextSteps = new();
             if (currentStep.IsInCountersign())
             if (currentStep.IsInCountersign())
@@ -1265,13 +1292,13 @@ namespace Hotline.FlowEngine.Workflows
                         {
                         {
                             //依据会签策略创建会签下一级节点
                             //依据会签策略创建会签下一级节点
                             nextSteps = await CreateCountersignStepsAsync(workflow, nextStepDefine, currentStep, dto,
                             nextSteps = await CreateCountersignStepsAsync(workflow, nextStepDefine, currentStep, dto,
-                                flowAssignInfo.FlowAssignType, expiredTime, cancellationToken);
+                                flowAssignInfo.FlowAssignType, expiredTime, stepHandlers, cancellationToken);
                         }
                         }
                         else
                         else
                         {
                         {
                             //创建普通节点(根据配置)
                             //创建普通节点(根据配置)
                             nextSteps = await CreateConfigStepsAsync(workflow, nextStepDefine, currentStep, dto,
                             nextSteps = await CreateConfigStepsAsync(workflow, nextStepDefine, currentStep, dto,
-                                flowAssignInfo, EWorkflowTraceStatus.Normal, expiredTime, cancellationToken);
+                                flowAssignInfo, EWorkflowTraceStatus.Normal, expiredTime, stepHandlers, cancellationToken);
                         }
                         }
                     }
                     }
                     else
                     else
@@ -1298,7 +1325,7 @@ namespace Hotline.FlowEngine.Workflows
                     {
                     {
                         //依据会签策略创建会签下一级节点
                         //依据会签策略创建会签下一级节点
                         nextSteps = await CreateCountersignStepsAsync(workflow, nextStepDefine, currentStep, dto,
                         nextSteps = await CreateCountersignStepsAsync(workflow, nextStepDefine, currentStep, dto,
-                            flowAssignInfo.FlowAssignType, expiredTime, cancellationToken);
+                            flowAssignInfo.FlowAssignType, expiredTime, stepHandlers, cancellationToken);
                     }
                     }
                 }
                 }
             }
             }
@@ -1306,19 +1333,19 @@ namespace Hotline.FlowEngine.Workflows
             {
             {
                 //依据会签策略创建会签下一级节点
                 //依据会签策略创建会签下一级节点
                 nextSteps = await CreateCountersignStepsAsync(workflow, nextStepDefine, currentStep, dto,
                 nextSteps = await CreateCountersignStepsAsync(workflow, nextStepDefine, currentStep, dto,
-                    flowAssignInfo.FlowAssignType, expiredTime, cancellationToken);
+                    flowAssignInfo.FlowAssignType, expiredTime, stepHandlers, cancellationToken);
             }
             }
             else if (isNextDynamic)
             else if (isNextDynamic)
             {
             {
                 //创建动态下一级节点
                 //创建动态下一级节点
                 nextSteps = await CreateDynamicStepsAsync(workflow, nextStepDefine, currentStep, dto, flowAssignInfo,
                 nextSteps = await CreateDynamicStepsAsync(workflow, nextStepDefine, currentStep, dto, flowAssignInfo,
-                    expiredTime, cancellationToken);
+                    expiredTime, stepHandlers, cancellationToken);
             }
             }
             else
             else
             {
             {
                 //创建普通节点(根据配置)
                 //创建普通节点(根据配置)
                 nextSteps = await CreateConfigStepsAsync(workflow, nextStepDefine, currentStep, dto, flowAssignInfo,
                 nextSteps = await CreateConfigStepsAsync(workflow, nextStepDefine, currentStep, dto, flowAssignInfo,
-                    EWorkflowTraceStatus.Normal, expiredTime, cancellationToken);
+                    EWorkflowTraceStatus.Normal, expiredTime, stepHandlers, cancellationToken);
             }
             }
 
 
             return nextSteps;
             return nextSteps;
@@ -1331,6 +1358,7 @@ namespace Hotline.FlowEngine.Workflows
             BasicWorkflowDto dto,
             BasicWorkflowDto dto,
             FlowAssignInfo flowAssignInfo,
             FlowAssignInfo flowAssignInfo,
             DateTime? expiredTime,
             DateTime? expiredTime,
+            List<WorkflowStepHandler> stepHandlers,
             CancellationToken cancellationToken)
             CancellationToken cancellationToken)
         {
         {
             var handlerType = nextStepDefine.InstancePolicy switch
             var handlerType = nextStepDefine.InstancePolicy switch
@@ -1344,7 +1372,7 @@ namespace Hotline.FlowEngine.Workflows
             };
             };
 
 
             return await CreateStepsAsync(workflow, nextStepDefine, prevStep, dto,
             return await CreateStepsAsync(workflow, nextStepDefine, prevStep, dto,
-                flowAssignInfo.FlowAssignType, dto.NextHandlers, null, EWorkflowStepStatus.WaitForAccept,
+                flowAssignInfo.FlowAssignType, dto.NextHandlers, stepHandlers, null, EWorkflowStepStatus.WaitForAccept,
                 ECountersignPosition.None, false, EWorkflowTraceStatus.Normal, handlerType, expiredTime, cancellationToken);
                 ECountersignPosition.None, false, EWorkflowTraceStatus.Normal, handlerType, expiredTime, cancellationToken);
         }
         }
 
 
@@ -1355,6 +1383,7 @@ namespace Hotline.FlowEngine.Workflows
             BasicWorkflowDto dto,
             BasicWorkflowDto dto,
             EFlowAssignType flowAssignType,
             EFlowAssignType flowAssignType,
             DateTime? expiredTime,
             DateTime? expiredTime,
+            List<WorkflowStepHandler> stepHandlers,
             CancellationToken cancellationToken
             CancellationToken cancellationToken
         )
         )
         {
         {
@@ -1370,7 +1399,7 @@ namespace Hotline.FlowEngine.Workflows
                 _ => throw new ArgumentOutOfRangeException()
                 _ => throw new ArgumentOutOfRangeException()
             };
             };
 
 
-            return CreateStepsAsync(workflow, stepDefine, prevStep, dto, flowAssignType, dto.NextHandlers,
+            return CreateStepsAsync(workflow, stepDefine, prevStep, dto, flowAssignType, dto.NextHandlers, stepHandlers,
                 countersignId, EWorkflowStepStatus.WaitForAccept, prevStep.GetNextStepCountersignPosition(),
                 countersignId, EWorkflowStepStatus.WaitForAccept, prevStep.GetNextStepCountersignPosition(),
                 false, EWorkflowTraceStatus.Normal, handlerType, expiredTime, cancellationToken);
                 false, EWorkflowTraceStatus.Normal, handlerType, expiredTime, cancellationToken);
         }
         }
@@ -1388,7 +1417,7 @@ namespace Hotline.FlowEngine.Workflows
             //会签未全部办理则不创建汇总节点
             //会签未全部办理则不创建汇总节点
             if (prevStep.StartedCountersignHasAllHandled())
             if (prevStep.StartedCountersignHasAllHandled())
             {
             {
-                //todo 创建会签汇总节点
+                // 创建会签汇总节点
                 var countersignEndStep =
                 var countersignEndStep =
                     await CreateCountersignEndStepAsync(prevStep, dto, expiredTime, cancellationToken);
                     await CreateCountersignEndStepAsync(prevStep, dto, expiredTime, cancellationToken);
                 nextSteps = new List<WorkflowStep> { countersignEndStep };
                 nextSteps = new List<WorkflowStep> { countersignEndStep };
@@ -1456,6 +1485,10 @@ namespace Hotline.FlowEngine.Workflows
                 _sessionContext.RequiredOrgId, _sessionContext.OrgName,
                 _sessionContext.RequiredOrgId, _sessionContext.OrgName,
                 _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName,
                 _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName,
                 _sessionContext.OrgIsCenter, opinion, nextStepCode);
                 _sessionContext.OrgIsCenter, opinion, nextStepCode);
+
+            var handler = step.FindActualHandler(_sessionContext.Roles, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId);
+            if (handler is not null)
+                handler.IsActualHandler = true;
         }
         }
 
 
 
 
@@ -1723,7 +1756,7 @@ namespace Hotline.FlowEngine.Workflows
 
 
         private async Task<bool> RecallAsync(Workflow workflow, BasicWorkflowDto dto, FlowAssignInfo flowAssignInfo,
         private async Task<bool> RecallAsync(Workflow workflow, BasicWorkflowDto dto, FlowAssignInfo flowAssignInfo,
             StepDefine targetStepDefine, WorkflowStep targetStep, EWorkflowTraceStatus traceStatus,
             StepDefine targetStepDefine, WorkflowStep targetStep, EWorkflowTraceStatus traceStatus,
-            DateTime? expiredTime, CancellationToken cancellationToken)
+            List<WorkflowStepHandler> stepHandlers, DateTime? expiredTime, CancellationToken cancellationToken)
         {
         {
             var targetIsStartStep = targetStepDefine.StepType is EStepType.Start;
             var targetIsStartStep = targetStepDefine.StepType is EStepType.Start;
 
 
@@ -1750,10 +1783,10 @@ namespace Hotline.FlowEngine.Workflows
                 workflow.SetStatusRunnable();
                 workflow.SetStatusRunnable();
 
 
             var targetStepNew = targetIsStartStep
             var targetStepNew = targetIsStartStep
-                ? await CreateStartStepAsync(workflow, targetStepDefine, dto, dto.NextHandlers, traceStatus, expiredTime,
+                ? await CreateStartStepAsync(workflow, targetStepDefine, dto, dto.NextHandlers, stepHandlers, traceStatus, expiredTime,
                     cancellationToken)
                     cancellationToken)
                 : (await CreateStepsAsync(workflow, targetStepDefine, targetPrevStep, dto,
                 : (await CreateStepsAsync(workflow, targetStepDefine, targetPrevStep, dto,
-                    flowAssignInfo.FlowAssignType, dto.NextHandlers,
+                    flowAssignInfo.FlowAssignType, dto.NextHandlers, stepHandlers,
                     null, EWorkflowStepStatus.WaitForAccept, ECountersignPosition.None, true, traceStatus,
                     null, EWorkflowStepStatus.WaitForAccept, ECountersignPosition.None, true, traceStatus,
                     null, expiredTime, cancellationToken)).First();
                     null, expiredTime, cancellationToken)).First();
 
 
@@ -1804,6 +1837,7 @@ namespace Hotline.FlowEngine.Workflows
             Workflow workflow,
             Workflow workflow,
             StepDefine endStepDefine,
             StepDefine endStepDefine,
             WorkflowStep prevStep,
             WorkflowStep prevStep,
+            List<WorkflowStepHandler> stepHandlers,
             CancellationToken cancellationToken)
             CancellationToken cancellationToken)
         {
         {
             if (workflow.Steps.Any(d => d.StepType == EStepType.End))
             if (workflow.Steps.Any(d => d.StepType == EStepType.End))
@@ -1812,8 +1846,8 @@ namespace Hotline.FlowEngine.Workflows
             var handler = new Kv { Key = _sessionContext.RequiredUserId, Value = _sessionContext.UserName };
             var handler = new Kv { Key = _sessionContext.RequiredUserId, Value = _sessionContext.UserName };
 
 
             var step = CreateStep(workflow, endStepDefine, prevStep, null, new List<Kv> { handler },
             var step = CreateStep(workflow, endStepDefine, prevStep, null, new List<Kv> { handler },
-                null, null, null, EWorkflowStepStatus.WaitForAccept, ECountersignPosition.None, DateTime.Now,
-                endStepDefine.Name, true);
+              stepHandlers, null, null, null, EWorkflowStepStatus.WaitForAccept,
+              ECountersignPosition.None, DateTime.Now, endStepDefine.Name, true);
 
 
             //step.Accept(_sessionContext.RequiredUserId, _sessionContext.UserName,
             //step.Accept(_sessionContext.RequiredUserId, _sessionContext.UserName,
             //    _sessionContext.RequiredOrgId, _sessionContext.OrgName,
             //    _sessionContext.RequiredOrgId, _sessionContext.OrgName,
@@ -1837,6 +1871,7 @@ namespace Hotline.FlowEngine.Workflows
             FlowAssignInfo flowAssignInfo,
             FlowAssignInfo flowAssignInfo,
             EWorkflowTraceStatus traceStatus,
             EWorkflowTraceStatus traceStatus,
             DateTime? expiredTime,
             DateTime? expiredTime,
+            List<WorkflowStepHandler> stepHandlers,
             CancellationToken cancellationToken)
             CancellationToken cancellationToken)
         {
         {
             List<Kv> handlers;
             List<Kv> handlers;
@@ -1859,8 +1894,8 @@ namespace Hotline.FlowEngine.Workflows
             }
             }
 
 
             return await CreateStepsAsync(workflow, stepDefine, prevStep, dto, flowAssignInfo.FlowAssignType, handlers,
             return await CreateStepsAsync(workflow, stepDefine, prevStep, dto, flowAssignInfo.FlowAssignType, handlers,
-                null, EWorkflowStepStatus.WaitForAccept, ECountersignPosition.None, true, traceStatus,
-                null, expiredTime, cancellationToken);
+                stepHandlers, null, EWorkflowStepStatus.WaitForAccept, ECountersignPosition.None,
+                true, traceStatus, null, expiredTime, cancellationToken);
         }
         }
 
 
         private async Task<List<WorkflowStep>> CreateStepsAsync(
         private async Task<List<WorkflowStep>> CreateStepsAsync(
@@ -1870,6 +1905,7 @@ namespace Hotline.FlowEngine.Workflows
             BasicWorkflowDto dto,
             BasicWorkflowDto dto,
             EFlowAssignType? flowAssignType,
             EFlowAssignType? flowAssignType,
             List<Kv> handlers,
             List<Kv> handlers,
+            List<WorkflowStepHandler> stepHandlers,
             string? countersignId,
             string? countersignId,
             EWorkflowStepStatus stepStatus,
             EWorkflowStepStatus stepStatus,
             ECountersignPosition csPosition,
             ECountersignPosition csPosition,
@@ -1890,7 +1926,7 @@ namespace Hotline.FlowEngine.Workflows
                 foreach (var handler in handlers)
                 foreach (var handler in handlers)
                 {
                 {
                     var step = CreateStep(workflow, stepDefine, prevStep, flowAssignType, new List<Kv> { handler },
                     var step = CreateStep(workflow, stepDefine, prevStep, flowAssignType, new List<Kv> { handler },
-                        dto.NextStepCode, dto.NextMainHandler, countersignId,
+                        stepHandlers, dto.NextStepCode, dto.NextMainHandler, countersignId,
                         stepStatus, csPosition, expiredTime, dto.NextStepName, isOrigin, handlerType);
                         stepStatus, csPosition, expiredTime, dto.NextStepName, isOrigin, handlerType);
 
 
                     steps.Add(step);
                     steps.Add(step);
@@ -1898,14 +1934,17 @@ namespace Hotline.FlowEngine.Workflows
             }
             }
             else
             else
             {
             {
-                var step = CreateStep(workflow, stepDefine, prevStep, flowAssignType, handlers,
+                var step = CreateStep(workflow, stepDefine, prevStep, flowAssignType, handlers, stepHandlers,
                     dto.NextStepCode, dto.NextMainHandler, countersignId,
                     dto.NextStepCode, dto.NextMainHandler, countersignId,
                     stepStatus, csPosition, expiredTime, dto.NextStepName, isOrigin, handlerType);
                     stepStatus, csPosition, expiredTime, dto.NextStepName, isOrigin, handlerType);
 
 
                 steps.Add(step);
                 steps.Add(step);
             }
             }
 
 
-            await _workflowStepRepository.AddRangeAsync(steps, cancellationToken);
+            //await _workflowStepRepository.AddRangeAsync(steps, cancellationToken);
+            await _workflowStepRepository.AddNav(steps)
+                .Include(d => d.StepHandlers)
+                .ExecuteCommandAsync();
 
 
             //create traces todo add range traces
             //create traces todo add range traces
             foreach (var step in steps)
             foreach (var step in steps)
@@ -2158,6 +2197,7 @@ namespace Hotline.FlowEngine.Workflows
             WorkflowStep prevStep,
             WorkflowStep prevStep,
             EFlowAssignType? flowAssignType,
             EFlowAssignType? flowAssignType,
             List<Kv> handlers,
             List<Kv> handlers,
+            List<WorkflowStepHandler> stepHandlers,
             string nextStepCode,
             string nextStepCode,
             string? nextMainHandler,
             string? nextMainHandler,
             string? countersignId,
             string? countersignId,
@@ -2166,7 +2206,8 @@ namespace Hotline.FlowEngine.Workflows
             DateTime? expiredTime,
             DateTime? expiredTime,
             string stepName,
             string stepName,
             bool isOrigin,
             bool isOrigin,
-            EHandlerType? handlerType = null //动态节点依据动态策略判断
+            EHandlerType? handlerType = null, //动态节点依据动态策略判断
+            string? opinion = null//汇总以及会签汇总节点需要提前为option赋值之前办理节点内容
         )
         )
         {
         {
             if (!handlers.Any())
             if (!handlers.Any())
@@ -2178,6 +2219,7 @@ namespace Hotline.FlowEngine.Workflows
 
 
             step.FlowAssignType = flowAssignType;
             step.FlowAssignType = flowAssignType;
             step.Handlers = handlers;
             step.Handlers = handlers;
+            step.StepHandlers = stepHandlers;
             step.NextStepCode = step.StepType is EStepType.End ? string.Empty : nextStepCode;
             step.NextStepCode = step.StepType is EStepType.End ? string.Empty : nextStepCode;
             step.IsMain = isMain;
             step.IsMain = isMain;
             step.PrevStepId = prevStep.Id;
             step.PrevStepId = prevStep.Id;
@@ -2193,6 +2235,9 @@ namespace Hotline.FlowEngine.Workflows
             if (handlerType.HasValue)
             if (handlerType.HasValue)
                 step.HandlerType = handlerType.Value;
                 step.HandlerType = handlerType.Value;
 
 
+            if(!string.IsNullOrEmpty(opinion))
+                step.Opinion = opinion;
+
             return step;
             return step;
         }
         }
 
 

+ 12 - 2
src/Hotline/FlowEngine/Workflows/WorkflowStep.cs

@@ -38,7 +38,6 @@ public class WorkflowStep : StepBasicEntity
     /// </summary>
     /// </summary>
     public bool IsOrigin { get; set; }
     public bool IsOrigin { get; set; }
 
 
-
     #region 会签
     #region 会签
 
 
     /// <summary>
     /// <summary>
@@ -92,10 +91,14 @@ public class WorkflowStep : StepBasicEntity
     [Navigate(NavigateType.ManyToOne, nameof(WorkflowId))]
     [Navigate(NavigateType.ManyToOne, nameof(WorkflowId))]
     public Workflow Workflow { get; set; }
     public Workflow Workflow { get; set; }
 
 
-    [Navigate(NavigateType.OneToOne, nameof(Id), 
+    [Navigate(NavigateType.OneToOne, nameof(Id),
         nameof(Workflows.WorkflowTrace.StepId))]
         nameof(Workflows.WorkflowTrace.StepId))]
     public WorkflowTrace WorkflowTrace { get; set; }
     public WorkflowTrace WorkflowTrace { get; set; }
 
 
+    [Navigate(NavigateType.OneToMany, nameof(Id),
+        nameof(WorkflowStepHandler.WorkflowStepId))]
+    public List<WorkflowStepHandler> StepHandlers { get; set; }
+
     #region Method
     #region Method
 
 
     /// <summary>
     /// <summary>
@@ -256,6 +259,13 @@ public class WorkflowStep : StepBasicEntity
         return IsCountersignEndStep && CountersignStartStepId == topCountersignStepId;
         return IsCountersignEndStep && CountersignStartStepId == topCountersignStepId;
     }
     }
 
 
+    public WorkflowStepHandler?
+        FindActualHandler(ICollection<string> roles, string? userId = null, string? orgId = null) =>
+        StepHandlers.FirstOrDefault(d => d.IsHandler(roles, userId, orgId));
+
+    public WorkflowStepHandler? GetActualHandler() =>
+        StepHandlers.FirstOrDefault(d => d.IsActualHandler);
+
     #endregion
     #endregion
 }
 }
 
 

+ 114 - 0
src/Hotline/FlowEngine/Workflows/WorkflowStepHandler.cs

@@ -0,0 +1,114 @@
+using Hotline.Share.Dtos;
+using SqlSugar;
+using XF.Domain.Entities;
+using XF.Domain.Exceptions;
+using XF.Domain.Repository;
+
+namespace Hotline.FlowEngine.Workflows;
+
+public class WorkflowStepHandler : CreationEntity
+{
+    public string WorkflowId { get; set; }
+    public string ExternalId { get; set; }
+    public string WorkflowStepId { get; set; }
+
+    /// <summary>
+    /// 流程指派类型
+    /// </summary>
+    public EFlowAssignType FlowAssignType { get; set; }
+
+    public string? UserId { get; set; }
+    public string? Username { get; set; }
+    public string? OrgId { get; set; }
+    public string? OrgName { get; set; }
+    public string? RoleId { get; set; }
+    public string? RoleName { get; set; }
+
+    /// <summary>
+    /// 是否为实际办理者
+    /// </summary>
+    public bool IsActualHandler { get; set; }
+
+    [Navigate(NavigateType.ManyToOne, nameof(WorkflowStepId))]
+    public WorkflowStep WorkflowStep { get; set; }
+
+    #region method
+
+    public static WorkflowStepHandler Create(string workflowId, string externalId, EFlowAssignType flowAssignType, string? userId = null, string? username = null,
+        string? orgId = null, string? orgName = null, string? roleId = null, string? roleName = null)
+    {
+        var handler = new WorkflowStepHandler
+        {
+            WorkflowId = workflowId,
+            ExternalId = externalId,
+        };
+        handler.Assign(flowAssignType, userId, username, orgId, orgName, roleId, roleName);
+        return handler;
+    }
+
+    public void Assign(EFlowAssignType assignType, string? userId, string? username,
+        string? orgId, string? orgName, string? roleId, string? roleName)
+    {
+        FlowAssignType = assignType;
+        switch (assignType)
+        {
+            case EFlowAssignType.Org:
+                if (string.IsNullOrEmpty(orgId) || string.IsNullOrEmpty(orgName))
+                    throw new ArgumentNullException(nameof(orgId));
+                OrgId = orgId;
+                OrgName = orgName;
+                break;
+            case EFlowAssignType.User:
+                if (string.IsNullOrEmpty(userId) || string.IsNullOrEmpty(username) ||
+                   string.IsNullOrEmpty(orgId) || string.IsNullOrEmpty(orgName))
+                    throw new ArgumentNullException(nameof(userId));
+                UserId = userId;
+                Username = username;
+                OrgId = orgId;
+                OrgName = orgName;
+                break;
+            //case EFlowAssignType.Role:
+            //    if (string.IsNullOrEmpty(roleId) || string.IsNullOrEmpty(roleName))
+            //        throw new ArgumentNullException(nameof(roleId));
+            //    RoleId = roleId;
+            //    RoleName = roleName;
+            //    break;
+            default:
+                throw new ArgumentOutOfRangeException(nameof(assignType), assignType, null);
+        }
+    }
+
+    public bool IsHandler(ICollection<string> roleIds, string? userId = null, string? orgId = null)
+    {
+        switch (FlowAssignType)
+        {
+            case EFlowAssignType.Org:
+                if (string.IsNullOrEmpty(OrgId))
+                    throw new UserFriendlyException($"数据异常, {nameof(OrgId)}");
+                return OrgId.Equals(orgId, StringComparison.OrdinalIgnoreCase);
+            case EFlowAssignType.User:
+                if (string.IsNullOrEmpty(UserId))
+                    throw new UserFriendlyException($"数据异常, {nameof(UserId)}");
+                return UserId.Equals(userId, StringComparison.OrdinalIgnoreCase);
+            //case EFlowAssignType.Role:
+            //    if (string.IsNullOrEmpty(RoleId))
+            //        throw new UserFriendlyException($"数据异常, {nameof(RoleId)}");
+            //    return roleIds.Any() && roleIds.Contains(RoleId, StringComparer.OrdinalIgnoreCase);
+            default:
+                throw new ArgumentOutOfRangeException();
+        }
+    }
+
+    public Kv GetHandler()
+    {
+        return FlowAssignType switch
+        {
+            EFlowAssignType.Org => new Kv(OrgId, OrgName),
+            EFlowAssignType.User => new Kv(UserId, Username),
+            //EFlowAssignType.Role => new Kv(RoleId, RoleName),
+            _ => throw new ArgumentOutOfRangeException()
+        };
+    }
+
+    #endregion
+}