Przeglądaj źródła

fixed: 拆分下一节点待选参数查询方式

xf 2 lat temu
rodzic
commit
36732d51b3

+ 2 - 2
src/Hotline.Api/Controllers/KnowledgeController.cs

@@ -540,7 +540,7 @@ namespace Hotline.Api.Controllers
         /// <returns></returns>
         [Permission(EPermission.AddKnowledge)]
         [HttpGet("add-flow-start")]
-        public async Task<IReadOnlyList<NextStepOptions>> GetAddFlowStartOptionsAsync()
+        public async Task<IReadOnlyList<KeyValuePair<string, string>>> GetAddFlowStartOptionsAsync()
         {
             return await _workflowApplication.GetStartOptionsAsync(WorkflowModuleConsts.KnowledgeAdd, HttpContext.RequestAborted);
         }
@@ -551,7 +551,7 @@ namespace Hotline.Api.Controllers
         /// <returns></returns>
         [Permission(EPermission.KnowledgeDelete)]
         [HttpGet("remove-flow-start")]
-        public async Task<IReadOnlyList<NextStepOptions>> GetRemoveFlowStartOptionsAsync()
+        public async Task<IReadOnlyList<KeyValuePair<string, string>>> GetRemoveFlowStartOptionsAsync()
         {
             return await _workflowApplication.GetStartOptionsAsync(WorkflowModuleConsts.KnowledgeDelete, HttpContext.RequestAborted);
         }

+ 1 - 1
src/Hotline.Api/Controllers/OrderController.cs

@@ -232,7 +232,7 @@ public class OrderController : BaseController
     /// </summary>
     /// <returns></returns>
     [HttpGet("flow-start")]
-    public async Task<IReadOnlyList<NextStepOptions>> GetFlowStartOptionsAsync()
+    public async Task<IReadOnlyList<KeyValuePair<string, string>>> GetFlowStartOptionsAsync()
     {
         return await _workflowApplication.GetStartOptionsAsync(WorkflowModuleConsts.OrderManage, HttpContext.RequestAborted);
     }

+ 1 - 1
src/Hotline.Api/Controllers/PbxController.cs

@@ -225,7 +225,7 @@ namespace Hotline.Api.Controllers
         /// </summary>
         /// <returns></returns>
         [HttpGet("flow-start")]
-        public async Task<IReadOnlyList<NextStepOptions>> GetFlowStartOptionsAsync()
+        public async Task<IReadOnlyList<KeyValuePair<string, string>>> GetFlowStartOptionsAsync()
         {
             return await _workflowApplication.GetStartOptionsAsync(WorkflowModuleConsts.TelRestApply,
                 HttpContext.RequestAborted);

+ 25 - 9
src/Hotline.Api/Controllers/WorkflowController.cs

@@ -1,4 +1,5 @@
-using Hotline.Application.FlowEngine;
+using Google.Rpc;
+using Hotline.Application.FlowEngine;
 using Hotline.FlowEngine.Definitions;
 using Hotline.FlowEngine.Workflows;
 using Hotline.Identity.Roles;
@@ -13,7 +14,9 @@ using Hotline.Users;
 using MapsterMapper;
 using Microsoft.AspNetCore.Mvc;
 using SqlSugar;
+using System.Threading;
 using XF.Domain.Authentications;
+using XF.Domain.Entities;
 using XF.Domain.Exceptions;
 using XF.Utility.EnumExtensions;
 
@@ -248,22 +251,35 @@ public class WorkflowController : BaseController
         var (total, items) = await _workflowRepository.Queryable()
             .WhereIF(!string.IsNullOrEmpty(dto.ModuleCode), d => d.ModuleCode == dto.ModuleCode)
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Id.Contains(dto.Keyword!) || d.Title.Contains(dto.Keyword!))
-            .OrderByDescending(d=>d.CreationTime)
+            .OrderByDescending(d => d.CreationTime)
             .ToPagedListAsync(dto, HttpContext.RequestAborted);
 
         return new PagedDto<WorkflowDto>(total, _mapper.Map<IReadOnlyList<WorkflowDto>>(items));
     }
-
+    
     /// <summary>
-    /// 查询当前流程下一节点参数
+    /// 查询当前流程下一节点配置
     /// </summary>
-    /// <param name="workflowId"></param>
-    /// <returns></returns>
     [HttpGet("{workflowId}/nextsteps")]
