xf 2 lat temu
rodzic
commit
f6cc2f0710

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

@@ -68,7 +68,10 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         var nextStepBoxDefine = _workflowDomainService.GetStepBoxDefine(definition, dto.NextStepCode);
         var workflow = await _workflowDomainService.CreateWorkflowAsync(definition, dto.Title, cancellationToken);
 
-        await _workflowDomainService.StartAsync(workflow, dto, nextStepBoxDefine, cancellationToken);
+        var flowAssignMode = await GetFlowAssignModeAsync(nextStepBoxDefine,
+            dto.NextHandlers.Select(d => d.Id).ToList(), cancellationToken);
+
+        await _workflowDomainService.StartAsync(workflow, dto, nextStepBoxDefine, flowAssignMode, cancellationToken);
 
         //更新接办部门(详情页面展示)
         await AddOrUpdateAssignAsync(workflow, dto, nextStepBoxDefine, cancellationToken);
@@ -87,11 +90,15 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, true, true, cancellationToken: cancellationToken);
         var nextStepBoxDefine = _workflowDomainService.GetStepBoxDefine(workflow.Definition, dto.NextStepCode);
         //下一节点为结束节点时,无办理人等参数,只有办理意见即可
-        var isOutOfCallCenter = nextStepBoxDefine.StepType is not EStepType.End 
+        var isOutOfCallCenter = nextStepBoxDefine.StepType is not EStepType.End
                                 && await CheckIfFlowOutOfCallCenterAsync(nextStepBoxDefine, dto.NextMainHandler, cancellationToken);
-        var isStartCountersign = nextStepBoxDefine.StepType is not EStepType.End 
+        var isStartCountersign = nextStepBoxDefine.StepType is not EStepType.End
                                  && nextStepBoxDefine.IsStartCountersign(dto.NextHandlers.Count);
-        await _workflowDomainService.NextAsync(workflow, dto, nextStepBoxDefine, isOutOfCallCenter, isStartCountersign, cancellationToken);
+
+        var flowAssignMode = await GetFlowAssignModeAsync(nextStepBoxDefine,
+            dto.NextHandlers.Select(d => d.Id).ToList(), cancellationToken);
+
+        await _workflowDomainService.NextAsync(workflow, dto, nextStepBoxDefine, isOutOfCallCenter, isStartCountersign, flowAssignMode, cancellationToken);
 
         //更新接办部门(详情页面展示)
         await AddOrUpdateAssignAsync(workflow, dto, nextStepBoxDefine, cancellationToken);

+ 3 - 3
src/Hotline.Application/Handlers/FlowEngine/NextStepHandler.cs