-    public async Task<IReadOnlyList<NextStepOptions>> GetNextStepOptions(string workflowId)
+    public async Task<IReadOnlyList<KeyValuePair<string, string>>> GetNextStepDefine(string workflowId)
     {
-        var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, true, true, cancellationToken: HttpContext.RequestAborted);
-        return await _workflowApplication.GetNextStepOptionsAsync(workflow, HttpContext.RequestAborted);
+        var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, true, true,
+            cancellationToken: HttpContext.RequestAborted);
+        var nextStepDefines = _workflowDomainService.GetNextStepDefines(workflow);
+        return nextStepDefines.Select(d => new KeyValuePair<string, string>(d.Code, d.Name)).ToList();
+    }
+
+    /// <summary>
+    /// 查询当前流程下一节点配置
+    /// </summary>
+    [HttpGet("step-options")]
+    public async Task<IReadOnlyList<KeyValuePair<string, string>>> GetNextStepOptions([FromQuery] QueryNextStepOptionDto dto)
+    {
+        var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, true, cancellationToken: HttpContext.RequestAborted);
+        var defineStep = workflow.Definition.FindStep(dto.Code);
+        if (defineStep is null)
+            throw UserFriendlyException.SameMessage("未查询到对应节点配置");
+        return await _workflowApplication.GetNextStepOptionsAsync(defineStep, HttpContext.RequestAborted);
     }
 
     /// <summary>

+ 14 - 6
src/Hotline.Application/FlowEngine/IWorkflowApplication.cs

@@ -3,6 +3,7 @@ using Hotline.FlowEngine.Definitions;
 using Hotline.FlowEngine.Workflows;
 using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Enums.FlowEngine;
+using Microsoft.AspNetCore.Mvc;
 
 namespace Hotline.Application.FlowEngine
 {
@@ -18,12 +19,6 @@ namespace Hotline.Application.FlowEngine
         /// <returns></returns>
         Task NextAsync(NextWorkflowDto dto, CancellationToken cancellationToken);
 
-        /// <summary>
-        /// 查询流程下一节点配置参数
-        /// </summary>
-        Task<IReadOnlyList<NextStepOptions>> GetNextStepOptionsAsync(Workflow workflow, CancellationToken cancellationToken);
-        Task<IReadOnlyList<NextStepOptions>> GetStartOptionsAsync(string moduleCode, CancellationToken cancellationToken);
-        
         /// <summary>
         /// 撤回至任意节点
         /// </summary>
@@ -33,5 +28,18 @@ namespace Hotline.Application.FlowEngine
         /// 跳转至任意节点
         /// </summary>
         Task JumpAsync(RecallDto dto, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// 查询流程开始节点的下一节点配置
+        /// </summary>
+        Task<IReadOnlyList<KeyValuePair<string, string>>> GetStartOptionsAsync(string moduleCode, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// 查询节点配置可选参数
+        /// </summary>
+        /// <param name="stepDefine"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        Task<IReadOnlyList<KeyValuePair<string, string>>> GetNextStepOptionsAsync(StepDefine stepDefine, CancellationToken cancellationToken);
     }
 }

+ 58 - 11
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -132,16 +132,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         await _workflowDomainService.JumpAsync(workflow, dto, targetStepDefine, isStartCountersign, flowAssignMode, cancellationToken);
     }
 
-    /// <summary>
-    /// 查询流程下一节点配置参数
-    /// </summary>
-    public async Task<IReadOnlyList<NextStepOptions>> GetNextStepOptionsAsync(Workflow workflow, CancellationToken cancellationToken)
-    {
-        var nextStepDefines = _workflowDomainService.GetNextStepOptions(workflow, cancellationToken);
-        return await GetNextStepOptionsAsync(nextStepDefines);
-    }
-
-    public async Task<IReadOnlyList<NextStepOptions>> GetStartOptionsAsync(string moduleCode, CancellationToken cancellationToken)
+    public async Task<IReadOnlyList<KeyValuePair<string, string>>> GetStartOptionsAsync(string moduleCode, CancellationToken cancellationToken)
     {
         var definition =
             await _definitionDomainService.GetLastVersionByModuleCodeAsync(moduleCode, cancellationToken);
@@ -154,9 +145,65 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         if (startStep == null)
             throw new UserFriendlyException("未正确配置开始节点");
         var nextStepDefines = definition.FindSteps(startStep.NextSteps);
-        return await GetNextStepOptionsAsync(nextStepDefines);
+        return nextStepDefines.Select(d => new KeyValuePair<string, string>(d.Code, d.Name)).ToList();
     }
 