@@ -31,14 +31,14 @@ public class NextStepHandler : INotificationHandler<NextStepNotify>
     {
         var workflow = notification.Workflow;
         var data = notification.Dto;
-        var assignMode = await _workflowApplication.GetFlowAssignModeAsync(notification.StepDefine,
-            data.NextHandlers.Select(d => d.Id).ToList(), cancellationToken);
+        //var assignMode = await _workflowApplication.GetFlowAssignModeAsync(notification.StepDefine,
+        //    data.NextHandlers.Select(d => d.Id).ToList(), cancellationToken);
 
         switch (workflow.ModuleCode)
         {
             case WorkflowModuleConsts.OrderManage:
                 await _orderDomainService.ManageFlowNextAsync(
-                    assignMode, notification.IsCountersignEnd, notification.IsCountersignStart,
+                    notification.FlowAssignMode, notification.IsCountersignEnd, notification.IsCountersignStart,
                     workflow.Id, workflow.CurrentStepTime, workflow.CurrentStepName, workflow.ExpiredTime,
                     cancellationToken);
                 break;

+ 2 - 11
src/Hotline.Application/Handlers/FlowEngine/StartWorkflowHandler.cs

@@ -15,19 +15,12 @@ namespace Hotline.Application.Handlers.FlowEngine
 {
     public class StartWorkflowHandler : INotificationHandler<StartWorkflowNotify>
     {
-        private readonly IWorkflowApplication _workflowApplication;
         private readonly IOrderDomainService _orderDomainService;
-        private readonly IOrderRepository _orderRepository;
 
         public StartWorkflowHandler(
-            IWorkflowApplication workflowApplication,
-            IOrderDomainService orderDomainService,
-            IOrderRepository orderRepository
-            )
+            IOrderDomainService orderDomainService)
         {
-            _workflowApplication = workflowApplication;
             _orderDomainService = orderDomainService;
-            _orderRepository = orderRepository;
         }
 
         /// <summary>Handles a notification</summary>
@@ -37,13 +30,11 @@ namespace Hotline.Application.Handlers.FlowEngine
         {
             var workflow = notification.Workflow;
             var data = notification.Dto;
-            var assignMode = await _workflowApplication.GetFlowAssignModeAsync(notification.StepDefine,
-                data.NextHandlers.Select(d => d.Id).ToList(), cancellationToken);
 
             switch (workflow.ModuleCode)
             {
                 case WorkflowModuleConsts.OrderManage:
-                    await _orderDomainService.ManageFlowNextAsync(assignMode,
+                    await _orderDomainService.ManageFlowNextAsync(notification.FlowAssignMode,
                         false, notification.IsCountersignStart,
                         workflow.Id, workflow.CurrentStepTime, workflow.CurrentStepName, workflow.ExpiredTime, cancellationToken);
                     break;

+ 80 - 5
src/Hotline.Share/Dtos/FlowEngine/StepBasicDto.cs

@@ -4,6 +4,8 @@ namespace Hotline.Share.Dtos.FlowEngine
 {
     public class StepBasicDto
     {
+        public string WorkflowId { get; set; }
+
         public string Name { get; set; }
 
         /// <summary>
@@ -18,11 +20,6 @@ namespace Hotline.Share.Dtos.FlowEngine
         /// </summary>
         public EHandlerType HandlerType { get; set; }
 
-        /// <summary>
-        /// 只允许该角色下本部门人办理,否则该角色下所有人均可办理(办理者类型为角色时此字段有值)
-        /// </summary>
-        public bool? OnlySelfOrg { get; set; }
-
         /// <summary>
         /// 办理者分类(或是直接保存办理者)
         /// <example>
@@ -35,5 +32,83 @@ namespace Hotline.Share.Dtos.FlowEngine
         /// 会签模式
         /// </summary>
         public ECountersignMode CountersignMode { get; set; }
+
+        public DateTime CreationTime { get; set; }
+
+        #region 办理参数
+
+        /// <summary>
+        /// (下一节点办理人)根据审批者类型不同,此字段为不同内容
+        /// <example>
+        /// 部门等级/分类为:orgCodes, 角色为:userIds
+        /// </example>
+        /// </summary>
+        public List<IdName> NextHandlers { get; set; } = new();
+
+        /// <summary>
+        /// 下一节点主办,(NextHandlers其中一个, 如果不是会签则只有一个)
+        /// </summary>
+        public string? NextMainHandler { get; set; }
+
+        /// <summary>
+        /// 下一节点code
+        /// </summary>
+        public string NextStepCode { get; set; }
+
+        /// <summary>
+        /// 是否短信通知
+        /// </summary>
+        public bool AcceptSms { get; set; }
+
+        /// <summary>
+        /// 办理意见
+        /// </summary>
+        public string Opinion { get; set; }
+
+        /// <summary>
+        /// 附件
+        /// </summary>
+        public List<string> Additions { get; set; } = new();
+
+        #endregion
+
+        #region 办理
+
+        /// <summary>
+        /// 办理人
+        /// </summary>
+        public string? UserId { get; set; }
+
+        public string? UserName { get; set; }
+
+        /// <summary>
+        /// 办理人部门code
+        /// </summary>
+        public string? OrgCode { get; set; }
+
+        public string? OrgName { get; set; }
+
+        /// <summary>
+        /// 办理完成时间
+        /// </summary>
+        public DateTime? CompleteTime { get; set; }
+
+        #endregion
+
+        #region 接办
+
+        /// <summary>
+        /// 接办人
+        /// </summary>
+        public string? AcceptUserId { get; set; }
+
+        public string? AcceptUserName { get; set; }
+
+        /// <summary>
+        /// 接办时间
+        /// </summary>
+        public DateTime? AcceptTime { get; set; }
+
+        #endregion
     }
 }

+ 0 - 13
src/Hotline.Share/Dtos/FlowEngine/WorkflowDto.cs

@@ -84,19 +84,6 @@ namespace Hotline.Share.Dtos.FlowEngine
         public List<StepBasicDto> Steps { get; set; }
     }
 
-    public class WorkflowTraceDto : StepBasicDto
-    {
-        public string WorkflowId { get; set; }
-
-        public string StepId { get; set; }
-
-        public NextWorkflowDto NextWorkflowDto { get; set; }
-
-        public bool IsBackward { get; set; }
-
-        public DateTime? CreationTime { get; set; }
-    }
-
     public class WorkflowSupplementDto
     {
         /// <summary>

+ 69 - 0
src/Hotline.Share/Dtos/FlowEngine/WorkflowTraceDto.cs

@@ -0,0 +1,69 @@
+using System.ComponentModel;
+using Hotline.Share.Enums.FlowEngine;
+using XF.Utility.EnumExtensions;
+
+namespace Hotline.Share.Dtos.FlowEngine;
+
+public class WorkflowTraceDto : StepBasicDto
+{
+    public string StepId { get; set; }
+
+    //public NextWorkflowDto NextWorkflowDto { get; set; }
+
+    //public bool IsBackward { get; set; }
+
+    /// <summary>
+    /// 流转记录状态
+    /// </summary>
+    public EWorkflowTraceStatus Status { get; set; }
+
+    public string StatusText => Status.GetDescription();
+
+    /// <summary>
+    /// 过期时间(生成流转记录时取值当前workflow的过期时间)
+    /// </summary>
+    public DateTime ExpiredTime { get; set; }
+
+    /// <summary>
+    /// 会签从属关系
+    /// </summary>
+    public string? ParentId { get; set; }
+
+    /// <summary>
+    /// 会签流转记录
+    /// </summary>
+    public List<WorkflowTraceDto> Traces { get; set; }
+
+    public ExpiredStatus ExpiredStatus
+    {
+        get
+        {
+            if (CompleteTime.HasValue)
+            {
+                return CompleteTime.Value < ExpiredTime ? ExpiredStatus.Completed : ExpiredStatus.Expired;
+            }
+            else
+            {
+                return DateTime.Now < ExpiredTime ? ExpiredStatus.Handling : ExpiredStatus.Expired;
+            }
+        }
+    }
+
+    public string ExpiredStatusText => ExpiredStatus.GetDescription();
+}
+
+/// <summary>
+/// 超期状态
+/// </summary>
+public enum ExpiredStatus
+{
+    //办理中-未超期、办理完成-未超期、超期 
+    [Description("办理中-未超期")]
+    Handling = 0,
+
+    [Description("办理完成-未超期")]
+    Completed = 1,
+
+    [Description("超期")]
+    Expired = 2,
+}

+ 3 - 3
src/Hotline/FlowEngine/Notifications/WorkflowNotify.cs

@@ -5,11 +5,11 @@ using MediatR;
 
 namespace Hotline.FlowEngine.Notifications;
 
-public record WorkflowNotify(Workflow Workflow, StepDefine StepDefine, BasicWorkflowDto Dto) : INotification;
+public record WorkflowNotify(Workflow Workflow, BasicWorkflowDto Dto) : INotification;
 
-public record StartWorkflowNotify(Workflow Workflow, StepDefine StepDefine, BasicWorkflowDto Dto, bool IsCountersignStart) : WorkflowNotify(Workflow, StepDefine, Dto);
+public record StartWorkflowNotify(Workflow Workflow, BasicWorkflowDto Dto, bool IsCountersignStart, FlowAssignMode FlowAssignMode) : WorkflowNotify(Workflow, Dto);
 
-public record NextStepNotify(Workflow Workflow, StepDefine StepDefine, BasicWorkflowDto Dto, bool IsCountersignStart, bool IsCountersignEnd) : WorkflowNotify(Workflow, StepDefine, Dto);
+public record NextStepNotify(Workflow Workflow, BasicWorkflowDto Dto, bool IsCountersignStart, bool IsCountersignEnd, FlowAssignMode FlowAssignMode) : WorkflowNotify(Workflow, Dto);
 
 public record AcceptWorkflowNotify(Workflow Workflow) : INotification;
 

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

@@ -12,7 +12,7 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 进行流程的开始节点
         /// </summary>
-        Task StartAsync(Workflow workflow, BasicWorkflowDto dto, StepDefine nextStepBoxDefine, CancellationToken cancellationToken);
+        Task StartAsync(Workflow workflow, BasicWorkflowDto dto, StepDefine nextStepBoxDefine, FlowAssignMode flowAssignMode, CancellationToken cancellationToken);
 
         /// <summary>
         /// 查询工作流
@@ -27,7 +27,7 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 办理(流转至下一节点)
         /// </summary>
-        Task NextAsync(Workflow workflow, BasicWorkflowDto dto, StepDefine nextStepBoxDefine, bool isOutOfCallCenter, bool isStartCountersign, CancellationToken cancellationToken);
+        Task NextAsync(Workflow workflow, BasicWorkflowDto dto, StepDefine nextStepBoxDefine, bool isOutOfCallCenter, bool isStartCountersign, FlowAssignMode flowAssignMode, CancellationToken cancellationToken);
 
         /// <summary>
         /// 退回(返回前一节点)

+ 40 - 0
src/Hotline/FlowEngine/Workflows/Workflow.cs

@@ -1,6 +1,7 @@
 using Hotline.FlowEngine.Definitions;
 using Hotline.Share.Enums.FlowEngine;
 using SqlSugar;
+using XF.Domain.Entities;
 using XF.Domain.Repository;
 
 namespace Hotline.FlowEngine.Workflows;
@@ -74,6 +75,18 @@ public class Workflow : CreationEntity
     [SugarColumn(Length = 2000)]
     public string Opinion { get; set; } = "办理中...";
 
+    /// <summary>
+    /// 办理人id
+    /// </summary>
+    [SugarColumn(ColumnDataType = "varchar(1000)", IsJson = true)]
+    public List<string> HandlerUsers { get; set; }
+
+    /// <summary>
+    /// 办理部门code
+    /// </summary>
+    [SugarColumn(ColumnDataType = "varchar(1000)", IsJson = true)]
+    public List<string> HandlerOrgs { get; set; }
+
     ///// <summary>
     ///// 外部业务唯一标识
     ///// </summary>
@@ -194,5 +207,32 @@ public class Workflow : CreationEntity
     /// </summary>
     public void ResetOption() => Opinion = "办理中...";
 
+    /// <summary>
+    /// 更新当前办理人(代办人或部门)
+    /// </summary>
+    public void UpdateHandlers(string handlerId, string handlerOrg, EFlowAssignType assignType, IEnumerable<string> handlers)
+    {
+        HandlerUsers.Remove(handlerId);
+        HandlerOrgs.Remove(handlerOrg);
+        switch (assignType)
+        {
+            case EFlowAssignType.Org:
+                HandlerOrgs.AddRange(handlers);
+                break;
+            case EFlowAssignType.User:
+                HandlerUsers.AddRange(handlers);
+                break;
+            default:
+                throw new ArgumentOutOfRangeException(nameof(assignType), assignType, null);
+        }
+    }
+
+    /// <summary>
+    /// 当前用户是否可以办理该流程
+    /// </summary>
+    /// <returns></returns>
+    public bool CanHandle(string userId, string orgCode) => 
+        HandlerUsers.Contains(userId) || HandlerOrgs.Contains(orgCode);
+
     #endregion
 }

+ 12 - 4
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -78,7 +78,7 @@ namespace Hotline.FlowEngine.Workflows
         /// <param name="dto"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
-        public async Task StartAsync(Workflow workflow, BasicWorkflowDto dto, StepDefine nextStepBoxDefine, CancellationToken cancellationToken)
+        public async Task StartAsync(Workflow workflow, BasicWorkflowDto dto, StepDefine nextStepBoxDefine, FlowAssignMode flowAssignMode, CancellationToken cancellationToken)
         {
             //var nextStepBoxDefine = GetStepBoxDefine(workflow.Definition, dto.NextStepCode);
 
@@ -96,10 +96,14 @@ namespace Hotline.FlowEngine.Workflows
 
             //更新当前节点名称、时间、会签节点code 等字段
             workflow.SetWorkflowCurrentStepInfo(isStartCountersign, nextStepBox);
+
+            workflow.UpdateHandlers(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgCode,
+                flowAssignMode.FlowAssignType, flowAssignMode.Handlers);
+
             await _workflowRepository.UpdateAsync(workflow, cancellationToken);
 
             //publish
-            _mediator.Publish(new StartWorkflowNotify(workflow, nextStepBoxDefine, dto, isStartCountersign), cancellationToken);
+            _mediator.Publish(new StartWorkflowNotify(workflow, dto, isStartCountersign, flowAssignMode));
         }
 
         public async Task<Workflow> GetWorkflowAsync(string workflowId,
@@ -190,7 +194,8 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 办理(流转至下一节点)
         /// </summary>
-        public async Task NextAsync(Workflow workflow, BasicWorkflowDto dto, StepDefine nextStepBoxDefine, bool isOutOfCallCenter, bool isStartCountersign, CancellationToken cancellationToken)
+        public async Task NextAsync(Workflow workflow, BasicWorkflowDto dto, StepDefine nextStepBoxDefine,
+            bool isOutOfCallCenter, bool isStartCountersign, FlowAssignMode flowAssignMode, CancellationToken cancellationToken)
         {
             CheckWhetherRunnable(workflow.Status);
 
@@ -328,6 +333,9 @@ namespace Hotline.FlowEngine.Workflows
             //更新当前节点名称、时间、会签节点code 等字段
             workflow.SetWorkflowCurrentStepInfo(isStartCountersign, nextStepBox);
 
+            workflow.UpdateHandlers(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgCode,
+                flowAssignMode.FlowAssignType, flowAssignMode.Handlers);
+
             await _workflowRepository.UpdateAsync(workflow, cancellationToken);
 
             #endregion
@@ -338,7 +346,7 @@ namespace Hotline.FlowEngine.Workflows
 
             #endregion
 
-            _mediator.Publish(new NextStepNotify(workflow, nextStepBoxDefine, dto, isStartCountersign, isCountersignOver));
+            _mediator.Publish(new NextStepNotify(workflow, dto, isStartCountersign, isCountersignOver, flowAssignMode));
         }
 
         /// <summary>

+ 4 - 0
src/Hotline/FlowEngine/Workflows/WorkflowTrace.cs

@@ -34,6 +34,8 @@ public class WorkflowTrace : StepBasicEntity
     [SugarColumn(IsIgnore = true)]
     public List<WorkflowTrace> Traces { get; set; }
 
+    #region method
+
     public void Previous(string userId, string userName, string orgCode, string orgName) =>
         Complete(userId, userName, orgCode, orgName, EWorkflowTraceStatus.Back);
 
@@ -52,4 +54,6 @@ public class WorkflowTrace : StepBasicEntity
         CompleteTime = DateTime.Now;
         Status = status;
     }
+
+    #endregion
 }