+    /// <summary>
+    /// 根据节点配置查询待选参数
+    /// </summary>
+    /// <param name="stepDefine"></param>
+    /// <param name="cancellationToken"></param>
+    /// <returns></returns>
+    /// <exception cref="ArgumentOutOfRangeException"></exception>
+    public async Task<IReadOnlyList<KeyValuePair<string, string>>> GetNextStepOptionsAsync(StepDefine stepDefine, CancellationToken cancellationToken)
+    {
+        if (stepDefine.StepType == EStepType.End) return new List<KeyValuePair<string, string>>();
+
+        switch (stepDefine.HandlerType)
+        {
+            case EHandlerType.AssignUser:
+                var users = await _userRepository.QueryAsync(d =>
+                    !d.IsDeleted &&
+                    stepDefine.HandlerClassifies.Select(d => d.Id).Contains(d.Id));
+                return users.Select(d => new KeyValuePair<string, string>(d.Id, d.Name)).ToList();
+            case EHandlerType.AssignOrg:
+                var orgs = await _organizeRepository.QueryAsync(d =>
+                    d.IsEnable &&
+                    stepDefine.HandlerClassifies.Select(d => d.Id).Contains(d.OrgCode));
+                return orgs.Select(d => new KeyValuePair<string, string>(d.OrgCode, d.OrgName))
+                    .ToList();
+            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.HandlerClassifies.Select(d => d.Id).Contains(d.Name))
+                    .ToListAsync();
+                var users1 = roles.SelectMany(d => d.Accounts).Select(d => d.User);
+                if (stepDefine.OnlySelfOrg ?? false)
+                    users1 = users1.Where(d => d.OrgCode == _sessionContext.RequiredOrgCode);
+                return users1.Select(d => new KeyValuePair<string, string>(d.Id, d.Name)).ToList();
+            case EHandlerType.OrgLevel:
+                //当前操作人所属部门的下级部门并且属于配置orgLevel的部门
+                var levels = stepDefine.HandlerClassifies.Select(d => d.Id).Select(d => int.Parse(d));
+                var orgs1 = await _organizeRepository.QueryAsync(d =>
+                    d.IsEnable && d.OrgCode.StartsWith(_sessionContext.RequiredOrgCode) &&
+                    levels.Contains(d.OrgLevel));
+                return orgs1.Select(d => new KeyValuePair<string, string>(d.OrgCode, d.OrgName))
+                    .ToList();
+            case EHandlerType.OrgType:
+                var types = stepDefine.HandlerClassifies.Select(d => d.Id)
+                    .Select(d => Enum.Parse<EOrgType>(d));
+                var org2 = await _organizeRepository.QueryAsync(d =>
+                    d.IsEnable && d.OrgCode.StartsWith(_sessionContext.RequiredOrgCode) &&
+                    types.Contains(d.OrgType));
+                return org2.Select(d => new KeyValuePair<string, string>(d.OrgCode, d.OrgName))
+                    .ToList();
+
+            default:
+                throw new ArgumentOutOfRangeException();
+        }
+    }
+
+
     /// <summary>
     /// 查询指派办理人的处理方式及实际办理人
     /// </summary>

+ 2 - 2
src/Hotline.Application/Handlers/FlowEngine/PreviousStepHandler.cs

@@ -8,12 +8,12 @@ using MediatR;
 
 namespace Hotline.Application.Handlers.FlowEngine
 {
-    public class PreviousStepHandler : INotificationHandler<PreviousStepNotify>
+    public class PreviousStepHandler : INotificationHandler<PreviousNotify>
     {
         /// <summary>Handles a notification</summary>
         /// <param name="notification">The notification</param>
         /// <param name="cancellationToken">Cancellation token</param>
-        public async Task Handle(PreviousStepNotify notification, CancellationToken cancellationToken)
+        public async Task Handle(PreviousNotify notification, CancellationToken cancellationToken)
         {
             //todo 1.query order 2.remove depCode from assignDepCodes, userId from assignUserIds
             throw new NotImplementedException();

+ 18 - 0
src/Hotline.Share/Dtos/FlowEngine/QueryNextStepOptionDto.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Dtos.FlowEngine
+{
+    public class QueryNextStepOptionDto
+    {
+        public string WorkflowId { get; set; }
+
+        /// <summary>
+        /// define.stepCode
+        /// </summary>
+        public string Code { get; set; }
+    }
+}

+ 5 - 1
src/Hotline/FlowEngine/Notifications/WorkflowNotify.cs

@@ -17,7 +17,11 @@ public record CountersignEndAssigned(Workflow Workflow) : INotification;
 
 public record CountersignStartAssigned(Workflow Workflow) : INotification;
 
-public record PreviousStepNotify(PreviousWorkflowDto Data) : INotification;
+public record PreviousNotify(Workflow Workflow, PreviousWorkflowDto Dto) : INotification;
+
+public record RecallNotify(Workflow Workflow, RecallDto Dto) : INotification;
+
+public record JumpNotify(Workflow Workflow, RecallDto Dto) : INotification;
 
 public record EndWorkflowNotify(Workflow Workflow) : INotification;
 

+ 1 - 1
src/Hotline/FlowEngine/Workflows/IWorkflowDomainService.cs

@@ -64,6 +64,6 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 查询当前待办节点的下一级节点配置(办理参数)
         /// </summary>
-        IReadOnlyList<StepDefine> GetNextStepOptions(Workflow workflow, CancellationToken cancellationToken);
+        IReadOnlyList<StepDefine> GetNextStepDefines(Workflow workflow);
     }
 }

+ 44 - 38
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -438,25 +438,11 @@ namespace Hotline.FlowEngine.Workflows
             if (prevStep == null)
                 throw UserFriendlyException.SameMessage("未查询到前一节点");
 
-            //重置上级节点办理数据
-            //prevStep.Status = EWorkflowStepStatus.Assigned;
-            if (prevStepBox.Status is EWorkflowStepStatus.Completed)
-            {
-                prevStepBox.Status = EWorkflowStepStatus.Assigned;
-                await _workflowStepRepository.UpdateAsync(prevStepBox, cancellationToken);
-            }
+            //检查并重置上级stepbox状态为待接办
+            await ResetStepBoxStatusAsync(prevStepBox, cancellationToken);
 
-            prevStep.Reset();
-            var newPrevStep = _mapper.Map<WorkflowStep>(prevStep);
-            newPrevStep.Status = EWorkflowStepStatus.Assigned;
-            newPrevStep.PreviousId = prevStep.PreviousId;
-            newPrevStep.IsMain = prevStep.IsMain;
-            newPrevStep.ParentId = prevStep.ParentId;
-            newPrevStep.Handlers = prevStep.Handlers;
-            newPrevStep.StartCountersignId = prevStep.StartCountersignId;
-            newPrevStep.CountersignId = prevStep.CountersignId;
-            newPrevStep.IsStartedCountersignComplete = prevStep.IsStartedCountersignComplete;
-            await _workflowStepRepository.AddAsync(newPrevStep, cancellationToken);
+            //复制一个节点为待接办
+            var newPrevStep = await CreateByAsync(prevStep, cancellationToken);
 
             //remove workflow.steps
             await _workflowStepRepository.RemoveRangeAsync(new List<WorkflowStep> { prevStep, currentStep },
@@ -469,7 +455,7 @@ namespace Hotline.FlowEngine.Workflows
             //update trace
             await PreviousTraceAsync(workflow.Id, dto, currentStep, cancellationToken);
 
-            //todo publish
+            await _mediator.Publish(new PreviousNotify(workflow, dto), cancellationToken);
         }
 
         /// <summary>
@@ -494,7 +480,7 @@ namespace Hotline.FlowEngine.Workflows
                 flowAssignMode.FlowAssignType, flowAssignMode.HandlerObjects);
             await _workflowRepository.UpdateAsync(workflow, cancellationToken);
 
-            //todo publish
+            await _mediator.Publish(new RecallNotify(workflow, dto), cancellationToken);
         }
 
         /// <summary>
@@ -559,7 +545,7 @@ namespace Hotline.FlowEngine.Workflows
             //update uncompleted traces
             await JumpTraceAsync(workflow.Id, dto, cancellationToken);
 
-            //todo publish
+            await _mediator.Publish(new JumpNotify(workflow, dto), cancellationToken);
         }
 
         /// <summary>
@@ -606,7 +592,7 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 查询当前待办节点的下一级节点配置(办理参数)
         /// </summary>
-        public IReadOnlyList<StepDefine> GetNextStepOptions(Workflow workflow, CancellationToken cancellationToken)
+        public IReadOnlyList<StepDefine> GetNextStepDefines(Workflow workflow)
         {
             var (currentStepBox, _) = GetUnCompleteStep(workflow.StepBoxes, _sessionContext.RequiredOrgCode, _sessionContext.RequiredUserId);
             return workflow.Definition.FindSteps(currentStepBox.NextSteps);
@@ -615,6 +601,37 @@ namespace Hotline.FlowEngine.Workflows
 
         #region private
 
+        /// <summary>
+        /// 复制一个节点为待接办
+        /// </summary>
+        private async Task<WorkflowStep> CreateByAsync(WorkflowStep step, CancellationToken cancellationToken)
+        {
+            step.Reset();
+            var newStep = _mapper.Map<WorkflowStep>(step);
+            newStep.Status = EWorkflowStepStatus.Assigned;
+            newStep.PreviousId = step.PreviousId;
+            newStep.IsMain = step.IsMain;
+            newStep.ParentId = step.ParentId;
+            newStep.Handlers = step.Handlers;
+            newStep.StartCountersignId = step.StartCountersignId;
+            newStep.CountersignId = step.CountersignId;
+            newStep.IsStartedCountersignComplete = step.IsStartedCountersignComplete;
+            await _workflowStepRepository.AddAsync(newStep, cancellationToken);
+            return newStep;
+        }
+
+        /// <summary>
+        /// 检查并重置目标stepbox状态为待接办
+        /// </summary>
+        private async Task ResetStepBoxStatusAsync(WorkflowStep stepBox, CancellationToken cancellationToken)
+        {
+            if (stepBox.Status is EWorkflowStepStatus.Completed)
+            {
+                stepBox.Status = EWorkflowStepStatus.Assigned;
+                await _workflowStepRepository.UpdateAsync(stepBox, cancellationToken);
+            }
+        }
+
         private async Task<WorkflowCountersign> CreateCountersignAsync(string workflowId, string startStepId, string startStepCode, int count, string? parentId = null, CancellationToken cancellationToken = default)
         {
             var countersign = new WorkflowCountersign
@@ -792,17 +809,17 @@ namespace Hotline.FlowEngine.Workflows
             var targetPrevStepBox = workflow.StepBoxes.FirstOrDefault(d => d.Id == targetStepBox.PreviousId);
             if (targetPrevStepBox == null)
                 throw new UserFriendlyException($"{nameof(RecallAsync)}, 未找到目标节点的前一节点, flowId: {workflow.Id}, targetStepBoxPrevId: {targetPrevStepBox.PreviousId}");
-            //真实的前一节点并不存在(非正常流转造成的),所以任意一个替代
+            //真实的前一节点并不存在(非正常流转造成的),所以取前一stepbox任意一个step替代
             var targetPrevStep = targetPrevStepBox.Steps.FirstOrDefault();
             if (targetPrevStep == null)
                 throw new UserFriendlyException($"{nameof(RecallAsync)}, 未找到目标节点的前一节点, flowId: {workflow.Id}");
 
-            //remove completedSteps include target self
-            var removeSteps = GetStepsIncludeSelf(targetStepBox);
+            //remove completedSteps include target stepBox
+            var removeSteps = GetStepsIncludeStepBox(targetStepBox);
             var tempStepBox = currentStepBox;
             while (tempStepBox.Code != targetStepBox.Code)
             {
-                removeSteps.AddRange(GetStepsIncludeSelf(tempStepBox));
+                removeSteps.AddRange(GetStepsIncludeStepBox(tempStepBox));
                 var prevStepBox = workflow.StepBoxes.FirstOrDefault(d => d.Id == tempStepBox.PreviousId);
                 if (prevStepBox is null)
                     throw new UserFriendlyException($"{nameof(RecallAsync)}, 未查询到节点, workflowId: {workflow.Id}, prevStepBoxId: {tempStepBox.PreviousId}");
@@ -818,23 +835,12 @@ namespace Hotline.FlowEngine.Workflows
             //flow manage
             await ResetWorkflowCurrentStepInfo(workflow, dto, targetStepBox, isStartCountersign, cancellationToken);
 
-            //if (workflow.IsInCountersign())
-            //{
-            //    var currentCountersignStepBox =
-            //        workflow.StepBoxes.First(d => d.Code == workflow.TopCountersignStepCode);
-            //    //目标节点在初始会签节点之前或正好
-
-            //    if (targetStepBox.Code == workflow.TopCountersignStepCode || targetStepBox.CreationTime < currentCountersignStepBox.CreationTime)
-            //        await ResetWorkflowCurrentStepInfo(workflow, dto, targetStepBox, isStartCountersign, cancellationToken);
-            //}
-
-
             //update uncompleted traces
             await RecallTraceAsync(workflow.Id, dto, cancellationToken);
 
         }
 
-        private List<WorkflowStep> GetStepsIncludeSelf(WorkflowStep stepBox)
+        private List<WorkflowStep> GetStepsIncludeStepBox(WorkflowStep stepBox)
         {
             var steps = new List<WorkflowStep> { stepBox };
             steps.AddRange(stepBox.Steps);